feat: integrate enakgame and voucher
Build & Deploy iOS to TestFlight / build-and-deploy (push) Waiting to run

This commit is contained in:
efrilm
2026-10-10 02:33:16 +07:00
parent e5515d5871
commit 38850b281f
104 changed files with 7122 additions and 8063 deletions
@@ -0,0 +1,101 @@
import 'dart:developer';
import 'package:data_channel/data_channel.dart';
import 'package:dio/dio.dart';
import 'package:injectable/injectable.dart';
import '../../../common/api/api_client.dart';
import '../../../common/api/api_failure.dart';
import '../../../common/api/interceptors/sensitive_aware_log_interceptor.dart';
import '../../../common/function/app_function.dart';
import '../../../common/url/api_path.dart';
import '../../../domain/wallet/wallet.dart';
import '../wallet_dtos.dart';
import '../wallet_response.dart';
/// Katalog, tukar, dan riwayat voucher (§9).
@injectable
class VoucherRemoteDataProvider {
final ApiClient _apiClient;
final String _logName = 'VoucherRemoteDataProvider';
VoucherRemoteDataProvider(this._apiClient);
Future<DC<WalletFailure, List<VoucherDto>>> fetchVouchers() => _request(
'fetchVouchers',
() => _apiClient.get(ApiPath.vouchers, headers: getAuthorizationHeader()),
(response) => ((response.data as Map)['data'] as List? ?? [])
.map((e) => VoucherDto.fromJson(Map<String, dynamic>.from(e as Map)))
.toList(),
);
Future<DC<WalletFailure, VoucherRedemptionDto>> redeem({
required String voucherId,
required String pin,
required String idempotencyKey,
}) => _request(
'redeem',
() => _apiClient.post(
ApiPath.voucherRedeem(voucherId),
headers: {...getAuthorizationHeader(), 'Idempotency-Key': idempotencyKey},
data: {'pin': pin},
extra: {kSensitiveRequest: true},
),
(response) => VoucherRedemptionDto.fromJson(walletDataOf(response)),
);
Future<DC<WalletFailure, VoucherRedemptionPageDto>> fetchRedemptions({
required int page,
required int limit,
}) => _request(
'fetchRedemptions',
() => _apiClient.get(
ApiPath.voucherRedemptions,
headers: getAuthorizationHeader(),
params: {'page': page, 'limit': limit},
),
_parseRedemptionPage,
);
/// `data` bisa berupa list langsung dengan `pagination` di envelope, atau
/// objek `{ data, pagination }`.
VoucherRedemptionPageDto _parseRedemptionPage(Response response) {
final body = response.data as Map;
final payload = body['data'];
final rawItems = payload is Map ? payload['data'] : payload;
final rawPagination = payload is Map
? payload['pagination']
: body['pagination'];
return VoucherRedemptionPageDto(
items: (rawItems as List? ?? [])
.map(
(e) => VoucherRedemptionDto.fromJson(
Map<String, dynamic>.from(e as Map),
),
)
.toList(),
pagination: rawPagination is Map
? WalletPaginationDto.fromJson(
Map<String, dynamic>.from(rawPagination),
)
: const WalletPaginationDto(),
);
}
Future<DC<WalletFailure, T>> _request<T>(
String name,
Future<Response> Function() call,
T Function(Response response) parse,
) async {
try {
final response = await call();
final failure = parseWalletFailure(response);
if (failure != null) return DC.error(failure);
return DC.data(parse(response));
} on ApiFailure catch (e, s) {
log(name, name: _logName, error: e, stackTrace: s);
return DC.error(WalletFailure.serverError(e));
}
}
}
@@ -60,19 +60,6 @@ class WalletRemoteDataProvider {
(response) => WalletExpiringDto.fromJson(walletDataOf(response)),
);
Future<DC<WalletFailure, PaymentCodeDto>> createPaymentCode({
required String pin,
}) => _request(
'createPaymentCode',
() => _apiClient.post(
ApiPath.walletPaymentCode,
headers: getAuthorizationHeader(),
data: {'pin': pin},
extra: {kSensitiveRequest: true},
),
(response) => PaymentCodeDto.fromJson(walletDataOf(response)),
);
Future<DC<WalletFailure, ExchangePreviewDto>> previewExchange({
required int coins,
}) => _request(