Commit 89983084 authored by DatHV's avatar DatHV
Browse files

update logic. refactor code

parent 928c3660
......@@ -58,7 +58,7 @@ class AppLoading {
}
void show({
Duration timeout = const Duration(seconds: Constants.loadingTimeoutSeconds),
Duration timeout = const Duration(seconds: Constants.timeoutSeconds),
Color? barrierColor = const Color(0x33000000),
bool absorbPointers = true,
double size = 56,
......
......@@ -37,21 +37,8 @@ class BaseViewModel extends GetxController with WidgetsBindingObserver {
}
}
void showProgressIndicator() {
Get.dialog(
const Center(child: CircularProgressIndicator()),
barrierDismissible: false,
);
}
void hideProgressIndicator() {
if (Get.isDialogOpen ?? false) {
Get.back();
}
}
void showLoading({int timeout = Constants.loadingTimeoutSeconds}) {
AppLoading().show(timeout: Duration(seconds: timeout));
void showLoading() {
AppLoading().show();
}
void hideLoading() {
......
......@@ -4,8 +4,7 @@ class Constants {
static var otpTtl = 180;
static var directionInApp = "IN-APP";
static var phoneNumberCount = 10;
static var timeoutSeconds = 30;
static const loadingTimeoutSeconds = 30;
static const timeoutSeconds = 30;
static const appStoreId = '1495923300';
}
......
import 'dart:convert';
import 'package:dio/dio.dart';
import 'package:logger/logger.dart';
class LoggerInterceptor extends Interceptor {
// Configs
final bool prettyPrintJson = false; // Mặc định: JSON 1 dòng dễ copy/paste
final bool chunkLogging = true; // Chia nhỏ log theo block để tránh bị cắt
final int chunkSize = 800; // Kích thước mỗi block
final Logger _logger = Logger(
printer: PrettyPrinter(
methodCount: 0,
......@@ -14,12 +20,17 @@ class LoggerInterceptor extends Interceptor {
@override
void onRequest(RequestOptions options, RequestInterceptorHandler handler) {
final uri = options.uri;
_logger.i(
'🚀 ${options.method} $uri\n'
'Headers: ${_formatHeaders(options.headers)}\n'
'Query: ${options.queryParameters}\n'
'Body: ${_formatData(options.data)}',
);
final buffer = StringBuffer();
buffer.writeln('🚀 ${options.method} $uri');
buffer.writeln('Headers: ${_formatHeaders(options.headers)}');
if (options.queryParameters.isNotEmpty) {
buffer.writeln('Query: ${_stringify(options.queryParameters)}');
}
_emit(Level.info, 'REQUEST', uri.toString(), buffer.toString());
if (options.data != null) {
final bodyString = _stringify(options.data);
_emitJsonBlocks(Level.info, 'REQUEST JSON', uri.toString(), bodyString);
}
handler.next(options);
}
......@@ -27,10 +38,15 @@ class LoggerInterceptor extends Interceptor {
void onResponse(Response response, ResponseInterceptorHandler handler) {
final uri = response.requestOptions.uri;
final statusCode = response.statusCode;
_logger.d(
'✅ $statusCode ${response.requestOptions.method} $uri\n'
'Response: ${_formatData(response.data)}',
);
final buffer = StringBuffer();
buffer.writeln('✅ $statusCode ${response.requestOptions.method} $uri');
if (response.headers.map.isNotEmpty) {
buffer.writeln('Resp Headers: ${_stringify(response.headers.map)}');
}
_emit(Level.debug, 'RESPONSE', uri.toString(), buffer.toString());
// emit body in copy-friendly blocks
final bodyString = _stringify(response.data);
_emitJsonBlocks(Level.debug, 'RESPONSE JSON', uri.toString(), bodyString);
handler.next(response);
}
......@@ -38,11 +54,14 @@ class LoggerInterceptor extends Interceptor {
void onError(DioException err, ErrorInterceptorHandler handler) {
final uri = err.requestOptions.uri;
final statusCode = err.response?.statusCode ?? 'Unknown';
_logger.e(
'❌ $statusCode ${err.requestOptions.method} $uri\n'
'Error: ${err.message}\n'
'Response: ${_formatData(err.response?.data)}',
);
final buffer = StringBuffer();
buffer.writeln('❌ $statusCode ${err.requestOptions.method} $uri');
buffer.writeln('Error: ${err.message}');
_emit(Level.error, 'ERROR', uri.toString(), buffer.toString());
if (err.response?.data != null) {
final bodyString = _stringify(err.response?.data);
_emitJsonBlocks(Level.error, 'ERROR JSON', uri.toString(), bodyString);
}
handler.next(err);
}
......@@ -55,11 +74,47 @@ class LoggerInterceptor extends Interceptor {
return filtered.toString();
}
String _formatData(dynamic data) {
String _stringify(dynamic data) {
if (data == null) return 'null';
if (data is String && data.length > 1000) {
return '${data.substring(0, 1000)}... (truncated)';
if (data is String) return data;
try {
if (prettyPrintJson) {
final encoder = const JsonEncoder.withIndent(' ');
return encoder.convert(data);
}
return jsonEncode(data);
} catch (_) {
return data.toString();
}
}
void _emit(Level level, String phase, String uri, String message) {
if (!chunkLogging || message.length <= chunkSize) {
_logger.log(level, '[$phase] $uri\n$message');
return;
}
final total = (message.length / chunkSize).ceil();
var index = 0;
for (var i = 0; i < message.length; i += chunkSize) {
final end = (i + chunkSize < message.length) ? i + chunkSize : message.length;
index += 1;
_logger.log(level, '[$phase PART $index/$total] $uri\n${message.substring(i, end)}');
}
}
void _emitJsonBlocks(Level level, String phase, String uri, String jsonText) {
if (!chunkLogging || jsonText.length <= chunkSize) {
_logger.log(level, '[$phase FULL] $uri');
_logger.log(level, jsonText);
return;
}
final total = (jsonText.length / chunkSize).ceil();
var index = 0;
for (var i = 0; i < jsonText.length; i += chunkSize) {
final end = (i + chunkSize < jsonText.length) ? i + chunkSize : jsonText.length;
index += 1;
_logger.log(level, '[$phase PART $index/$total] $uri');
_logger.log(level, jsonText.substring(i, end));
}
return data.toString();
}
}
\ No newline at end of file
......@@ -5,8 +5,9 @@ import '../../preference/data_preference.dart';
import '../home/models/achievement_model.dart';
class AchievementViewModel extends RestfulApiViewModel {
bool isPointHunting;
var achievements = <AchievementModel>[].obs;
final bool isPointHunting;
final RxList<AchievementModel> achievements = <AchievementModel>[].obs;
AchievementViewModel({this.isPointHunting = false});
@override
......@@ -23,12 +24,16 @@ class AchievementViewModel extends RestfulApiViewModel {
"start": 0,
"limit": 1000,
};
await callApi<AchievementListResponse>(
request: () => client.getAchievementList(body),
onSuccess: (data, _) {
achievements.value = data.achievements ?? [];
achievements.assignAll(data?.achievements ?? []);
},
showAppNavigatorDialog: true,
onFailure: (msg, _, __) async {
achievements.clear();
},
showAppNavigatorDialog: false,
);
}
}
\ No newline at end of file
......@@ -13,7 +13,7 @@ class AffiliateTabViewModel extends RestfulApiViewModel {
final RxList<AffiliateCategoryModel> allAffiliateCategories = <AffiliateCategoryModel>[].obs;
final RxList<AffiliateProductTopSaleModel> affiliateProducts = <AffiliateProductTopSaleModel>[].obs;
final RxBool isLoading = false.obs;
var overview = Rxn<CashbackOverviewModel>();
final Rxn<CashbackOverviewModel> overview = Rxn<CashbackOverviewModel>();
void Function((List<AffiliateBrandModel>, String) data)? onShowAffiliateBrandPopup;
@override
......@@ -34,62 +34,79 @@ class AffiliateTabViewModel extends RestfulApiViewModel {
}
Future<void> _getAffiliateBrandGetList() async {
try {
final result = await client.affiliateBrandGetList();
affiliateBrands.value = result.data ?? [];
} catch (error) {
print("Error fetching affiliate brands: $error");
}
await callApi<List<AffiliateBrandModel>>(
request: () => client.affiliateBrandGetList(),
onSuccess: (data, _) {
affiliateBrands.assignAll(data);
},
onFailure: (msg, _, __) async {
affiliateBrands.clear();
},
showAppNavigatorDialog: true,
);
}
Future<void> _getAffiliateCategoryGetList() async {
try {
final result = await client.affiliateCategoryGetList();
final category = AffiliateCategoryModel(
code: AffiliateCategoryType.other,
name: "Khác",
);
final results = (result.data ?? []);
allAffiliateCategories.value = results;
await callApi<List<AffiliateCategoryModel>>(
request: () => client.affiliateCategoryGetList(),
onSuccess: (data, _) {
final category = AffiliateCategoryModel(
code: AffiliateCategoryType.other,
name: "Khác",
);
final results = data;
allAffiliateCategories.assignAll(results);
final data = results.take(7).toList();
data.add(category);
affiliateCategories.value = data;
} catch (error) {
print("Error fetching affiliate brands: $error");
}
final limitedData = results.take(7).toList();
limitedData.add(category);
affiliateCategories.assignAll(limitedData);
},
onFailure: (msg, _, __) async {
affiliateCategories.clear();
allAffiliateCategories.clear();
},
showAppNavigatorDialog: true,
);
}
Future<void> _getAffiliateProductTopSale() async {
try {
final result = await client.affiliateProductTopSale();
affiliateProducts.value = result.data ?? [];
} catch (error) {
print("Error fetching affiliate brands: $error");
}
await callApi<List<AffiliateProductTopSaleModel>>(
request: () => client.affiliateProductTopSale(),
onSuccess: (data, _) {
affiliateProducts.assignAll(data);
},
onFailure: (msg, _, __) async {
affiliateProducts.clear();
},
showAppNavigatorDialog: true,
);
}
Future<void> _getAffiliateOverview() async {
try {
final result = await client.getCashBackOverview();
overview.value = result.data;
} catch (error) {
print("Error fetching affiliate brands: $error");
}
await callApi<CashbackOverviewModel>(
request: () => client.getCashBackOverview(),
onSuccess: (data, _) {
overview.value = data;
},
onFailure: (msg, _, __) async {
overview.value = null;
},
showAppNavigatorDialog: true,
);
}
affiliateBrandGetListBuyCategory(AffiliateCategoryModel category) async {
showLoading();
try {
final result = await client.affiliateBrandGetList(categoryCode: AffiliateCategoryModel.codeToJson(category.code));
hideLoading();
final data = result.data ?? [];
if (result.isSuccess && data.isNotEmpty) {
onShowAffiliateBrandPopup?.call((data, category.name ?? ''));
}
} catch (error) {
hideLoading();
print("Error fetching affiliate brands: $error");
}
Future<void> affiliateBrandGetListBuyCategory(AffiliateCategoryModel category) async {
await callApi<List<AffiliateBrandModel>>(
request: () => client.affiliateBrandGetList(categoryCode: AffiliateCategoryModel.codeToJson(category.code)),
onSuccess: (data, _) {
if (data.isNotEmpty) {
onShowAffiliateBrandPopup?.call((data, category.name ?? ''));
}
},
onFailure: (msg, _, __) async {
// Không cần làm gì, error đã được handle bởi callApi
},
showAppNavigatorDialog: true,
);
}
}
\ No newline at end of file
import 'package:get/get_rx/src/rx_types/rx_types.dart';
import 'package:mypoint_flutter_app/networking/restful_api_client_all_request.dart';
import '../../configs/constants.dart';
import '../../networking/restful_api_viewmodel.dart';
import 'daily_checkin_models.dart';
class DailyCheckInViewModel extends RestfulApiViewModel {
var checkInData = Rxn<CheckInDataModel>();
var submitData = Rxn<SubmitCheckInData>();
final Rxn<CheckInDataModel> checkInData = Rxn<CheckInDataModel>();
final Rxn<SubmitCheckInData> submitData = Rxn<SubmitCheckInData>();
void Function(String message, bool onBack)? onShowAlertError;
void Function(SubmitCheckInData? data)? submitDataResponse;
......@@ -17,40 +16,34 @@ class DailyCheckInViewModel extends RestfulApiViewModel {
}
@override
onInit() {
void onInit() {
super.onInit();
_rewardOpportunityGetList();
}
Future<void> _rewardOpportunityGetList() async {
showLoading();
try {
final response = await client.rewardOpportunityGetList();
hideLoading();
checkInData.value = response.data;
if (!response.isSuccess) {
onShowAlertError?.call(response.errorMessage ?? Constants.commonError, true);
}
} catch (error) {
hideLoading();
onShowAlertError?.call(Constants.commonError, true);
}
await callApi<CheckInDataModel>(
request: () => client.rewardOpportunityGetList(),
onSuccess: (data, _) {
checkInData.value = data;
},
onFailure: (msg, _, __) async {
onShowAlertError?.call(msg, true);
},
);
}
Future<void> submitCheckIn() async {
showLoading();
try {
final response = await client.submitCheckIn();
hideLoading();
submitData.value = response.data;
submitDataResponse?.call(response.data);
_rewardOpportunityGetList();
if (!response.isSuccess) {
onShowAlertError?.call(response.errorMessage ?? Constants.commonError, false);
}
} catch (error) {
hideLoading();
onShowAlertError?.call(Constants.commonError, false);
}
await callApi<SubmitCheckInData>(
request: () => client.submitCheckIn(),
onSuccess: (data, _) {
submitData.value = data;
submitDataResponse?.call(data);
_rewardOpportunityGetList(); // Refresh data after successful check-in
},
onFailure: (msg, _, __) async {
onShowAlertError?.call(msg, false);
},
);
}
}
\ No newline at end of file
......@@ -6,32 +6,38 @@ import '../../../widgets/alert/popup_data_model.dart';
import '../models/game_bundle_item_model.dart';
class GameCardViewModel extends RestfulApiViewModel {
var data = Rxn<GameBundleItemModel>();
final Rxn<GameBundleItemModel> data = Rxn<GameBundleItemModel>();
void Function(String message, bool onClose)? onShowAlertError;
void Function(PopupDataModel popup)? submitGameCardSuccess;
void Function()? getGameDetailSuccess;
Future<void> submitGameCard(String gameId, int itemId) async {
showProgressIndicator();
final response = await client.submitGameCard(gameId, itemId.toString());
hideProgressIndicator();
final popupData = response.data?.popup;
if (response.isSuccess && popupData != null) {
submitGameCardSuccess?.call(popupData);
} else {
onShowAlertError?.call(response.errorMessage ?? Constants.commonError, false);
}
await callApi<GameBundleItemModel>(
request: () => client.submitGameCard(gameId, itemId.toString()),
onSuccess: (data, _) {
final popupData = data?.popup;
if (popupData != null) {
submitGameCardSuccess?.call(popupData);
} else {
onShowAlertError?.call(Constants.commonError, false);
}
},
onFailure: (msg, _, __) async {
onShowAlertError?.call(msg, false);
},
);
}
Future<void> getGameDetail({String? id}) async {
showLoading();
final response = await client.getGameDetail(id ?? data.value?.id ?? '');
hideLoading();
if (response.data != null) {
data.value = response.data;
getGameDetailSuccess?.call();
} else {
onShowAlertError?.call(response.errorMessage ?? Constants.commonError, true);
}
await callApi<GameBundleItemModel>(
request: () => client.getGameDetail(id ?? data.value?.id ?? ''),
onSuccess: (data, _) {
this.data.value = data;
getGameDetailSuccess?.call();
},
onFailure: (msg, _, __) async {
onShowAlertError?.call(msg, true);
},
);
}
}
\ No newline at end of file
......@@ -9,9 +9,9 @@ class HealthBookCardDetailViewModel extends RestfulApiViewModel {
void Function(String message)? onShowAlertError;
Future<void> getHealthBookCardDetail(String cardId) async {
showProgressIndicator();
showLoading();
final response = await client.getDetailHealthBookCard(cardId);
showProgressIndicator();
hideLoading();
if (response.isSuccess) {
card.value = response.data;
} else {
......
......@@ -5,32 +5,27 @@ import 'models/history_point_models.dart';
import 'models/transaction_summary_by_date_model.dart';
class HistoryPointViewModel extends RestfulApiViewModel {
var historyPoint = Rxn<ListHistoryResponseModel>();
var transactionSummary = Rxn<TransactionSummaryByDateModel>();
final Rxn<ListHistoryResponseModel> historyPoint = Rxn<ListHistoryResponseModel>();
final Rxn<TransactionSummaryByDateModel> transactionSummary = Rxn<TransactionSummaryByDateModel>();
final RxInt selectedTabIndex = 0.obs;
DateTime selectedDate = DateTime.now();
@override
onInit() {
void onInit() {
super.onInit();
freshData();
}
changeDate(bool prevMonth) {
void changeDate(bool prevMonth) {
selectedDate = DateTime(selectedDate.year, selectedDate.month + (prevMonth ? -1 : 1), 1);
freshData();
}
Future<void> freshData() async {
showLoading();
try {
await Future.wait<void>([
_getTransactionGetSummaryByDate(),
_getTransactionSummaryByDateModel(),
], eagerError: false);
} finally {
hideLoading();
}
await Future.wait<void>([
_getTransactionGetSummaryByDate(),
_getTransactionSummaryByDateModel(),
], eagerError: false);
}
Future<void> _getTransactionGetSummaryByDate() async {
......@@ -39,8 +34,16 @@ class HistoryPointViewModel extends RestfulApiViewModel {
'year': selectedDate.year,
'lang': 'vi',
};
final res = await client.transactionGetSummaryByDate(body);
transactionSummary.value = res.data;
await callApi<TransactionSummaryByDateModel>(
request: () => client.transactionGetSummaryByDate(body),
onSuccess: (data, _) {
transactionSummary.value = data;
},
onFailure: (msg, _, __) async {
transactionSummary.value = null;
},
);
}
Future<void> _getTransactionSummaryByDateModel() async {
......@@ -53,7 +56,15 @@ class HistoryPointViewModel extends RestfulApiViewModel {
'start': 0,
'lang': 'vi',
};
final res = await client.transactionHistoryGetList(body);
historyPoint.value = res.data;
await callApi<ListHistoryResponseModel>(
request: () => client.transactionHistoryGetList(body),
onSuccess: (data, _) {
historyPoint.value = data;
},
onFailure: (msg, _, __) async {
historyPoint.value = null;
},
);
}
}
\ No newline at end of file
import 'package:get/get_rx/src/rx_types/rx_types.dart';
import 'package:mypoint_flutter_app/networking/restful_api_client_all_request.dart';
import '../../base/base_response_model.dart';
import '../../networking/restful_api_viewmodel.dart';
import '../../configs/constants.dart';
import 'models/interested_categories_model.dart';
class InterestedCategoriesViewModel extends RestfulApiViewModel {
var interestedCategories = Rxn<InterestedCategoriesResponse>();
final Rxn<InterestedCategoriesResponse> interestedCategories = Rxn<InterestedCategoriesResponse>();
Set<String> selectedIds = {};
void Function(String message)? onShowAlertError;
Future<void> getInterestedCategories() async {
showLoading();
try {
final response = await client.categoryTopLevelGetList();
hideLoading();
if (response.isSuccess && response.data != null) {
final categories = response.data!;
await callApi<InterestedCategoriesResponse>(
request: () => client.categoryTopLevelGetList(),
onSuccess: (data, _) {
selectedIds =
categories.listItems
data.listItems
?.where((item) => item.subscribed == "1")
.map((item) => item.categoryCode ?? '')
.where((code) => code.isNotEmpty)
.toList()
.toSet() ??
<String>{};
interestedCategories.value = categories;
} else {
onShowAlertError?.call(response.message ?? Constants.commonError);
}
} catch (error) {
hideLoading();
onShowAlertError?.call(Constants.commonError);
}
interestedCategories.value = data;
},
onFailure: (msg, _, _) async {
onShowAlertError?.call(msg);
},
);
}
submitInterestedCategories() async {
Future<void> submitInterestedCategories() async {
final categories = selectedIds.toList();
showLoading();
try {
final response = await client.submitCategorySubscribe(categories.join(','));
hideLoading();
onShowAlertError?.call(
response.isSuccess ? "Cập nhật sở thích thành công" : response.message ?? Constants.commonError,
);
final List<String> categoryCodes =
interestedCategories.value?.listItems
?.map((item) => item.categoryCode ?? '')
.where((code) => code.isNotEmpty)
.toList() ??
[];
final filteredList = categoryCodes?.where((item) => !categories.contains(item)).toList();
if (filteredList == null || filteredList.isEmpty) return;
submitUnsubscribeInterestedCategories(filteredList!);
} catch (error) {
hideLoading();
onShowAlertError?.call(Constants.commonError);
await callApi<EmptyCodable>(
request: () => client.submitCategorySubscribe(categories.join(',')),
onSuccess: (data, _) {
onShowAlertError?.call("Cập nhật sở thích thành công");
_handleUnsubscribeCategories(categories);
},
onFailure: (msg, _, _) async {
onShowAlertError?.call(msg);
},
);
}
void _handleUnsubscribeCategories(List<String> categories) {
final List<String> categoryCodes = interestedCategories.value?.listItems
?.map((item) => item.categoryCode ?? '')
.where((code) => code.isNotEmpty)
.toList() ?? [];
final filteredList = categoryCodes.where((item) => !categories.contains(item)).toList();
if (filteredList.isNotEmpty) {
submitUnsubscribeInterestedCategories(filteredList);
}
}
submitUnsubscribeInterestedCategories(List<String> categories) async {
final _ = await client.submitCategoryUnsubscribeList(categories.join(','));
Future<void> submitUnsubscribeInterestedCategories(List<String> categories) async {
await callApi<EmptyCodable>(
request: () => client.submitCategoryUnsubscribeList(categories.join(',')),
onSuccess: (data, _) {
// Silent success for unsubscribe
},
onFailure: (msg, _, _) async {
// Silent failure for unsubscribe
},
);
}
}
......@@ -5,53 +5,55 @@ import '../../networking/restful_api_viewmodel.dart';
import 'models/invite_friend_campaign_model.dart';
class InviteFriendCampaignViewModel extends RestfulApiViewModel {
var inviteFriendDetail = Rxn<InviteFriendDetailModel>();
var campaignDetail = Rxn<CampaignInviteFriendDetail>();
final Rxn<InviteFriendDetailModel> inviteFriendDetail = Rxn<InviteFriendDetailModel>();
final Rxn<CampaignInviteFriendDetail> campaignDetail = Rxn<CampaignInviteFriendDetail>();
void Function(String message, bool onBack)? onShowAlertError;
void Function(String, String)? phoneInviteFriendResponse;
loadData() {
void loadData() {
_getInviteFriendDetail();
_getCampaignInviteFriendDetail();
}
Future<void> phoneInviteFriend(String phone) async {
showLoading();
try {
final response = await client.phoneInviteFriend(phone);
hideLoading();
final sms = response.data?.sms ?? '';
if (response.isSuccess && sms.isNotEmpty) {
phoneInviteFriendResponse?.call(sms, phone);
} else {
onShowAlertError?.call(response.errorMessage ?? Constants.commonError, false);
}
} catch (error) {
hideLoading();
onShowAlertError?.call(Constants.commonError, false);
}
await callApi<InviteFriendResponse>(
request: () => client.phoneInviteFriend(phone),
onSuccess: (data, _) {
final sms = data?.sms ?? '';
if (sms.isNotEmpty) {
phoneInviteFriendResponse?.call(sms, phone);
} else {
onShowAlertError?.call(Constants.commonError, false);
}
},
onFailure: (msg, _, __) async {
onShowAlertError?.call(msg, false);
},
);
}
Future<void> _getInviteFriendDetail() async {
showLoading();
try {
final response = await client.getCampaignInviteFriend();
hideLoading();
inviteFriendDetail.value = response.data;
if (!response.isSuccess) {
onShowAlertError?.call(response.errorMessage ?? Constants.commonError, true);
}
} catch (error) {
onShowAlertError?.call(Constants.commonError, true);
} finally {
hideLoading();
}
Future<void> _getInviteFriendDetail() async {
await callApi<InviteFriendDetailModel>(
request: () => client.getCampaignInviteFriend(),
onSuccess: (data, _) {
inviteFriendDetail.value = data;
},
onFailure: (msg, _, __) async {
onShowAlertError?.call(msg, true);
},
);
}
Future<void> _getCampaignInviteFriendDetail() async {
try {
final response = await client.getDetailCampaignInviteFriend();
campaignDetail.value = response.data;
} catch (_) {}
await callApi<CampaignInviteFriendDetail>(
request: () => client.getDetailCampaignInviteFriend(),
onSuccess: (data, _) {
campaignDetail.value = data;
},
onFailure: (msg, _, __) async {
// Silent failure for this optional call
},
showAppNavigatorDialog: false,
);
}
}
......@@ -4,9 +4,7 @@ import '../../networking/restful_api_viewmodel.dart';
import '../home/models/pipi_detail_model.dart';
class PipiDetailViewModel extends RestfulApiViewModel {
var items = RxList<PipiSupportItemModel>();
PipiDetailViewModel();
final RxList<PipiSupportItemModel> items = <PipiSupportItemModel>[].obs;
@override
void onInit() {
......@@ -15,11 +13,14 @@ class PipiDetailViewModel extends RestfulApiViewModel {
}
Future<void> fetchPipiDetails() async {
try {
final response = await client.getPipiDetail();
items.value = response.data?.items ?? [];
} catch (error) {
print("Error fetching Pipi details: $error");
}
await callApi<PipiDetailResponseModel>(
request: () => client.getPipiDetail(),
onSuccess: (data, _) {
items.assignAll(data?.items ?? []);
},
onFailure: (msg, _, __) async {
items.clear();
},
);
}
}
\ No newline at end of file
......@@ -208,8 +208,7 @@ class _RegisterFormInputScreenState extends BaseState<RegisterFormInputScreen> w
}
void _continueToPaymentHandle() {
final verifyURL = _viewModel.form.value?.verify?.url ?? '';
if (verifyURL.isNotEmpty) {
if (_viewModel.verifyUrl.isNotEmpty) {
_viewModel.verifyRegisterForm();
} else {
_gotoPaymentScreen();
......
......@@ -12,6 +12,9 @@ class RegisterFormInputViewModel extends RestfulApiViewModel {
void Function(String message)? onShowAlertError;
void Function(VerifyRegisterCampaignModel data)? verifyRegisterFormSuccess;
String get verifyUrl {
return form.value?.verify?.url ?? '';
}
Future<void> fetchRegisterFormInput(String id) async {
final response = await client.getRegistrationForm(id);
form.value = response.data;
......@@ -21,11 +24,10 @@ class RegisterFormInputViewModel extends RestfulApiViewModel {
}
Future<void> verifyRegisterForm() async {
showProgressIndicator();
final path = form.value?.formRegistration?.verify?.url ?? '/accountPasswordReset/1.0.0';
showLoading();
final metaData = (form.value?.submitParams ?? {}).toJsonString();
final response = await client.verifyRegisterForm(path, {'metadata': metaData});
hideProgressIndicator();
final response = await client.verifyRegisterForm(verifyUrl, {'metadata': metaData});
hideLoading();
final data = response.data;
if (!response.isSuccess && data != null) {
onShowAlertError?.call(response.errorMessage ?? Constants.commonError);
......
......@@ -49,13 +49,13 @@ class _TransactionDetailScreenState extends BaseState<TransactionDetailScreen> w
_viewModel = Get.put(
TransactionDetailViewModel(product: _product!, quantity: _quantity, targetPhoneNumber: _targetPhoneNumber, metaData: _metaData),
);
_viewModel.refreshData();
_viewModel.onShowAlertError = (message) {
if (message.isNotEmpty) {
if (message.isEmpty) return;
WidgetsBinding.instance.addPostFrameCallback((_) {
showAlertError(content: message);
}
});
};
_viewModel.refreshData();
}
@override
......
......@@ -39,12 +39,6 @@ class TransactionDetailViewModel extends RestfulApiViewModel {
TransactionDetailViewModel({required this.product, required this.quantity, this.targetPhoneNumber, this.metaData});
@override
void onInit() {
super.onInit();
refreshData();
}
Future<void> refreshData() async {
isLoading.value = true;
await Future.wait([_getPreviewOrderPayment(), _getPaymentMethods(), _getPaymentBankAccounts()]);
......
......@@ -43,7 +43,7 @@ class MyMobileCardDetailViewModel extends RestfulApiViewModel {
Future<void> onChangeCardStatus() async {
final newState = !isUsed.value;
showProgressIndicator();
showLoading();
try {
final response = newState ? await client.myProductMarkAsUsed(itemId) : await client.myProductMarkAsNotUsedYet(itemId);
if (response.isSuccess) {
......@@ -52,7 +52,7 @@ class MyMobileCardDetailViewModel extends RestfulApiViewModel {
} catch (_) {
} finally {
hideProgressIndicator();
hideLoading();
}
}
}
\ No newline at end of file
......@@ -2,6 +2,7 @@ import 'package:barcode_widget/barcode_widget.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:mypoint_flutter_app/widgets/back_button.dart';
import 'package:mypoint_flutter_app/widgets/custom_toast_message.dart';
import 'package:mypoint_flutter_app/widgets/dashed_line.dart';
import 'package:qr_flutter/qr_flutter.dart';
import '../../resources/base_color.dart';
......@@ -80,7 +81,7 @@ class VoucherCodeCardScreen extends StatelessWidget {
GestureDetector(
onTap: () {
Clipboard.setData(ClipboardData(text: code));
ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text('Đã sao chép mã')));
showToastMessage('Đã sao chép mã');
},
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 4),
......
......@@ -133,9 +133,9 @@ class VoucherListViewModel extends RestfulApiViewModel {
}
void submitCampaignViewVoucherComplete() async {
showProgressIndicator();
final response = await client.submitCampaignViewVoucherComplete();
hideProgressIndicator();
submitCampaignViewVoucherResponse?.call(response);
showLoading();
final response = await client.submitCampaignViewVoucherComplete();
hideLoading();
submitCampaignViewVoucherResponse?.call(response);
}
}
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment