Commit f714cdcc authored by DatHV's avatar DatHV
Browse files

update logic, flutter refactor

parent cc202df4
...@@ -3,6 +3,7 @@ class Constants { ...@@ -3,6 +3,7 @@ class Constants {
static get commonError => "Hệ thống không thể xử lý yêu cầu hiện tại. Vui lòng thử lại sau hoặc liên hệ hotline 1900599863 để được trợ giúp."; static get commonError => "Hệ thống không thể xử lý yêu cầu hiện tại. Vui lòng thử lại sau hoặc liên hệ hotline 1900599863 để được trợ giúp.";
static var otpTtl = 180; static var otpTtl = 180;
static var directionInApp = "IN-APP"; static var directionInApp = "IN-APP";
static var phoneNumberCount = 10;
} }
class ErrorCodes { class ErrorCodes {
......
import 'dart:async';
class Debouncer {
Debouncer({this.ms = 300});
final int ms;
Timer? _t;
void run(void Function() action) {
_t?.cancel();
_t = Timer(Duration(milliseconds: ms), action);
}
void dispose() => _t?.cancel();
}
\ No newline at end of file
...@@ -5,10 +5,12 @@ import 'package:mypoint_flutter_app/networking/app_navigator.dart'; ...@@ -5,10 +5,12 @@ import 'package:mypoint_flutter_app/networking/app_navigator.dart';
import 'package:mypoint_flutter_app/preference/data_preference.dart'; import 'package:mypoint_flutter_app/preference/data_preference.dart';
import 'package:mypoint_flutter_app/preference/point/point_manager.dart'; import 'package:mypoint_flutter_app/preference/point/point_manager.dart';
import 'package:mypoint_flutter_app/resources/base_color.dart'; import 'package:mypoint_flutter_app/resources/base_color.dart';
import 'package:mypoint_flutter_app/screen/home/header_home_viewmodel.dart';
import 'package:mypoint_flutter_app/shared/router_gage.dart'; import 'package:mypoint_flutter_app/shared/router_gage.dart';
void main() async { void main() async {
WidgetsFlutterBinding.ensureInitialized(); WidgetsFlutterBinding.ensureInitialized();
Get.put(HeaderThemeController(), permanent: true);
await DataPreference.instance.init(); await DataPreference.instance.init();
await UserPointManager().fetchUserPoint(); await UserPointManager().fetchUserPoint();
runApp(const MyApp()); runApp(const MyApp());
......
...@@ -47,6 +47,7 @@ class RestfulAPIClient { ...@@ -47,6 +47,7 @@ class RestfulAPIClient {
final isGet = method == Method.GET; final isGet = method == Method.GET;
Json query = isGet ? params : {}; Json query = isGet ? params : {};
Json body = !isGet ? params : {}; Json body = !isGet ? params : {};
// body["lang"] = 'vi';
final option = Options(method: method.name) final option = Options(method: method.name)
.compose( .compose(
_dio.options, _dio.options,
......
...@@ -66,7 +66,7 @@ import '../screen/transaction/model/order_product_payment_response_model.dart'; ...@@ -66,7 +66,7 @@ import '../screen/transaction/model/order_product_payment_response_model.dart';
import '../screen/transaction/model/payment_bank_account_info_model.dart'; import '../screen/transaction/model/payment_bank_account_info_model.dart';
import '../screen/transaction/model/payment_method_model.dart'; import '../screen/transaction/model/payment_method_model.dart';
import '../screen/transaction/model/preview_order_payment_model.dart'; import '../screen/transaction/model/preview_order_payment_model.dart';
import '../screen/voucher/models/like_product_reponse_model.dart'; import '../screen/voucher/models/like_product_response_model.dart';
import '../screen/voucher/models/my_mobile_card_response.dart'; import '../screen/voucher/models/my_mobile_card_response.dart';
import '../screen/voucher/models/my_product_status_type.dart'; import '../screen/voucher/models/my_product_status_type.dart';
import '../screen/voucher/models/product_brand_model.dart'; import '../screen/voucher/models/product_brand_model.dart';
...@@ -338,10 +338,10 @@ extension RestfullAPIClientAllApi on RestfulAPIClient { ...@@ -338,10 +338,10 @@ extension RestfullAPIClientAllApi on RestfulAPIClient {
}); });
} }
Future<BaseResponseModel<LikeProductReponseModel>> likeProduct(int id) async { Future<BaseResponseModel<LikeProductResponseModel>> likeProduct(int id) async {
final body = {"product_id": id}; final body = {"product_id": id};
return requestNormal(APIPaths.productCustomerLikes, Method.POST, body, (data) { return requestNormal(APIPaths.productCustomerLikes, Method.POST, body, (data) {
return LikeProductReponseModel.fromJson(data as Json); return LikeProductResponseModel.fromJson(data as Json);
}); });
} }
...@@ -608,7 +608,7 @@ extension RestfullAPIClientAllApi on RestfulAPIClient { ...@@ -608,7 +608,7 @@ extension RestfullAPIClientAllApi on RestfulAPIClient {
Future<BaseResponseModel<MembershipInfoResponse>> getMembershipLevelInfo() async { Future<BaseResponseModel<MembershipInfoResponse>> getMembershipLevelInfo() async {
String? token = DataPreference.instance.token ?? ""; String? token = DataPreference.instance.token ?? "";
final body = {"access_token": token}; final body = {"access_token": token, "lang": "vi"};
return requestNormal(APIPaths.getMembershipLevelInfo, Method.POST, body, (data) { return requestNormal(APIPaths.getMembershipLevelInfo, Method.POST, body, (data) {
return MembershipInfoResponse.fromJson(data as Json); return MembershipInfoResponse.fromJson(data as Json);
}); });
......
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:mypoint_flutter_app/networking/restful_api_request.dart'; import 'package:mypoint_flutter_app/networking/restful_api_request.dart';
import '../../base/restful_api_viewmodel.dart'; import '../../base/restful_api_viewmodel.dart';
import '../data_preference.dart';
import 'header_home_model.dart'; import 'header_home_model.dart';
class UserPointManager extends RestfulApiViewModel { class UserPointManager extends RestfulApiViewModel {
...@@ -13,7 +14,8 @@ class UserPointManager extends RestfulApiViewModel { ...@@ -13,7 +14,8 @@ class UserPointManager extends RestfulApiViewModel {
get point => _userPoint.value; get point => _userPoint.value;
Future<int> fetchUserPoint() async { Future fetchUserPoint() async {
if (!DataPreference.instance.logged) return;
try { try {
final response = await client.getHomeHeaderData(); final response = await client.getHomeHeaderData();
if (response.isSuccess && response.data != null) { if (response.isSuccess && response.data != null) {
...@@ -25,6 +27,5 @@ class UserPointManager extends RestfulApiViewModel { ...@@ -25,6 +27,5 @@ class UserPointManager extends RestfulApiViewModel {
} catch (e) { } catch (e) {
_userPoint.value = 0; _userPoint.value = 0;
} }
return _userPoint.value;
} }
} }
...@@ -51,7 +51,6 @@ class _AffiliateTabScreenState extends BaseState<AffiliateTabScreen> with BasicS ...@@ -51,7 +51,6 @@ class _AffiliateTabScreenState extends BaseState<AffiliateTabScreen> with BasicS
backgroundColor: Colors.grey.shade50, backgroundColor: Colors.grey.shade50,
appBar: CustomNavigationBar( appBar: CustomNavigationBar(
title: "Mua sắm", title: "Mua sắm",
backgroundImage: _headerHomeVM.headerData.background ?? "assets/images/bg_header_navi.png",
leftButtons: _canBackButton ? [CustomBackButton()] : [], leftButtons: _canBackButton ? [CustomBackButton()] : [],
rightButtons: [ rightButtons: [
IconButton( IconButton(
......
import 'dart:async';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:mypoint_flutter_app/extensions/num_extension.dart'; import 'package:mypoint_flutter_app/extensions/num_extension.dart';
...@@ -7,6 +8,7 @@ import 'package:mypoint_flutter_app/widgets/custom_navigation_bar.dart'; ...@@ -7,6 +8,7 @@ import 'package:mypoint_flutter_app/widgets/custom_navigation_bar.dart';
import 'package:mypoint_flutter_app/widgets/image_loader.dart'; import 'package:mypoint_flutter_app/widgets/image_loader.dart';
import '../../base/base_screen.dart'; import '../../base/base_screen.dart';
import '../../base/basic_state.dart'; import '../../base/basic_state.dart';
import '../../extensions/debouncer.dart';
import '../../preference/data_preference.dart'; import '../../preference/data_preference.dart';
import '../../preference/point/point_manager.dart'; import '../../preference/point/point_manager.dart';
import '../../resources/base_color.dart'; import '../../resources/base_color.dart';
...@@ -26,6 +28,7 @@ class DataNetworkServiceScreen extends BaseScreen { ...@@ -26,6 +28,7 @@ class DataNetworkServiceScreen extends BaseScreen {
class _DataNetworkServiceScreenState extends BaseState<DataNetworkServiceScreen> with BasicState { class _DataNetworkServiceScreenState extends BaseState<DataNetworkServiceScreen> with BasicState {
final DataNetworkServiceViewModel _viewModel = Get.put(DataNetworkServiceViewModel()); final DataNetworkServiceViewModel _viewModel = Get.put(DataNetworkServiceViewModel());
late final TextEditingController _phoneController; late final TextEditingController _phoneController;
final _deb = Debouncer(ms: 500);
@override @override
void initState() { void initState() {
...@@ -76,8 +79,7 @@ class _DataNetworkServiceScreenState extends BaseState<DataNetworkServiceScreen> ...@@ -76,8 +79,7 @@ class _DataNetworkServiceScreenState extends BaseState<DataNetworkServiceScreen>
Widget _buildButton() { Widget _buildButton() {
return Obx(() { return Obx(() {
final isValidInput = final isValidInput = _viewModel.validatePhoneNumber() && (_viewModel.selectedProduct.value != null);
(_viewModel.phoneNumber.value.trim().length >= 10) && (_viewModel.selectedProduct.value != null);
return ElevatedButton( return ElevatedButton(
onPressed: isValidInput ? _redeemProductMobileCard : null, onPressed: isValidInput ? _redeemProductMobileCard : null,
style: ElevatedButton.styleFrom( style: ElevatedButton.styleFrom(
...@@ -234,7 +236,7 @@ class _DataNetworkServiceScreenState extends BaseState<DataNetworkServiceScreen> ...@@ -234,7 +236,7 @@ class _DataNetworkServiceScreenState extends BaseState<DataNetworkServiceScreen>
keyboardType: TextInputType.phone, keyboardType: TextInputType.phone,
onChanged: (value) { onChanged: (value) {
_viewModel.phoneNumber.value = value; _viewModel.phoneNumber.value = value;
_viewModel.checkMobileNetwork(); _deb.run(() => _viewModel.checkMobileNetwork());
}, },
), ),
), ),
......
...@@ -30,6 +30,12 @@ class DataNetworkServiceViewModel extends RestfulApiViewModel { ...@@ -30,6 +30,12 @@ class DataNetworkServiceViewModel extends RestfulApiViewModel {
return UserPointManager().point >= payPoint; return UserPointManager().point >= payPoint;
} }
bool validatePhoneNumber() {
final phone = phoneNumber.value.replaceAll(RegExp(r'\s+'), '');
final regex = RegExp(r'^(0|\+84)(3[2-9]|5[6|8|9]|7[0|6-9]|8[1-5]|9[0-4|6-9])[0-9]{7}$');
return regex.hasMatch(phone);
}
@override @override
void onInit() { void onInit() {
super.onInit(); super.onInit();
...@@ -49,37 +55,39 @@ class DataNetworkServiceViewModel extends RestfulApiViewModel { ...@@ -49,37 +55,39 @@ class DataNetworkServiceViewModel extends RestfulApiViewModel {
} }
firstLoadNetworkData() async { firstLoadNetworkData() async {
showLoading(); _getNetworkBrands();
await getNetworkBrands();
print("topUpBrands ${topUpBrands.length}");
await checkMobileNetwork();
hideLoading();
} }
getNetworkBrands() { _getNetworkBrands() {
showLoading();
client.productTopUpBrands().then((response) { client.productTopUpBrands().then((response) {
topUpBrands.value = response.data ?? []; topUpBrands.value = response.data ?? [];
hideLoading();
checkMobileNetwork();
}).catchError((error) { }).catchError((error) {
hideLoading();
print('Error fetching brands topup: $error'); print('Error fetching brands topup: $error');
}); });
} }
checkMobileNetwork() { checkMobileNetwork() {
showLoading();
client.checkMobileNetwork(phoneNumber.value).then((response) { client.checkMobileNetwork(phoneNumber.value).then((response) {
final brandCode = response.data?.brand ?? ''; final brandCode = response.data?.brand ?? '';
final brand = topUpBrands.isNotEmpty final brand = topUpBrands.isNotEmpty
? topUpBrands.firstWhere( ? topUpBrands.firstWhere(
(brand) => brand.code == brandCode, (brand) => brand.code == brandCode,
orElse: () => topUpBrands.first, orElse: () => topUpBrands.first,
) ) : null;
: null;
selectedBrand.value = brand; selectedBrand.value = brand;
hideLoading();
getTelcoDetail(); getTelcoDetail();
}).catchError((error) { }).catchError((error) {
final first = topUpBrands.value.firstOrNull; final first = topUpBrands.value.firstOrNull;
if (first != null) { if (first != null) {
selectedBrand.value = first; selectedBrand.value = first;
} }
hideLoading();
getTelcoDetail(); getTelcoDetail();
print('Error checking mobile network: $error'); print('Error checking mobile network: $error');
}); });
......
...@@ -59,7 +59,6 @@ class _GameTabScreenState extends BaseState<GameTabScreen> with BasicState, Popu ...@@ -59,7 +59,6 @@ class _GameTabScreenState extends BaseState<GameTabScreen> with BasicState, Popu
appBar: CustomNavigationBar( appBar: CustomNavigationBar(
title: "Games", title: "Games",
leftButtons: _canBackButton ? [CustomBackButton()] : [], leftButtons: _canBackButton ? [CustomBackButton()] : [],
backgroundImage: _headerHomeVM.headerData.background ?? "assets/images/bg_header_navi.png",
rightButtons: [ rightButtons: [
CompositedTransformTarget( CompositedTransformTarget(
link: _layerLink, link: _layerLink,
......
import 'package:get/get_rx/src/rx_types/rx_types.dart'; import 'package:get/get.dart';
import 'package:mypoint_flutter_app/networking/restful_api_request.dart'; import 'package:mypoint_flutter_app/networking/restful_api_request.dart';
import '../../base/restful_api_viewmodel.dart'; import '../../base/restful_api_viewmodel.dart';
import '../../preference/point/header_home_model.dart'; import '../../preference/point/header_home_model.dart';
import 'models/notification_unread_model.dart'; import 'models/notification_unread_model.dart';
class HeaderThemeController extends GetxController {
final background = RxnString();
void setBackground(String? url) => background.value = url;
}
class HeaderHomeViewModel extends RestfulApiViewModel { class HeaderHomeViewModel extends RestfulApiViewModel {
final Rx<HeaderHomeModel?> _headerHomeData = Rx<HeaderHomeModel?>(null); final Rx<HeaderHomeModel?> _headerHomeData = Rx<HeaderHomeModel?>(null);
var notificationUnreadData = Rxn<NotificationUnreadData>(); var notificationUnreadData = Rxn<NotificationUnreadData>();
...@@ -30,6 +35,7 @@ class HeaderHomeViewModel extends RestfulApiViewModel { ...@@ -30,6 +35,7 @@ class HeaderHomeViewModel extends RestfulApiViewModel {
try { try {
final result = await client.getDynamicHeaderHome(); final result = await client.getDynamicHeaderHome();
_headerHomeData.value = result.data; _headerHomeData.value = result.data;
Get.find<HeaderThemeController>().setBackground(_headerHomeData.value?.background);
} catch (error) { } catch (error) {
print("Error fetching getDynamicHeaderHome: $error"); print("Error fetching getDynamicHeaderHome: $error");
} }
......
...@@ -92,10 +92,11 @@ class _MainTabScreenState extends State<MainTabScreen> { ...@@ -92,10 +92,11 @@ class _MainTabScreenState extends State<MainTabScreen> {
const SizedBox(height: 2), const SizedBox(height: 2),
Text( Text(
label, label,
maxLines: 1,
style: TextStyle( style: TextStyle(
color: isSelected ? Colors.white : Colors.white70, color: isSelected ? Colors.white : Colors.white70,
fontWeight: isSelected ? FontWeight.bold : FontWeight.normal, fontWeight: isSelected ? FontWeight.bold : FontWeight.normal,
fontSize: 14, fontSize: 12,
), ),
), ),
], ],
......
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:get/get_core/src/get_main.dart';
import 'package:intl/intl.dart'; import 'package:intl/intl.dart';
import 'package:mypoint_flutter_app/extensions/string_extension.dart'; import 'package:mypoint_flutter_app/extensions/string_extension.dart';
...@@ -10,6 +12,7 @@ import 'models/membership_level_model.dart'; ...@@ -10,6 +12,7 @@ import 'models/membership_level_model.dart';
class MemberLevelHeaderWidget extends StatelessWidget { class MemberLevelHeaderWidget extends StatelessWidget {
final MembershipLevelModel? level; final MembershipLevelModel? level;
const MemberLevelHeaderWidget({super.key, this.level}); const MemberLevelHeaderWidget({super.key, this.level});
@override @override
...@@ -38,13 +41,13 @@ class MemberLevelHeaderWidget extends StatelessWidget { ...@@ -38,13 +41,13 @@ class MemberLevelHeaderWidget extends StatelessWidget {
children: [ children: [
Row( Row(
children: [ children: [
Container( loadNetworkImage(
width: 72, url: "level?.logo",
height: 72, width: 116,
decoration: BoxDecoration(shape: BoxShape.circle, border: Border.all(color: Colors.white, width: 2)), height: 116,
child: ClipOval(child: Image.asset("assets/images/bg_default_11.png")), placeholderAsset: "assets/images/ic_logo_rank_member.png",
), ),
const SizedBox(width: 12), const SizedBox(width: 6),
Column( Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
...@@ -53,6 +56,7 @@ class MemberLevelHeaderWidget extends StatelessWidget { ...@@ -53,6 +56,7 @@ class MemberLevelHeaderWidget extends StatelessWidget {
style: const TextStyle(fontSize: 22, fontWeight: FontWeight.bold, color: Colors.white), style: const TextStyle(fontSize: 22, fontWeight: FontWeight.bold, color: Colors.white),
), ),
const SizedBox(height: 4), const SizedBox(height: 4),
if ((level?.levelName ?? "").isNotEmpty)
Container( Container(
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 4), padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 4),
decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.circular(20)), decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.circular(20)),
...@@ -65,7 +69,7 @@ class MemberLevelHeaderWidget extends StatelessWidget { ...@@ -65,7 +69,7 @@ class MemberLevelHeaderWidget extends StatelessWidget {
), ),
], ],
), ),
const SizedBox(height: 16), const SizedBox(height: 6),
// Progress bar // Progress bar
_buildCardInfo(), _buildCardInfo(),
], ],
...@@ -79,13 +83,19 @@ class MemberLevelHeaderWidget extends StatelessWidget { ...@@ -79,13 +83,19 @@ class MemberLevelHeaderWidget extends StatelessWidget {
final int spendingMax = double.tryParse(level?.upgradeGmvThreshold ?? "0")?.toInt() ?? 1; final int spendingMax = double.tryParse(level?.upgradeGmvThreshold ?? "0")?.toInt() ?? 1;
return Container( return Container(
padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 16), padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 16),
decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.circular(16)), decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(16),
boxShadow: [
BoxShadow(color: Colors.black.withOpacity(0.3), blurRadius: 16, spreadRadius: 0, offset: const Offset(0, 6)),
],
),
child: Row( child: Row(
children: [ children: [
Expanded( Expanded(
child: GestureDetector( child: GestureDetector(
onTap: () { onTap: () {
print("GestureDetector"); Get.toNamed('/pointHistoryScreen');
}, },
behavior: HitTestBehavior.opaque, behavior: HitTestBehavior.opaque,
child: Column( child: Column(
...@@ -118,7 +128,7 @@ class MemberLevelHeaderWidget extends StatelessWidget { ...@@ -118,7 +128,7 @@ class MemberLevelHeaderWidget extends StatelessWidget {
Expanded( Expanded(
child: GestureDetector( child: GestureDetector(
onTap: () { onTap: () {
print("GestureDetector"); Get.toNamed('/historyPointCashBackScreen');
}, },
behavior: HitTestBehavior.opaque, behavior: HitTestBehavior.opaque,
child: Column( child: Column(
......
...@@ -45,7 +45,7 @@ class _MembershipScreenState extends BaseState<MembershipScreen> with BasicState ...@@ -45,7 +45,7 @@ class _MembershipScreenState extends BaseState<MembershipScreen> with BasicState
Padding( Padding(
padding: EdgeInsets.symmetric(horizontal: 16, vertical: 8), padding: EdgeInsets.symmetric(horizontal: 16, vertical: 8),
child: Text( child: Text(
"Hạng thành viên sẽ được cập nhật sau ${_viewModel.selectedLevel?.levelEndAtDate}", "Hạng thành viên sẽ được cập nhật sau ${_viewModel.selectedLevel?.levelEndAtDate ?? ''}",
style: TextStyle(color: Colors.black54, fontSize: 13), style: TextStyle(color: Colors.black54, fontSize: 13),
), ),
), ),
...@@ -82,7 +82,7 @@ class _MembershipScreenState extends BaseState<MembershipScreen> with BasicState ...@@ -82,7 +82,7 @@ class _MembershipScreenState extends BaseState<MembershipScreen> with BasicState
], ],
), ),
const SizedBox(height: 8), const SizedBox(height: 8),
HtmlWidget("item.content ?? "), HtmlWidget(item.content ?? ''),
], ],
), ),
); );
......
import 'dart:convert';
import 'package:flutter/services.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:mypoint_flutter_app/extensions/collection_extension.dart'; import 'package:mypoint_flutter_app/extensions/collection_extension.dart';
import 'package:mypoint_flutter_app/networking/restful_api_request.dart'; import 'package:mypoint_flutter_app/networking/restful_api_request.dart';
...@@ -22,14 +20,13 @@ class MembershipViewModel extends RestfulApiViewModel { ...@@ -22,14 +20,13 @@ class MembershipViewModel extends RestfulApiViewModel {
if (levels == null || levels!.isEmpty) { if (levels == null || levels!.isEmpty) {
return null; return null;
} }
return levels?.safe(selectedTab.value)?.conditions?.whereType<MembershipLevelTermAndConditionModel>().toList(); return levels?.safe(selectedTab.value)?.conditions;
} }
@override @override
onInit() { onInit() {
super.onInit(); super.onInit();
getMembershipLevelInfo(); getMembershipLevelInfo();
// loadMembershipInfoFromAssets();
} }
_makeSelectedLevel() { _makeSelectedLevel() {
...@@ -40,22 +37,10 @@ class MembershipViewModel extends RestfulApiViewModel { ...@@ -40,22 +37,10 @@ class MembershipViewModel extends RestfulApiViewModel {
selectedLevel = levels!.firstWhere((e) => e.levelStartAtDate?.isNotEmpty == true, orElse: () => levels!.first); selectedLevel = levels!.firstWhere((e) => e.levelStartAtDate?.isNotEmpty == true, orElse: () => levels!.first);
} }
loadMembershipInfoFromAssets() async {
final jsonStr = await rootBundle.loadString('assets/data/membership_info.json');
final jsonMap = jsonDecode(jsonStr);
final result = MembershipInfoResponse.fromJson(jsonMap['data']);
membershipInfo.value = result;
_makeSelectedLevel();
}
getMembershipLevelInfo() async { getMembershipLevelInfo() async {
showLoading(); showLoading();
try { try {
final response = await client.getMembershipLevelInfo(); final response = await client.getMembershipLevelInfo();
print("getMembershipLevelInfo");
print(response.data?.membershipRule);
print(response.data?.levels?.first?.condition);
print(response.data?.levels?.first?.conditions);
membershipInfo.value = response.data; membershipInfo.value = response.data;
_makeSelectedLevel(); _makeSelectedLevel();
hideLoading(); hideLoading();
......
...@@ -59,7 +59,7 @@ class MembershipLevelModel { ...@@ -59,7 +59,7 @@ class MembershipLevelModel {
final String? downgradeToLevelId; final String? downgradeToLevelId;
@JsonKey(name: 'membership_level_term_and_conditions') @JsonKey(name: 'membership_level_term_and_conditions')
final List<MembershipLevelTermAndConditionModel?>? conditions; final List<MembershipLevelTermAndConditionModel>? conditions;
@JsonKey(name: 'accumulated_counter') @JsonKey(name: 'accumulated_counter')
final AccumulatedCounter? accumulatedCounter; final AccumulatedCounter? accumulatedCounter;
......
...@@ -32,10 +32,7 @@ MembershipLevelModel _$MembershipLevelModelFromJson( ...@@ -32,10 +32,7 @@ MembershipLevelModel _$MembershipLevelModelFromJson(
conditions: conditions:
(json['membership_level_term_and_conditions'] as List<dynamic>?) (json['membership_level_term_and_conditions'] as List<dynamic>?)
?.map( ?.map(
(e) => (e) => MembershipLevelTermAndConditionModel.fromJson(
e == null
? null
: MembershipLevelTermAndConditionModel.fromJson(
e as Map<String, dynamic>, e as Map<String, dynamic>,
), ),
) )
......
...@@ -124,13 +124,15 @@ class _ProductMobileCardScreenState extends BaseState<ProductMobileCardScreen> w ...@@ -124,13 +124,15 @@ class _ProductMobileCardScreenState extends BaseState<ProductMobileCardScreen> w
} }
Widget _buildProductItem() { Widget _buildProductItem() {
const double kItemHeight = 80;
final widthItem = (MediaQuery.of(context).size.width - 12*3)/2;
return Expanded( return Expanded(
child: GridView.count( child: GridView.count(
crossAxisCount: 2, crossAxisCount: 2,
padding: const EdgeInsets.symmetric(horizontal: 16), padding: const EdgeInsets.symmetric(horizontal: 16),
crossAxisSpacing: 12, crossAxisSpacing: 12,
mainAxisSpacing: 12, mainAxisSpacing: 12,
childAspectRatio: 2.4, childAspectRatio: widthItem/kItemHeight,
children: children:
_viewModel.products.map((product) { _viewModel.products.map((product) {
final isSelected = _viewModel.selectedProduct?.id == product.id; final isSelected = _viewModel.selectedProduct?.id == product.id;
...@@ -153,7 +155,7 @@ class _ProductMobileCardScreenState extends BaseState<ProductMobileCardScreen> w ...@@ -153,7 +155,7 @@ class _ProductMobileCardScreenState extends BaseState<ProductMobileCardScreen> w
borderRadius: BorderRadius.circular(12), borderRadius: BorderRadius.circular(12),
color: isSelected ? Colors.orange.withOpacity(0.1) : Colors.white, color: isSelected ? Colors.orange.withOpacity(0.1) : Colors.white,
), ),
padding: const EdgeInsets.all(12), padding: const EdgeInsets.all(10),
child: Column( child: Column(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
......
...@@ -7,6 +7,7 @@ import '../../resources/base_color.dart'; ...@@ -7,6 +7,7 @@ import '../../resources/base_color.dart';
import '../../widgets/alert/data_alert_model.dart'; import '../../widgets/alert/data_alert_model.dart';
import '../../widgets/back_button.dart'; import '../../widgets/back_button.dart';
import '../../widgets/custom_empty_widget.dart'; import '../../widgets/custom_empty_widget.dart';
import '../../widgets/custom_navigation_bar.dart';
import '../../widgets/image_loader.dart'; import '../../widgets/image_loader.dart';
import 'models/notification_item_model.dart'; import 'models/notification_item_model.dart';
import 'notification_viewmodel.dart'; import 'notification_viewmodel.dart';
...@@ -44,22 +45,14 @@ class _NotificationScreenState extends BaseState<NotificationScreen> with BasicS ...@@ -44,22 +45,14 @@ class _NotificationScreenState extends BaseState<NotificationScreen> with BasicS
@override @override
Widget createBody() { Widget createBody() {
return Scaffold( return Scaffold(
appBar: AppBar( appBar: CustomNavigationBar(
scrolledUnderElevation: 0, title: "Thông báo",
backgroundColor: Colors.white, rightButtons: [
elevation: 0,
centerTitle: true,
title: const Text(
'Thông báo',
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold, color: Colors.black87),
),
leading: CustomBackButton(),
actions: [
CompositedTransformTarget( CompositedTransformTarget(
link: _layerLink, link: _layerLink,
child: IconButton( child: IconButton(
key: _infoKey, key: _infoKey,
icon: const Icon(Icons.settings, color: Colors.black), icon: const Icon(Icons.settings, color: Colors.black54),
onPressed: _toggleSetting, onPressed: _toggleSetting,
), ),
), ),
......
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