Commit 682ab1de authored by DatHV's avatar DatHV
Browse files

fix bug.

parent 1edd930e
...@@ -166,7 +166,7 @@ class _OnboardingScreenState extends BaseState<OnboardingScreen> with BasicState ...@@ -166,7 +166,7 @@ class _OnboardingScreenState extends BaseState<OnboardingScreen> with BasicState
const TextSpan(text: " và "), const TextSpan(text: " và "),
WidgetSpan( WidgetSpan(
child: GestureDetector( child: GestureDetector(
onTap: () => Get.to(FAQScreen()),// Get.to(CampaignDetailScreen(type: DetailPageRuleType.privacyPolicy)), onTap: () => Get.toNamed(campaignDetailScreen, arguments: {"type": DetailPageRuleType.privacyPolicy}),
child: const Text( child: const Text(
"Chính sách bảo mật", "Chính sách bảo mật",
style: TextStyle( style: TextStyle(
......
...@@ -6,6 +6,7 @@ import '../../core/network/restful_api_viewmodel.dart'; ...@@ -6,6 +6,7 @@ import '../../core/network/restful_api_viewmodel.dart';
import '../../app/config/constants.dart'; import '../../app/config/constants.dart';
import '../../shared/preferences/data_preference.dart'; import '../../shared/preferences/data_preference.dart';
import '../../shared/widgets/custom_toast_message.dart'; import '../../shared/widgets/custom_toast_message.dart';
import 'model/otp_verify_response_model.dart';
import 'otp_viewmodel.dart'; import 'otp_viewmodel.dart';
class DeleteAccountOtpRepository extends RestfulApiViewModel implements IOtpRepository { class DeleteAccountOtpRepository extends RestfulApiViewModel implements IOtpRepository {
...@@ -20,10 +21,10 @@ class DeleteAccountOtpRepository extends RestfulApiViewModel implements IOtpRepo ...@@ -20,10 +21,10 @@ class DeleteAccountOtpRepository extends RestfulApiViewModel implements IOtpRepo
Future<void> sendOtp() async {} Future<void> sendOtp() async {}
@override @override
Future<BaseResponseModel<EmptyCodable>> verifyOtp(String otpCode) async { Future<BaseResponseModel<OTPVerifyResponseModel>> verifyOtp(String otpCode) {
showLoading(); showLoading();
try { return client.verifyDeleteAccount(otpCode).then((value) async {
final value = await client.verifyDeleteAccount(otpCode); hideLoading();
if (value.isSuccess) { if (value.isSuccess) {
await DataPreference.instance.clearBioToken(phoneNumber); await DataPreference.instance.clearBioToken(phoneNumber);
await DataPreference.instance.clearData(); await DataPreference.instance.clearData();
...@@ -31,9 +32,7 @@ class DeleteAccountOtpRepository extends RestfulApiViewModel implements IOtpRepo ...@@ -31,9 +32,7 @@ class DeleteAccountOtpRepository extends RestfulApiViewModel implements IOtpRepo
showToastMessage("Xóa tài khoản thành công"); showToastMessage("Xóa tài khoản thành công");
} }
return value; return value;
} finally { });
hideLoading();
}
} }
@override @override
...@@ -46,7 +45,7 @@ class DeleteAccountOtpRepository extends RestfulApiViewModel implements IOtpRepo ...@@ -46,7 +45,7 @@ class DeleteAccountOtpRepository extends RestfulApiViewModel implements IOtpRepo
return otpTtl; return otpTtl;
} }
final mgs = value.errorMessage ?? Constants.commonError; final mgs = value.errorMessage ?? Constants.commonError;
Get.snackbar("Thông báo", mgs); showToastMessage(mgs);
return null; return null;
} finally { } finally {
hideLoading(); hideLoading();
......
...@@ -17,7 +17,11 @@ class ForgotPassOTPRepository extends RestfulApiViewModel implements IOtpReposit ...@@ -17,7 +17,11 @@ class ForgotPassOTPRepository extends RestfulApiViewModel implements IOtpReposit
@override @override
Future<int?> resendOtp() { Future<int?> resendOtp() {
throw UnimplementedError(); showLoading();
return client.otpCreateNew(phoneNumber).then((value) {
hideLoading();
return value.data?.resendAfterSecond;
});
} }
@override @override
......
...@@ -46,16 +46,16 @@ class PersonalEditDataModel { ...@@ -46,16 +46,16 @@ class PersonalEditDataModel {
}); });
Json get body => <String, dynamic> { Json get body => <String, dynamic> {
"worker_site_id": DataPreference.instance.profile?.workerSite?.id, "worker_site_id": DataPreference.instance.profile?.workerSite?.id ?? "",
"fullname": name, "fullname": name ?? "",
"nickname": nickname, "nickname": nickname ?? "",
"date_of_birth": birthday?.toFormattedString(format: "yyyy-MM-dd"), "date_of_birth": birthday?.toFormattedString(format: "yyyy-MM-dd"),
"sex": gender?.value ?? "U", "sex": gender?.value ?? "U",
"address_full": address, "address_full": address ?? "",
"address_district_code": district?.code ?? "", "address_district_code": district?.code ?? "",
"address_province_code": province?.code ?? "", "address_province_code": province?.code ?? "",
"identification_number": identificationNumber, "identification_number": identificationNumber ?? "",
"email": email, "email": email ?? "",
"avatar": "", "avatar": "",
"avatar_2": "", "avatar_2": "",
}; };
......
...@@ -28,20 +28,10 @@ class _PersonalEditScreenState extends BaseState<PersonalEditScreen> with BasicS ...@@ -28,20 +28,10 @@ class _PersonalEditScreenState extends BaseState<PersonalEditScreen> with BasicS
showAlertError(content: message, barrierDismissible: true, onConfirmed: null); showAlertError(content: message, barrierDismissible: true, onConfirmed: null);
}; };
viewModel.updateProfileResponseSuccess = () { viewModel.updateProfileResponseSuccess = () {
DataAlertModel alertData = DataAlertModel( showAlertError(
localHeaderImage: "assets/images/ic_pipi_05.png", content: "Cập nhật thông tin cá nhân thành công!",
title: "Thông báo", headerImage: "assets/images/ic_pipi_05.png",
description: "Cập nhật thông tin cá nhân thành công!", onConfirmed: () => Get.back());
buttons: [
AlertButton(
text: "Đã hiểu",
onPressed: () => Get.back(),
bgColor: BaseColor.primary500,
textColor: Colors.white,
),
],
);
showAlert(data: alertData);
}; };
} }
...@@ -191,6 +181,7 @@ class _PersonalEditScreenState extends BaseState<PersonalEditScreen> with BasicS ...@@ -191,6 +181,7 @@ class _PersonalEditScreenState extends BaseState<PersonalEditScreen> with BasicS
item.sectionType == SectionPersonalEditType.gender; item.sectionType == SectionPersonalEditType.gender;
final isDate = item.sectionType == SectionPersonalEditType.birthday; final isDate = item.sectionType == SectionPersonalEditType.birthday;
final isTappableItem = isTapField || isDate; final isTappableItem = isTapField || isDate;
final value = item.value ?? "";
return Padding( return Padding(
padding: const EdgeInsets.only(top: 8, bottom: 8, left: 16, right: 16), // all(16.0), padding: const EdgeInsets.only(top: 8, bottom: 8, left: 16, right: 16), // all(16.0),
child: Column( child: Column(
...@@ -223,7 +214,7 @@ class _PersonalEditScreenState extends BaseState<PersonalEditScreen> with BasicS ...@@ -223,7 +214,7 @@ class _PersonalEditScreenState extends BaseState<PersonalEditScreen> with BasicS
Expanded( Expanded(
child: TextField( child: TextField(
keyboardType: item.keyboardType ?? TextInputType.text, keyboardType: item.keyboardType ?? TextInputType.text,
controller: TextEditingController(text: item.value ?? ""), controller: TextEditingController(text: value),
enabled: isTappableItem ? false : (item.isEditable ?? true), enabled: isTappableItem ? false : (item.isEditable ?? true),
decoration: InputDecoration.collapsed( decoration: InputDecoration.collapsed(
hintText: item.hintText ?? "", hintText: item.hintText ?? "",
...@@ -242,6 +233,14 @@ class _PersonalEditScreenState extends BaseState<PersonalEditScreen> with BasicS ...@@ -242,6 +233,14 @@ class _PersonalEditScreenState extends BaseState<PersonalEditScreen> with BasicS
), ),
), ),
const SizedBox(height: 6), const SizedBox(height: 6),
if (item.sectionType == SectionPersonalEditType.email && value.isNotEmpty && viewModel.isValidEmail(value) == false)
Row(
children: [
const Icon(Icons.error, color: Colors.red, size: 14),
const SizedBox(width: 4),
Text('Email không đúng định dạng', style: const TextStyle(fontSize: 12, color: Colors.red)),
],
),
if (item.warningText != null) if (item.warningText != null)
Row( Row(
children: [ children: [
......
...@@ -157,7 +157,7 @@ class PersonalEditViewModel extends RestfulApiViewModel { ...@@ -157,7 +157,7 @@ class PersonalEditViewModel extends RestfulApiViewModel {
} }
if (model.birthday == null) { if (model.birthday == null) {
return false; return false;
} }
if (model.gender == null || model.gender == PersonalGender.unknown) { if (model.gender == null || model.gender == PersonalGender.unknown) {
return false; return false;
} }
......
...@@ -74,19 +74,18 @@ class _PersonalScreenState extends BaseState<PersonalScreen> with BasicState, Po ...@@ -74,19 +74,18 @@ class _PersonalScreenState extends BaseState<PersonalScreen> with BasicState, Po
} }
Widget _buildHeaderPersonal(HeaderHomeModel data) { Widget _buildHeaderPersonal(HeaderHomeModel data) {
final width = MediaQuery.of(context).size.width;
final topPadding = MediaQuery.of(context).padding.top;
final name = DataPreference.instance.displayName; final name = DataPreference.instance.displayName;
final level = DataPreference.instance.rankName ?? "Hạng Đồng"; final level = DataPreference.instance.rankName ?? "Hạng Đồng";
final email = DataPreference.instance.profile?.workerSite?.email ?? ""; final email = DataPreference.instance.profile?.workerSite?.email ?? "";
final topWebPadding = Constants.extendTopPaddingNavigation; final topWebPadding = Constants.extendTopPaddingNavigation;
final avatar = WebData.getAvatar(); final avatar = WebData.getAvatar();
return Container( return Container(
height: width * 163 / 375 + topWebPadding,
decoration: BoxDecoration(image: DecorationImage(image: NetworkImage(data.background ?? ""), fit: BoxFit.cover)), decoration: BoxDecoration(image: DecorationImage(image: NetworkImage(data.background ?? ""), fit: BoxFit.cover)),
child: Padding( child: SafeArea(
padding: EdgeInsets.only(top: 12 + topWebPadding, bottom: 12, left: 8, right: 8),// symmetric(horizontal: 12, vertical: 8), bottom: false,
minimum: EdgeInsets.only(top: 12 + topWebPadding, bottom: 12, left: 12, right: 12),
child: Column( child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
GestureDetector( GestureDetector(
...@@ -94,47 +93,51 @@ class _PersonalScreenState extends BaseState<PersonalScreen> with BasicState, Po ...@@ -94,47 +93,51 @@ class _PersonalScreenState extends BaseState<PersonalScreen> with BasicState, Po
await Get.toNamed(personalEditScreen); await Get.toNamed(personalEditScreen);
setState(() {}); setState(() {});
}, },
child: Container( child: Row(
margin: EdgeInsets.only(top: topPadding), children: [
child: Row( Container(
children: [ width: 64,
Container( height: 64,
width: 64, decoration: BoxDecoration(
height: 64, shape: BoxShape.circle,
decoration: BoxDecoration( border: Border.all(color: Colors.white, width: 2),
shape: BoxShape.circle, ),
border: Border.all(color: Colors.white, width: 2), child: ClipOval(
), child: loadNetworkImage(
child: ClipOval( url: avatar,
child: loadNetworkImage( fit: BoxFit.cover,
url: avatar, placeholderAsset: "assets/images/ic_logo.png"
fit: BoxFit.cover, )
placeholderAsset: "assets/images/ic_logo.png"
)
),
), ),
const SizedBox(width: 8), ),
Column( const SizedBox(width: 8),
Expanded(
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Text( Text(
name, name,
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: const TextStyle(fontSize: 22, fontWeight: FontWeight.bold, color: Colors.white), style: const TextStyle(fontSize: 22, fontWeight: FontWeight.bold, color: Colors.white),
), ),
if (email.isNotEmpty) if (email.isNotEmpty)
Text( Text(
email, email,
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: const TextStyle(fontSize: 16, color: Colors.white70, fontWeight: FontWeight.w600), style: const TextStyle(fontSize: 16, color: Colors.white70, fontWeight: FontWeight.w600),
), ),
], ],
), ),
const Spacer(), ),
const Icon(Icons.chevron_right, color: Colors.white, size: 22), const SizedBox(width: 8),
], const Icon(Icons.chevron_right, color: Colors.white, size: 22),
), ],
), ),
), ),
const Spacer(), const SizedBox(height: 16),
Row( Row(
children: [ children: [
GestureDetector( GestureDetector(
......
...@@ -85,7 +85,7 @@ class SplashScreenViewModel extends RestfulApiViewModel { ...@@ -85,7 +85,7 @@ class SplashScreenViewModel extends RestfulApiViewModel {
// Get token from SDK // Get token from SDK
final token = await webGetToken().timeout(_sdkTimeout); final token = await webGetToken().timeout(_sdkTimeout);
if (token != null && token.isNotEmpty) { if (token != null && token.isNotEmpty) {
debugPrint('✅ SplashScreen - Token retrieved from x-app-sdk: ${token.substring(0, 8)}...'); debugPrint('✅ SplashScreen - Token retrieved from x-app-sdk: $token...');
return token; return token;
} else { } else {
final error = webGetLastError(); final error = webGetLastError();
......
...@@ -89,7 +89,7 @@ class _PhoneTopUpScreenState extends BaseState<PhoneTopUpScreen> with BasicState ...@@ -89,7 +89,7 @@ class _PhoneTopUpScreenState extends BaseState<PhoneTopUpScreen> with BasicState
), ),
keyboardType: TextInputType.phone, keyboardType: TextInputType.phone,
onChanged: (value) { onChanged: (value) {
_viewModel.phoneNumber.value = value; _viewModel.phoneNumber.value = value.trim();
_deb.run(() => _viewModel.checkMobileNetwork()); _deb.run(() => _viewModel.checkMobileNetwork());
}, },
), ),
...@@ -110,9 +110,11 @@ class _PhoneTopUpScreenState extends BaseState<PhoneTopUpScreen> with BasicState ...@@ -110,9 +110,11 @@ class _PhoneTopUpScreenState extends BaseState<PhoneTopUpScreen> with BasicState
selectedBrand: _viewModel.selectedBrand.value, selectedBrand: _viewModel.selectedBrand.value,
onSelected: (brand) { onSelected: (brand) {
Navigator.pop(context); Navigator.pop(context);
print("BrandSelectShe 2222 2 et ${brand.name}");
if (brand.id != _viewModel.selectedBrand.value?.id) return; if (brand.id != _viewModel.selectedBrand.value?.id) return;
_viewModel.selectedProduct.value = null; _viewModel.selectedProduct.value = null;
_viewModel.selectedBrand.value = brand; _viewModel.selectedBrand.value = brand;
print("BrandSelectSheet ${brand.name}");
_viewModel.getTelcoDetail(); _viewModel.getTelcoDetail();
}, },
), ),
...@@ -163,7 +165,7 @@ class _PhoneTopUpScreenState extends BaseState<PhoneTopUpScreen> with BasicState ...@@ -163,7 +165,7 @@ class _PhoneTopUpScreenState extends BaseState<PhoneTopUpScreen> with BasicState
return GestureDetector( return GestureDetector(
onTap: () { onTap: () {
setState(() { setState(() {
_viewModel.phoneNumber.value = phone; _viewModel.phoneNumber.value = phone.trim();
_phoneController.text = phone; _phoneController.text = phone;
_viewModel.checkMobileNetwork(); _viewModel.checkMobileNetwork();
}); });
...@@ -365,7 +367,7 @@ class _PhoneTopUpScreenState extends BaseState<PhoneTopUpScreen> with BasicState ...@@ -365,7 +367,7 @@ class _PhoneTopUpScreenState extends BaseState<PhoneTopUpScreen> with BasicState
String phone = contact.phones.first.number; String phone = contact.phones.first.number;
phone = phone.replaceAll(RegExp(r'[\s\-\(\)]'), ''); phone = phone.replaceAll(RegExp(r'[\s\-\(\)]'), '');
_phoneController.text = phone; _phoneController.text = phone;
_viewModel.phoneNumber.value = phone; _viewModel.phoneNumber.value = phone.trim();
_viewModel.checkMobileNetwork(); _viewModel.checkMobileNetwork();
} catch (e) { } catch (e) {
debugPrint('❌ pickContact error: $e'); debugPrint('❌ pickContact error: $e');
......
...@@ -66,13 +66,15 @@ class TopUpViewModel extends RestfulApiViewModel { ...@@ -66,13 +66,15 @@ class TopUpViewModel extends RestfulApiViewModel {
} }
Future<void> checkMobileNetwork() async { Future<void> checkMobileNetwork() async {
final phone = phoneNumber.value.trim();
if (phone.isEmpty) return;
await callApi<BrandNameCheckResponse>( await callApi<BrandNameCheckResponse>(
request: () => _callProductApi((api) => api.checkMobileNetwork(phoneNumber.value)), request: () => _callProductApi((api) => api.checkMobileNetwork(phone)),
onSuccess: (data, _) { onSuccess: (data, _) {
final brandCode = data.brand ?? ''; final brandCode = (data.brand ?? '').toUpperCase();
var brand = topUpBrands.isNotEmpty var brand = topUpBrands.isNotEmpty
? topUpBrands.firstWhere( ? topUpBrands.firstWhere(
(brand) => brand.code == brandCode, (brand) => (brand.code ?? "").toUpperCase() == brandCode,
orElse: () => topUpBrands.first, orElse: () => topUpBrands.first,
) : topUpBrands.firstOrNull; ) : topUpBrands.firstOrNull;
selectedBrand.value = brand; selectedBrand.value = brand;
......
...@@ -25,6 +25,9 @@ class TransactionHistoryDetailScreen extends BaseScreen { ...@@ -25,6 +25,9 @@ class TransactionHistoryDetailScreen extends BaseScreen {
class _TransactionHistoryDetailScreenState extends BaseState<TransactionHistoryDetailScreen> with BasicState { class _TransactionHistoryDetailScreenState extends BaseState<TransactionHistoryDetailScreen> with BasicState {
late final TransactionHistoryDetailViewModel _viewModel; late final TransactionHistoryDetailViewModel _viewModel;
late var canBack = true; late var canBack = true;
void _goHome() {
Get.offAllNamed(mainScreen, arguments: {"tabIndex": 0});
}
@override @override
void initState() { void initState() {
...@@ -252,7 +255,8 @@ class _TransactionHistoryDetailScreenState extends BaseState<TransactionHistoryD ...@@ -252,7 +255,8 @@ class _TransactionHistoryDetailScreenState extends BaseState<TransactionHistoryD
onPressed: () { onPressed: () {
final finish = transaction.directionScreenRedButton?.begin(); final finish = transaction.directionScreenRedButton?.begin();
if (finish != true) { if (finish != true) {
Get.until((route) => Get.currentRoute == mainScreen); print("finish directionScreenRedButton");
_goHome();
} }
}, },
style: ElevatedButton.styleFrom( style: ElevatedButton.styleFrom(
...@@ -270,7 +274,7 @@ class _TransactionHistoryDetailScreenState extends BaseState<TransactionHistoryD ...@@ -270,7 +274,7 @@ class _TransactionHistoryDetailScreenState extends BaseState<TransactionHistoryD
if (transaction.titleClearButton != null) if (transaction.titleClearButton != null)
TextButton( TextButton(
onPressed: () { onPressed: () {
Get.until((route) => Get.currentRoute == mainScreen); _goHome();
}, },
style: TextButton.styleFrom( style: TextButton.styleFrom(
minimumSize: const Size(double.infinity, 50), minimumSize: const Size(double.infinity, 50),
......
import 'dart:math'; import 'dart:math';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_widget_from_html_core/flutter_widget_from_html_core.dart'; import 'package:flutter_widget_from_html_core/flutter_widget_from_html_core.dart';
import 'package:mypoint_flutter_app/core/utils/extensions/num_extension.dart'; import 'package:mypoint_flutter_app/core/utils/extensions/num_extension.dart';
...@@ -35,6 +36,7 @@ class VoucherDetailScreen extends BaseScreen { ...@@ -35,6 +36,7 @@ class VoucherDetailScreen extends BaseScreen {
class _VoucherDetailScreenState extends BaseState<VoucherDetailScreen> with BasicState { class _VoucherDetailScreenState extends BaseState<VoucherDetailScreen> with BasicState {
late final VoucherDetailViewModel _viewModel; late final VoucherDetailViewModel _viewModel;
late final String _viewModelTag;
double _infoHeight = 0; double _infoHeight = 0;
@override @override
...@@ -59,13 +61,23 @@ class _VoucherDetailScreenState extends BaseState<VoucherDetailScreen> with Basi ...@@ -59,13 +61,23 @@ class _VoucherDetailScreenState extends BaseState<VoucherDetailScreen> with Basi
}); });
return; return;
} }
_viewModel = Get.put(VoucherDetailViewModel(productId: productId, customerProductId: customerProductId)); _viewModelTag = 'voucher_detail_${DateTime.now().microsecondsSinceEpoch}';
_viewModel = Get.put(
VoucherDetailViewModel(productId: productId, customerProductId: customerProductId),
tag: _viewModelTag,
);
_viewModel.onShowAlertError = (message) { _viewModel.onShowAlertError = (message) {
if (message.isEmpty) return; if (message.isEmpty) return;
showAlertError(content: message); showAlertError(content: message);
}; };
} }
@override
void dispose() {
Get.delete<VoucherDetailViewModel>(tag: _viewModelTag);
super.dispose();
}
@override @override
Widget createBody() { Widget createBody() {
return Scaffold( return Scaffold(
...@@ -108,7 +120,12 @@ class _VoucherDetailScreenState extends BaseState<VoucherDetailScreen> with Basi ...@@ -108,7 +120,12 @@ class _VoucherDetailScreenState extends BaseState<VoucherDetailScreen> with Basi
child: Row( child: Row(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [CustomBackButton(), _buildFavoriteButton()], children: [
CustomBackButton(),
_buildFavoriteButton(),
if (kIsWeb)
Expanded(child: SizedBox.shrink())
],
), ),
), ),
), ),
......
...@@ -11,7 +11,7 @@ class VoucherActionMenu extends StatelessWidget { ...@@ -11,7 +11,7 @@ class VoucherActionMenu extends StatelessWidget {
padding: const EdgeInsets.symmetric(vertical: 12), padding: const EdgeInsets.symmetric(vertical: 12),
child: Row( child: Row(
children: const [ children: const [
_ActionItem(icon: "assets/images/ic_topup.png", label: 'Nạp tiền\ndiện thoại', type: DirectionalScreenName.topup,), _ActionItem(icon: "assets/images/ic_topup.png", label: 'Nạp tiền\nđiện thoại', type: DirectionalScreenName.topup,),
_ActionItem(icon: "assets/images/ic_card_code.png", label: 'Đổi mã\nthẻ nạp', type: DirectionalScreenName.productMobileCard,), _ActionItem(icon: "assets/images/ic_card_code.png", label: 'Đổi mã\nthẻ nạp', type: DirectionalScreenName.productMobileCard,),
_ActionItem(icon: "assets/images/ic_sim_service.png", label: 'Gói cước\nnhà mạng', type: DirectionalScreenName.simService,), _ActionItem(icon: "assets/images/ic_sim_service.png", label: 'Gói cước\nnhà mạng', type: DirectionalScreenName.simService,),
_ActionItem(icon: "assets/images/ic_topup_data.png", label: 'Ưu đãi\nData', type: DirectionalScreenName.mobileTopupData,), _ActionItem(icon: "assets/images/ic_topup_data.png", label: 'Ưu đãi\nData', type: DirectionalScreenName.mobileTopupData,),
......
...@@ -52,8 +52,9 @@ class VoucherListViewModel extends RestfulApiViewModel { ...@@ -52,8 +52,9 @@ class VoucherListViewModel extends RestfulApiViewModel {
} }
void onSearchChanged(String value) { void onSearchChanged(String value) {
if (_searchQuery == value) return; final value_ = value.trim();
_searchQuery = value; if (_searchQuery == value_) return;
_searchQuery = value_;
_debounce?.cancel(); _debounce?.cancel();
_debounce = Timer(const Duration(seconds: 1), () { _debounce = Timer(const Duration(seconds: 1), () {
loadData(reset: true); loadData(reset: true);
......
...@@ -33,30 +33,33 @@ class CustomAlertDialog extends StatelessWidget { ...@@ -33,30 +33,33 @@ class CustomAlertDialog extends StatelessWidget {
children: [ children: [
_buildHeaderImage(), _buildHeaderImage(),
Padding( Padding(
padding: const EdgeInsets.all(16), padding: const EdgeInsets.all(8),
child: Column( child: Column(
children: [ children: [
if ((alertData.title ?? "").isNotEmpty) if ((alertData.title ?? "").isNotEmpty)... [
Text( Text(
alertData.title!, alertData.title!,
style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold), style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
textAlign: TextAlign.center, textAlign: TextAlign.center,
), ),
const SizedBox(height: 8), const SizedBox(height: 4)
if (alertData.description != null) ],
if (alertData.description != null)... [
HtmlWidget(''' HtmlWidget('''
<div style="text-align: center;"> <div style="text-align: center;">
${alertData.description!} ${alertData.description!}
</div> </div>
'''), '''),
const SizedBox(height: 4), const SizedBox(height: 4),
if ((alertData.content ?? "").isNotEmpty) ],
if ((alertData.content ?? "").isNotEmpty)... [
Text( Text(
alertData.content!, alertData.content!,
style: TextStyle(fontSize: 14, fontWeight: FontWeight.w600, color: BaseColor.primary500), style: TextStyle(fontSize: 14, fontWeight: FontWeight.w600, color: BaseColor.primary500),
textAlign: TextAlign.center, textAlign: TextAlign.center,
), ),
const SizedBox(height: 8), const SizedBox(height: 4),
],
_buildButtons(), _buildButtons(),
], ],
), ),
......
...@@ -16,7 +16,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev ...@@ -16,7 +16,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
# In Windows, build-name is used as the major, minor, and patch parts # In Windows, build-name is used as the major, minor, and patch parts
# of the product and file versions while build-number is used as the build suffix. # of the product and file versions while build-number is used as the build suffix.
version: 1.21.11+2025102401 version: 1.21.13+2025123101
environment: environment:
sdk: ^3.7.0 sdk: ^3.7.0
......
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