Commit f0334970 authored by DatHV's avatar DatHV
Browse files

update flash sale

parent b93b2948
import 'package:json_annotation/json_annotation.dart'; import 'package:json_annotation/json_annotation.dart';
import '../../flash_sale/preview_flash_sale_model.dart'; import '../../flash_sale/models/preview_flash_sale_model.dart';
import '../../voucher/models/product_model.dart'; import '../../voucher/models/product_model.dart';
part 'flash_sale_model.g.dart'; part 'flash_sale_model.g.dart';
......
import 'package:json_annotation/json_annotation.dart'; import 'package:json_annotation/json_annotation.dart';
import 'package:mypoint_flutter_app/directional/directional_screen.dart'; import 'package:mypoint_flutter_app/directional/directional_screen.dart';
import '../../flash_sale/preview_flash_sale_model.dart'; import '../../flash_sale/models/preview_flash_sale_model.dart';
import 'header_section_type.dart'; import 'header_section_type.dart';
part 'main_section_config_model.g.dart'; part 'main_section_config_model.g.dart';
......
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:mypoint_flutter_app/extensions/string_extension.dart';
import 'package:mypoint_flutter_app/widgets/custom_app_bar.dart'; import 'package:mypoint_flutter_app/widgets/custom_app_bar.dart';
import '../../base/base_screen.dart';
import '../../base/basic_state.dart';
import '../../widgets/image_loader.dart'; import '../../widgets/image_loader.dart';
import 'models/notification_detail_model.dart'; import 'models/notification_detail_model.dart';
import 'notification_detail_viewmodel.dart';
class NotificationDetailScreen extends StatelessWidget { class NotificationDetailScreen extends BaseScreen {
final NotificationDetailModel notification; const NotificationDetailScreen({super.key});
const NotificationDetailScreen({super.key, required this.notification}); @override
State<NotificationDetailScreen> createState() => _NotificationDetailScreenState();
}
class _NotificationDetailScreenState extends BaseState<NotificationDetailScreen> with BasicState {
final _viewModel = Get.put(NotificationDetailViewModel());
@override
void initState() {
super.initState();
NotificationDetailModel? notification;
String? notificationId;
String? title;
String? body;
final args = Get.arguments;
if (args is Map) {
notification = args['notification'];
notificationId = args['notificationId'];
title = args['title'];
body = args['body'];
}
if (title.orEmpty.isNotEmpty && body.orEmpty.isNotEmpty) {
notification ??= NotificationDetailModel(title: title, body: body);
}
if (notificationId == null && notification == null) {
WidgetsBinding.instance.addPostFrameCallback((_) {
Get.back();
});
return;
}
_viewModel.onShowAlertError = (message) {
if (message.isEmpty) return;
showAlertError(
content: message,
onConfirmed: () {
Get.back();
},
);
};
_viewModel.fetchNotificationDetail(id: notificationId, data: notification);
}
@override @override
Widget build(BuildContext context) { Widget createBody() {
return Scaffold( return Scaffold(
appBar: CustomAppBar.back(title: "Chi tiết thông báo"), appBar: CustomAppBar.back(title: "Chi tiết thông báo"),
body: Container( body: Obx(
color: Colors.grey.shade100, () => Container(
padding: const EdgeInsets.all(16), color: Colors.grey.shade100,
child: IntrinsicHeight( padding: const EdgeInsets.all(16),
child: Container( child: IntrinsicHeight(
padding: const EdgeInsets.all(16), child: Container(
decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.circular(12)), padding: const EdgeInsets.all(16),
child: Row( decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.circular(12)),
crossAxisAlignment: CrossAxisAlignment.start, child: Row(
children: [ crossAxisAlignment: CrossAxisAlignment.start,
ClipRRect( children: [
borderRadius: BorderRadius.circular(8), ClipRRect(
child: loadNetworkImage( borderRadius: BorderRadius.circular(8),
url: notification.workingSite?.avatar ?? "", child: loadNetworkImage(
fit: BoxFit.cover, url: _viewModel.notification.value?.workingSite?.avatar ?? "",
width: 40, fit: BoxFit.cover,
height: 40, width: 40,
placeholderAsset: 'assets/images/ic_logo.png', height: 40,
placeholderAsset: 'assets/images/ic_logo.png',
),
), ),
), const SizedBox(width: 12),
const SizedBox(width: 12), Expanded(
Expanded( child: Column(
child: Column( crossAxisAlignment: CrossAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start, children: [
children: [ Text(
Text(notification.title ?? '', style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 16)), _viewModel.notification.value?.title ?? '',
const SizedBox(height: 6), style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 16),
Text(notification.body ?? '', style: const TextStyle(fontSize: 14)), ),
const SizedBox(height: 10), const SizedBox(height: 6),
Text(_timeAgo(notification.createTime), style: const TextStyle(color: Colors.grey, fontSize: 13)), Text(_viewModel.notification.value?.body ?? '', style: const TextStyle(fontSize: 14)),
], const SizedBox(height: 10),
if (_viewModel.notification.value?.createTime.orEmpty.isNotEmpty == true)
Text(
_timeAgo(_viewModel.notification.value?.createTime),
style: const TextStyle(color: Colors.grey, fontSize: 13),
),
],
),
), ),
), ],
], ),
), ),
), ),
), ),
......
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 'models/notification_detail_model.dart';
class NotificationDetailViewModel extends RestfulApiViewModel {
var notification = Rxn<NotificationDetailModel>();
void Function(String message)? onShowAlertError;
Future<void> fetchNotificationDetail({String? id, NotificationDetailModel? data}) async {
if (data != null) {
notification.value = data;
return;
}
if (id == null) return;
await callApi<NotificationDetailResponseModel>(
request: () => client.getNotificationDetail(id ?? ''),
onSuccess: (data, _) {
final notify = data.notification;
if (notify != null) {
notification.value = data.notification;
} else {
onShowAlertError?.call(Constants.commonError);
}
},
onFailure: (msg, _, _) async {
onShowAlertError?.call(msg);
},
);
}
}
\ No newline at end of file
...@@ -3,6 +3,7 @@ import 'package:mypoint_flutter_app/networking/restful_api_client_all_request.da ...@@ -3,6 +3,7 @@ import 'package:mypoint_flutter_app/networking/restful_api_client_all_request.da
import '../../base/base_response_model.dart'; import '../../base/base_response_model.dart';
import '../../networking/restful_api_viewmodel.dart'; import '../../networking/restful_api_viewmodel.dart';
import '../../preference/data_preference.dart'; import '../../preference/data_preference.dart';
import '../../shared/router_gage.dart';
import 'models/category_notify_item_model.dart'; import 'models/category_notify_item_model.dart';
import 'models/notification_detail_model.dart'; import 'models/notification_detail_model.dart';
import 'models/notification_item_model.dart'; import 'models/notification_item_model.dart';
...@@ -128,7 +129,7 @@ class NotificationViewModel extends RestfulApiViewModel { ...@@ -128,7 +129,7 @@ class NotificationViewModel extends RestfulApiViewModel {
if (notification == null) return; if (notification == null) return;
final pushSuccess = notification.directionalScreen?.begin() ?? false; final pushSuccess = notification.directionalScreen?.begin() ?? false;
if (!pushSuccess) { if (!pushSuccess) {
Get.to(() => NotificationDetailScreen(notification: notification)); Get.toNamed(notificationDetailScreen, arguments: {'notification': notification, 'notificationId': item.notificationId});
} }
}, },
onFailure: (msg, _, _) async { onFailure: (msg, _, _) async {
......
import 'dart:async'; import 'dart:async';
import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:mypoint_flutter_app/extensions/string_extension.dart'; import 'package:mypoint_flutter_app/extensions/string_extension.dart';
......
import 'dart:core'; import 'dart:core';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:intl/intl.dart'; import 'package:mypoint_flutter_app/extensions/num_extension.dart';
import '../../base/base_screen.dart'; import '../../base/base_screen.dart';
import '../../base/basic_state.dart'; import '../../base/basic_state.dart';
import '../../resources/base_color.dart'; import '../../resources/base_color.dart';
...@@ -22,7 +22,6 @@ class TransactionDetailScreen extends BaseScreen { ...@@ -22,7 +22,6 @@ class TransactionDetailScreen extends BaseScreen {
class _TransactionDetailScreenState extends BaseState<TransactionDetailScreen> with BasicState { class _TransactionDetailScreenState extends BaseState<TransactionDetailScreen> with BasicState {
late final TransactionDetailViewModel _viewModel; late final TransactionDetailViewModel _viewModel;
final currencyFormatter = NumberFormat.currency(locale: 'vi_VN', symbol: 'đ', decimalDigits: 0);
ProductModel? _product; ProductModel? _product;
String? _metaData; String? _metaData;
int _quantity = 1; int _quantity = 1;
...@@ -211,9 +210,6 @@ class _TransactionDetailScreenState extends BaseState<TransactionDetailScreen> w ...@@ -211,9 +210,6 @@ class _TransactionDetailScreenState extends BaseState<TransactionDetailScreen> w
} }
Widget _buildTotalRow(String label, int amount, bool isHighlighted) { Widget _buildTotalRow(String label, int amount, bool isHighlighted) {
final formattedAmount = currencyFormatter.format(amount);
final displayAmount = amount < 0 ? formattedAmount : formattedAmount;
return Padding( return Padding(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
child: Row( child: Row(
...@@ -221,7 +217,7 @@ class _TransactionDetailScreenState extends BaseState<TransactionDetailScreen> w ...@@ -221,7 +217,7 @@ class _TransactionDetailScreenState extends BaseState<TransactionDetailScreen> w
children: [ children: [
Text(label, style: TextStyle(fontSize: 16, color: Colors.grey.shade700)), Text(label, style: TextStyle(fontSize: 16, color: Colors.grey.shade700)),
Text( Text(
displayAmount, amount.money(CurrencyUnit.vnd),
style: TextStyle( style: TextStyle(
fontSize: 16, fontSize: 16,
fontWeight: FontWeight.w500, fontWeight: FontWeight.w500,
...@@ -469,7 +465,7 @@ class _TransactionDetailScreenState extends BaseState<TransactionDetailScreen> w ...@@ -469,7 +465,7 @@ class _TransactionDetailScreenState extends BaseState<TransactionDetailScreen> w
const Text('Tổng thanh toán', style: TextStyle(fontSize: 14, color: Colors.grey)), const Text('Tổng thanh toán', style: TextStyle(fontSize: 14, color: Colors.grey)),
const SizedBox(height: 4), const SizedBox(height: 4),
Text( Text(
currencyFormatter.format(_viewModel.finalTotal), _viewModel.finalTotal.money(CurrencyUnit.vnd),
style: const TextStyle(fontSize: 22, fontWeight: FontWeight.bold), style: const TextStyle(fontSize: 22, fontWeight: FontWeight.bold),
), ),
], ],
......
...@@ -159,6 +159,7 @@ class _VoucherDetailScreenState extends BaseState<VoucherDetailScreen> with Basi ...@@ -159,6 +159,7 @@ class _VoucherDetailScreenState extends BaseState<VoucherDetailScreen> with Basi
} }
Widget _buildInfo(ProductModel product, {Key? key}) { Widget _buildInfo(ProductModel product, {Key? key}) {
final double screenWidth = MediaQuery.of(context).size.width;
return Container( return Container(
key: key, key: key,
padding: const EdgeInsets.all(16), padding: const EdgeInsets.all(16),
...@@ -198,9 +199,59 @@ class _VoucherDetailScreenState extends BaseState<VoucherDetailScreen> with Basi ...@@ -198,9 +199,59 @@ class _VoucherDetailScreenState extends BaseState<VoucherDetailScreen> with Basi
const SizedBox(width: 8), const SizedBox(width: 8),
Expanded(child: Text(product.brand?.name ?? '', style: const TextStyle(fontSize: 14))), Expanded(child: Text(product.brand?.name ?? '', style: const TextStyle(fontSize: 14))),
// PriceTagWidget(point: product.amountToBePaid ?? 0), // PriceTagWidget(point: product.amountToBePaid ?? 0),
if (product.percentDiscount != null)
Container(
padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 2),
decoration: BoxDecoration(color: Colors.red, borderRadius: BorderRadius.circular(20)),
child: Text(
'-${product.percentDiscount}%',
style: const TextStyle(color: Colors.white, fontWeight: FontWeight.bold, fontSize: 12),
),
),
const SizedBox(width: 4),
CustomPointText(point: product.amountToBePaid ?? 0, type: product.price?.method), CustomPointText(point: product.amountToBePaid ?? 0, type: product.price?.method),
const SizedBox(width: 4),
if (product.price?.value != null && product.previewFlashSale?.isFlashSalePrice == true)
Text(
'${product.price?.value?.money(CurrencyUnit.noneSpace)}đ',
style: const TextStyle(
fontSize: 14,
color: Colors.grey,
decoration: TextDecoration.lineThrough,
),
),
], ],
), ),
if (product.isShowProsessSoldItem)
const SizedBox(height: 16),
if (product.isShowProsessSoldItem)
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
// Thanh tiến trình
SizedBox(
width: screenWidth - 64 - 90,
child: ClipRRect(
borderRadius: BorderRadius.circular(6),
child: LinearProgressIndicator(
value: product.progress,
minHeight: 10,
backgroundColor: Colors.grey.shade300,
valueColor: AlwaysStoppedAnimation<Color>(
product.inStock ? Colors.orange : Colors.red,
),
),
),
),
const SizedBox(width: 2),
Text(
product.inStock
? 'Đã bán ${product.previewFlashSale?.fsQuantitySold ?? 0}'
: 'Đã bán hết',
style: TextStyle(fontSize: 12, color: product.inStock ? Colors.black : Colors.grey),
),
],
),
], ],
), ),
); );
...@@ -218,7 +269,7 @@ class _VoucherDetailScreenState extends BaseState<VoucherDetailScreen> with Basi ...@@ -218,7 +269,7 @@ class _VoucherDetailScreenState extends BaseState<VoucherDetailScreen> with Basi
if (hasExpire) if (hasExpire)
Text( Text(
product.expired ? "Hết hạn" : product.expire, product.expired ? "Hết hạn" : product.expire,
style: const TextStyle(color: BaseColor.primary500, fontWeight: FontWeight.bold, fontSize: 12), style: const TextStyle(color: Colors.orange, fontWeight: FontWeight.bold, fontSize: 14),
), ),
if (isOutOfStock && !_viewModel.isMyProduct) if (isOutOfStock && !_viewModel.isMyProduct)
Container( Container(
......
...@@ -11,7 +11,7 @@ import 'package:mypoint_flutter_app/screen/voucher/models/product_price_model.da ...@@ -11,7 +11,7 @@ import 'package:mypoint_flutter_app/screen/voucher/models/product_price_model.da
import 'package:mypoint_flutter_app/screen/voucher/models/product_properties_model.dart'; import 'package:mypoint_flutter_app/screen/voucher/models/product_properties_model.dart';
import 'package:mypoint_flutter_app/screen/voucher/models/product_type.dart'; import 'package:mypoint_flutter_app/screen/voucher/models/product_type.dart';
import 'package:mypoint_flutter_app/widgets/alert/popup_data_model.dart'; import 'package:mypoint_flutter_app/widgets/alert/popup_data_model.dart';
import '../../flash_sale/preview_flash_sale_model.dart'; import '../../flash_sale/models/preview_flash_sale_model.dart';
import 'media_type.dart'; import 'media_type.dart';
import 'my_product_status_type.dart'; import 'my_product_status_type.dart';
......
...@@ -14,6 +14,7 @@ import '../screen/data_network_service/data_network_service_screen.dart'; ...@@ -14,6 +14,7 @@ import '../screen/data_network_service/data_network_service_screen.dart';
import '../screen/device_manager/device_manager_screen.dart'; import '../screen/device_manager/device_manager_screen.dart';
import '../screen/electric_payment/electric_payment_history_screen.dart'; import '../screen/electric_payment/electric_payment_history_screen.dart';
import '../screen/electric_payment/electric_payment_screen.dart'; import '../screen/electric_payment/electric_payment_screen.dart';
import '../screen/flash_sale/flash_sale_screen.dart';
import '../screen/game/game_cards/game_card_screen.dart'; import '../screen/game/game_cards/game_card_screen.dart';
import '../screen/game/game_tab_screen.dart'; import '../screen/game/game_tab_screen.dart';
import '../screen/health_book/health_book_card_detail.dart'; import '../screen/health_book/health_book_card_detail.dart';
...@@ -27,6 +28,7 @@ import '../screen/login/login_screen.dart'; ...@@ -27,6 +28,7 @@ import '../screen/login/login_screen.dart';
import '../screen/main_tab_screen/main_tab_screen.dart'; import '../screen/main_tab_screen/main_tab_screen.dart';
import '../screen/membership/membership_screen.dart'; import '../screen/membership/membership_screen.dart';
import '../screen/mobile_card/product_mobile_card_screen.dart'; import '../screen/mobile_card/product_mobile_card_screen.dart';
import '../screen/notification/notification_detail_screen.dart';
import '../screen/notification/notification_screen.dart'; import '../screen/notification/notification_screen.dart';
import '../screen/onboarding/onboarding_screen.dart'; import '../screen/onboarding/onboarding_screen.dart';
import '../screen/order_menu/order_menu_screen.dart'; import '../screen/order_menu/order_menu_screen.dart';
...@@ -56,6 +58,7 @@ const onboardingScreen = '/onboarding'; ...@@ -56,6 +58,7 @@ const onboardingScreen = '/onboarding';
const loginScreen = '/login'; const loginScreen = '/login';
const mainScreen = '/main'; const mainScreen = '/main';
const settingScreen = '/setting'; const settingScreen = '/setting';
const flashSaleScreen = '/flashSale';
const vouchersScreen = '/vouchers'; const vouchersScreen = '/vouchers';
const voucherDetailScreen = '/voucherDetail'; const voucherDetailScreen = '/voucherDetail';
const gameCardScreen = '/gameCardScreen'; const gameCardScreen = '/gameCardScreen';
...@@ -103,6 +106,7 @@ const historyPointScreen = '/historyPointScreen'; ...@@ -103,6 +106,7 @@ const historyPointScreen = '/historyPointScreen';
const qrCodeScreen = '/qrCodeScreen'; const qrCodeScreen = '/qrCodeScreen';
const myMobileCardDetailScreen = '/myMobileCardDetailScreen'; const myMobileCardDetailScreen = '/myMobileCardDetailScreen';
const healthBookCardDetail = '/healthBookCardDetail'; const healthBookCardDetail = '/healthBookCardDetail';
const notificationDetailScreen = '/notificationDetailScreen';
class RouterPage { class RouterPage {
static List<GetPage> pages() { static List<GetPage> pages() {
...@@ -125,6 +129,7 @@ class RouterPage { ...@@ -125,6 +129,7 @@ class RouterPage {
), ),
GetPage(name: settingScreen, page: () => SettingScreen()), GetPage(name: settingScreen, page: () => SettingScreen()),
GetPage(name: vouchersScreen, page: () => VoucherListScreen()), GetPage(name: vouchersScreen, page: () => VoucherListScreen()),
GetPage(name: flashSaleScreen, page: () => const FlashSaleScreen()),
GetPage(name: voucherDetailScreen, page: () => VoucherDetailScreen()), GetPage(name: voucherDetailScreen, page: () => VoucherDetailScreen()),
GetPage(name: gameCardScreen, page: () => GameCardScreen()), GetPage(name: gameCardScreen, page: () => GameCardScreen()),
GetPage(name: registerFormInputScreen, page: () => RegisterFormInputScreen()), GetPage(name: registerFormInputScreen, page: () => RegisterFormInputScreen()),
...@@ -171,6 +176,7 @@ class RouterPage { ...@@ -171,6 +176,7 @@ class RouterPage {
GetPage(name: myMobileCardDetailScreen, page: () => MyMobileCardDetailScreen()), GetPage(name: myMobileCardDetailScreen, page: () => MyMobileCardDetailScreen()),
GetPage(name: healthBookScreen, page: () => HealthBookScreen()), GetPage(name: healthBookScreen, page: () => HealthBookScreen()),
GetPage(name: healthBookCardDetail, page: () => HealthBookCardDetail()), GetPage(name: healthBookCardDetail, page: () => HealthBookCardDetail()),
GetPage(name: notificationDetailScreen, page: () => NotificationDetailScreen()),
]; ];
} }
} }
\ No newline at end of file
...@@ -25,7 +25,7 @@ class CustomPointText extends StatelessWidget { ...@@ -25,7 +25,7 @@ class CustomPointText extends StatelessWidget {
Text( Text(
isFree ? 'Miễn phí' : point.money(currencyUnit), isFree ? 'Miễn phí' : point.money(currencyUnit),
style: TextStyle( style: TextStyle(
fontSize: 12, fontSize: 14,
color: Colors.black, color: Colors.black,
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
), ),
......
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