Commit 6b980613 authored by DatHV's avatar DatHV
Browse files

update project structure

parent bfff9e47
import 'dart:core';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:mypoint_flutter_app/extensions/num_extension.dart';
import '../../base/base_screen.dart';
import '../../base/basic_state.dart';
import '../../resources/base_color.dart';
import '../../widgets/custom_navigation_bar.dart';
import '../../widgets/image_loader.dart';
import 'package:mypoint_flutter_app/core/utils/extensions/num_extension.dart';
import '../../shared/widgets/base_view/base_screen.dart';
import '../../shared/widgets/base_view/basic_state.dart';
import '../../core/theme/base_color.dart';
import '../../shared/widgets/custom_navigation_bar.dart';
import '../../shared/widgets/image_loader.dart';
import '../voucher/models/product_model.dart';
import 'model/payment_bank_account_info_model.dart';
import 'model/payment_method_model.dart';
......@@ -163,10 +163,10 @@ class _TransactionDetailScreenState extends BaseState<TransactionDetailScreen> w
children: [
Center(child: Image.asset('assets/images/ic_point.png', width: 30, height: 30)),
const SizedBox(width: 12),
Text(pointData!.textDisplay ?? '', style: const TextStyle(fontSize: 16, fontWeight: FontWeight.w500)),
Text(pointData.textDisplay ?? '', style: const TextStyle(fontSize: 16, fontWeight: FontWeight.w500)),
],
),
if (pointData!.isEnableUsePoint)
if (pointData.isEnableUsePoint)
Switch(
activeColor: Colors.white,
activeTrackColor: Colors.green,
......@@ -177,7 +177,7 @@ class _TransactionDetailScreenState extends BaseState<TransactionDetailScreen> w
setState(() {
_viewModel.usePoints.value = value;
final total = _viewModel.previewData.value?.totalPrice ?? 0;
final point = pointData!.point ?? 0;
final point = pointData.point ?? 0;
shouldDisablePaymentMethods = value && (total - point <= 0);
if (!value && _viewModel.selectedPaymentMethodIndex < 0) {
if (_viewModel.paymentBankAccounts.value.isNotEmpty) {
......@@ -401,7 +401,7 @@ class _TransactionDetailScreenState extends BaseState<TransactionDetailScreen> w
method.logo!,
width: 24,
height: 24,
errorBuilder: (_, __, ___) => const Icon(Icons.payment),
errorBuilder: (_, _, _) => const Icon(Icons.payment),
),
),
Text(method.name ?? '', style: const TextStyle(fontSize: 16)),
......
import 'package:flutter/cupertino.dart';
import 'package:get/get.dart';
import 'package:mypoint_flutter_app/networking/api/product_api.dart' deferred as product_api;
import 'package:mypoint_flutter_app/core/network/api/product_api.dart' deferred as product_api;
import 'package:mypoint_flutter_app/shared/router_gage.dart';
import 'package:uuid/uuid.dart';
import '../../base/base_response_model.dart';
import '../../networking/restful_api_viewmodel.dart';
import '../../configs/constants.dart';
import '../../preference/contact_storage_service.dart';
import '../../preference/data_preference.dart';
import '../../shared/widgets/base_view/base_response_model.dart';
import '../../core/network/restful_api_viewmodel.dart';
import '../../app/config/constants.dart';
import '../../core/services/contact_storage_service.dart';
import '../../shared/preferences/data_preference.dart';
import '../voucher/models/product_model.dart';
import '../webview/payment_web_view_screen.dart';
import 'model/payment_bank_account_info_model.dart';
......@@ -19,7 +19,6 @@ class TransactionDetailViewModel extends RestfulApiViewModel {
var previewData = Rxn<PreviewOrderPaymentModel>();
var paymentMethods = RxList<PaymentMethodModel>();
var paymentBankAccounts = RxList<PaymentBankAccountInfoModel>();
final RxBool isLoading = false.obs;
final ProductModel product;
String? metaData;
final int quantity;
......
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:month_picker_dialog/month_picker_dialog.dart';
import 'package:mypoint_flutter_app/extensions/datetime_extensions.dart';
import 'package:mypoint_flutter_app/screen/transaction/transactions_history_viewmodel.dart';
import 'package:mypoint_flutter_app/widgets/custom_empty_widget.dart';
import 'package:mypoint_flutter_app/widgets/image_loader.dart';
import '../../resources/base_color.dart';
import 'package:mypoint_flutter_app/core/utils/extensions/datetime_extensions.dart';
import 'package:mypoint_flutter_app/features/transaction/transactions_history_viewmodel.dart';
import 'package:mypoint_flutter_app/shared/widgets/custom_empty_widget.dart';
import 'package:mypoint_flutter_app/shared/widgets/image_loader.dart';
import '../../core/theme/base_color.dart';
import '../../shared/router_gage.dart';
import '../../widgets/custom_navigation_bar.dart';
import '../../shared/widgets/custom_navigation_bar.dart';
import 'history/transaction_history_model.dart';
import 'history/transaction_history_response_model.dart';
......@@ -33,7 +33,12 @@ class _TransactionHistoryScreenState extends State<TransactionHistoryScreen> {
_buildCategoryTabs(),
_buildSummaryBox(summary),
const SizedBox(height: 8),
if (items.isEmpty) Expanded(child: Center(child: EmptyWidget(size: Size(160, 160)))),
if (items.isEmpty)
Expanded(
child: Center(
child: EmptyWidget(isLoading: _viewModel.isLoading.value),
),
),
Expanded(
child: ListView.builder(
physics: const AlwaysScrollableScrollPhysics(),
......@@ -64,7 +69,7 @@ class _TransactionHistoryScreenState extends State<TransactionHistoryScreen> {
scrollDirection: Axis.horizontal,
padding: const EdgeInsets.symmetric(horizontal: 16),
itemCount: _viewModel.categories.value.length,
separatorBuilder: (_, __) => const SizedBox(width: 8),
separatorBuilder: (_, _) => const SizedBox(width: 8),
itemBuilder: (context, index) {
final category = _viewModel.categories.value[index];
final isSelected = category.code == _viewModel.categorySelected?.code;
......
import 'package:get/get_rx/src/rx_types/rx_types.dart';
import 'package:mypoint_flutter_app/extensions/datetime_extensions.dart';
import 'package:mypoint_flutter_app/networking/restful_api_client_all_request.dart';
import '../../networking/restful_api_viewmodel.dart';
import 'package:mypoint_flutter_app/core/utils/extensions/datetime_extensions.dart';
import 'package:mypoint_flutter_app/core/network/restful_api_client_all_request.dart';
import '../../core/network/restful_api_viewmodel.dart';
import 'history/transaction_category_model.dart';
import 'history/transaction_history_response_model.dart';
......@@ -11,7 +11,6 @@ class TransactionsHistoryViewModel extends RestfulApiViewModel {
void Function(String message)? onShowAlertError;
TransactionCategoryModel? categorySelected;
DateTime date = DateTime.now();
bool _isLoading = false;
@override
onInit() {
......@@ -20,39 +19,36 @@ class TransactionsHistoryViewModel extends RestfulApiViewModel {
}
Future<void> _getCategories() async {
showLoading();
try {
final response = await client.getTransactionHistoryCategories();
categories.value = response.data ?? [];
await callApi<List<TransactionCategoryModel>>(
request: () => client.getTransactionHistoryCategories(),
onSuccess: (data, _) {
categories.value = data;
categorySelected = categories.isNotEmpty ? categories.first : null;
hideLoading();
},
onFailure: (message, _, _) {
onShowAlertError?.call(message);
},
onComplete: () {
getTransactionHistoryResponse();
} catch (error) {
hideLoading();
onShowAlertError?.call("Error fetching product detail: $error");
}
},
);
}
Future<void> getTransactionHistoryResponse() async {
if (_isLoading) return;
final body = {
'category_code': categorySelected?.code ?? '',
'date': date.toFormattedString(format: 'yyyy-MM'),
'limit': 10000,
'offset':0,
};
_isLoading = true;
showLoading();
try {
final response = await client.getTransactionHistoryResponse(body);
final data = response.data;
await callApi<TransactionHistoryResponse>(
request: () => client.getTransactionHistoryResponse(body),
onSuccess: (data, _) {
historyResponse.value = data;
_isLoading = false;
hideLoading();
} catch (error) {
_isLoading = false;
hideLoading();
onShowAlertError?.call("Error fetching product detail: $error");
}
},
onFailure: (message, _, _) {
onShowAlertError?.call(message);
},
);
}
}
import 'package:flutter/material.dart';
import 'package:get/get_state_manager/src/rx_flutter/rx_obx_widget.dart';
import 'package:mypoint_flutter_app/shared/direction_google_map.dart';
import '../models/product_store_model.dart';
class StoreListSection extends StatefulWidget {
......@@ -64,7 +63,7 @@ class _StoreListSectionState extends State<StoreListSection> {
});
}
_onTapStore(ProductStoreModel store) {
void _onTapStore(ProductStoreModel store) {
showGoogleMap(lat: store.latitude, lng: store.longitude);
}
......@@ -82,7 +81,7 @@ class _StoreListSectionState extends State<StoreListSection> {
width: 20,
height: 20,
fit: BoxFit.cover,
errorBuilder: (_, __, ___) => Image.asset('assets/images/ic_logo.png', width: 20, height: 20),
errorBuilder: (_, _, _) => Image.asset('assets/images/ic_logo.png', width: 20, height: 20),
),
),
const SizedBox(width: 8),
......
import 'dart:math';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_widget_from_html_core/flutter_widget_from_html_core.dart';
import 'package:mypoint_flutter_app/extensions/num_extension.dart';
import 'package:mypoint_flutter_app/extensions/string_extension.dart';
import 'package:mypoint_flutter_app/screen/voucher/detail/store_list_section.dart';
import 'package:mypoint_flutter_app/screen/voucher/models/product_type.dart';
import 'package:mypoint_flutter_app/screen/voucher/voucher_code_card_screen.dart';
import 'package:mypoint_flutter_app/core/utils/extensions/num_extension.dart';
import 'package:mypoint_flutter_app/core/utils/extensions/string_extension.dart';
import 'package:mypoint_flutter_app/features/voucher/detail/store_list_section.dart';
import 'package:mypoint_flutter_app/features/voucher/models/product_type.dart';
import 'package:mypoint_flutter_app/features/voucher/voucher_code_card_screen.dart';
import 'package:url_launcher/url_launcher.dart';
import '../../../base/base_screen.dart';
import '../../../base/basic_state.dart';
import '../../../preference/point/point_manager.dart';
import '../../../resources/base_color.dart';
import '../../../shared/widgets/base_view/base_screen.dart';
import '../../../shared/widgets/base_view/basic_state.dart';
import '../../../shared/preferences/point/point_manager.dart';
import '../../../core/theme/base_color.dart';
import '../../../shared/router_gage.dart';
import '../../../widgets/alert/data_alert_model.dart';
import '../../../widgets/back_button.dart';
import '../../../widgets/custom_empty_widget.dart';
import '../../../widgets/custom_point_text_tag.dart';
import '../../../widgets/dashed_line.dart';
import '../../../widgets/image_loader.dart';
import '../../../widgets/measure_size.dart';
import '../../../shared/widgets/alert/data_alert_model.dart';
import '../../../shared/widgets/back_button.dart';
import '../../../shared/widgets/custom_empty_widget.dart';
import '../../../shared/widgets/custom_point_text_tag.dart';
import '../../../shared/widgets/dashed_line.dart';
import '../../../shared/widgets/image_loader.dart';
import '../../../shared/widgets/measure_size.dart';
import '../models/cash_type.dart';
import '../models/my_product_status_type.dart';
import '../models/product_model.dart';
......@@ -71,14 +70,11 @@ class _VoucherDetailScreenState extends BaseState<VoucherDetailScreen> with Basi
return Scaffold(
backgroundColor: Colors.grey.shade100,
body: Obx(() {
if (_viewModel.isLoading.value) {
return const Center(child: CircularProgressIndicator());
}
final product = _viewModel.product.value;
if (product == null) {
return Stack(
children: [
const Center(child: EmptyWidget()),
Center(child: EmptyWidget(isLoading: _viewModel.isLoading.value)),
SafeArea(child: Padding(padding: const EdgeInsets.all(8), child: CustomBackButton())),
],
);
......@@ -259,7 +255,7 @@ class _VoucherDetailScreenState extends BaseState<VoucherDetailScreen> with Basi
}
Widget _buildExpireAndStock(ProductModel product) {
final bool isOutOfStock = !(product.inStock ?? true);
final bool isOutOfStock = !(product.inStock);
final bool hasExpire = product.expire.isNotEmpty;
return Row(
mainAxisAlignment: MainAxisAlignment.center,
......@@ -381,7 +377,7 @@ class _VoucherDetailScreenState extends BaseState<VoucherDetailScreen> with Basi
}
Widget _buildBottomAction(ProductModel product) {
final bool isOutOfStock = !(product.inStock ?? true);
final bool isOutOfStock = !(product.inStock);
if (product.isMyProduct && product.customerInfoModel?.status != MyProductStatusType.waiting) {
return const SizedBox.shrink();
}
......
import 'package:flutter/cupertino.dart';
import 'package:get/get.dart';
import 'package:mypoint_flutter_app/networking/api/product_api.dart' deferred as product_api;
import 'package:mypoint_flutter_app/core/utils/extensions/string_extension.dart';
import 'package:mypoint_flutter_app/core/network/api/product_api.dart' deferred as product_api;
import 'package:uuid/uuid.dart';
import '../../../base/base_response_model.dart';
import '../../../networking/restful_api_viewmodel.dart';
import '../../../configs/constants.dart';
import '../../../shared/widgets/base_view/base_response_model.dart';
import '../../../core/network/restful_api_viewmodel.dart';
import '../../../app/config/constants.dart';
import '../../../shared/router_gage.dart';
import '../../transaction/model/order_product_payment_response_model.dart';
import '../models/product_model.dart';
import '../models/product_store_model.dart';
......@@ -19,7 +20,6 @@ class VoucherDetailViewModel extends RestfulApiViewModel {
var stores = RxList<ProductStoreModel>();
var product = Rxn<ProductModel>();
var isLoading = false.obs;
var liked = false.obs;
void Function(String message)? onShowAlertError;
var quantity = 1.obs;
......@@ -51,13 +51,13 @@ class VoucherDetailViewModel extends RestfulApiViewModel {
final value = product.value;
if (value == null) return;
try {
if (value!.liked == true) {
await _callProductApi((api) => api.unlikeProduct(value?.likeId ?? 0));
value?.likeId = 0;
if (value.liked == true) {
await _callProductApi((api) => api.unlikeProduct(value.likeId ?? 0));
value.likeId = 0;
liked.value = false;
} else {
final response = await _callProductApi((api) => api.likeProduct(_id!));
value?.likeId = response.data?.id;
value.likeId = response.data?.id;
liked.value = (response.data?.id ?? 0) != 0;
}
} catch (error) {
......@@ -66,35 +66,33 @@ class VoucherDetailViewModel extends RestfulApiViewModel {
}
Future<void> _getProductDetail() async {
if (isLoading.value) return;
try {
isLoading.value = true;
final response =
isMyProduct
? await _callProductApi((api) => api.getCustomerProductDetail(customerProductId ?? 0))
: await _callProductApi((api) => api.getProduct(productId ?? 0));
product.value = response.data;
await callApi<ProductModel>(
request: () =>
isMyProduct ?
_callProductApi((api) => api.getCustomerProductDetail(customerProductId ?? 0)) :
_callProductApi((api) => api.getProduct(productId ?? 0)),
onSuccess: (data, _) {
product.value = data;
liked.value = product.value?.liked == true;
} catch (error) {
onShowAlertError?.call("Error fetching product detail: $error");
} finally {
isLoading.value = false;
if (isMyProduct) {
_getProductStores();
}
}
},
onFailure: (message, _, _) {
onShowAlertError?.call(message);
},
);
}
Future<void> _getProductStores() async {
if (_id == null) return;
try {
final response = await _callProductApi((api) => api.getProductStores(_id!));
stores.value = response.data ?? [];
stores.refresh();
} catch (error) {
onShowAlertError?.call("Error product stores: $error");
debugPrint("Error product stores: $error");
} finally {}
await callApi<List<ProductStoreModel>>(
request: () => _callProductApi((api) => api.getProductStores(_id!)),
onSuccess: (data, _) {
stores.value = data;
},
onFailure: (message, _, _) {
onShowAlertError?.call(message);
},
withLoading: false,
);
}
Future<void> verifyOrderProduct(Function verified) async {
......@@ -122,29 +120,32 @@ class VoucherDetailViewModel extends RestfulApiViewModel {
}
Future<void> redeemProduct() async {
showLoading();
final requestId = Uuid().v4();
try {
final response = await _callProductApi(
(api) => api.orderSubmitPayment(
await callApi<OrderProductPaymentResponseModel>(
request: () =>
_callProductApi(
(api) =>
api.orderSubmitPayment(
products: [product.value!],
quantity: 1,
requestId: requestId,
point: product.value?.amountToBePaid ?? 0,
),
);
if (response.isSuccess && (response.data?.id ?? "").isNotEmpty) {
),
onSuccess: (data, _) {
final id = data.id.orEmpty;
if (id.isNotEmpty) {
Get.offNamed(
transactionHistoryDetailScreen,
arguments: {"orderId": response.data?.id ?? "", "canBack": false},
arguments: {"orderId": id, "canBack": false},
);
} else {
onShowAlertError?.call(response.errorMessage ?? Constants.commonError);
}
} catch (error) {
onShowAlertError?.call(Constants.commonError);
} finally {
hideLoading();
}
},
onFailure: (message, _, _) {
onShowAlertError?.call(message);
},
);
}
}
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:url_launcher/url_launcher.dart';
import '../../../widgets/custom_toast_message.dart';
import '../../../shared/widgets/custom_toast_message.dart';
class RechargeSheet extends StatelessWidget {
final String code;
......
import 'package:flutter/services.dart';
import 'package:get/get.dart';
import 'package:get/get_core/src/get_main.dart';
import 'package:get/get_rx/src/rx_types/rx_types.dart';
import 'package:mypoint_flutter_app/extensions/num_extension.dart';
import 'package:mypoint_flutter_app/networking/api/product_api.dart' deferred as product_api;
import '../../../configs/constants.dart';
import '../../../networking/restful_api_viewmodel.dart';
import 'package:mypoint_flutter_app/core/utils/extensions/num_extension.dart';
import 'package:mypoint_flutter_app/core/network/api/product_api.dart' deferred as product_api;
import '../../../app/config/constants.dart';
import '../../../core/network/restful_api_viewmodel.dart';
import '../../mobile_card/models/usable_voucher_model.dart';
import '../../../base/base_response_model.dart';
import '../../../shared/widgets/base_view/base_response_model.dart';
class MyMobileCardDetailViewModel extends RestfulApiViewModel {
String itemId;
......
......@@ -2,11 +2,11 @@ import 'package:auto_size_text/auto_size_text.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:get/get.dart';
import 'package:mypoint_flutter_app/widgets/custom_toast_message.dart';
import 'package:mypoint_flutter_app/widgets/image_loader.dart';
import '../../../resources/base_color.dart';
import '../../../widgets/bottom_sheet_helper.dart';
import '../../../widgets/custom_navigation_bar.dart';
import 'package:mypoint_flutter_app/shared/widgets/custom_toast_message.dart';
import 'package:mypoint_flutter_app/shared/widgets/image_loader.dart';
import '../../../core/theme/base_color.dart';
import '../../../shared/widgets/bottom_sheet_helper.dart';
import '../../../shared/widgets/custom_navigation_bar.dart';
import 'card_recharge_sheet.dart';
import 'my_mobile_card_detail_viewmodel.dart';
......
import 'package:get/get_rx/src/rx_types/rx_types.dart';
import 'package:mypoint_flutter_app/configs/constants.dart';
import 'package:mypoint_flutter_app/networking/api/product_api.dart' deferred as product_api;
import '../../../networking/restful_api_viewmodel.dart';
import 'package:mypoint_flutter_app/app/config/constants.dart';
import 'package:mypoint_flutter_app/core/network/api/product_api.dart' deferred as product_api;
import '../../../core/network/restful_api_viewmodel.dart';
import '../../mobile_card/models/usable_voucher_model.dart';
import '../models/my_product_status_type.dart';
import '../../../base/base_response_model.dart';
import '../../../shared/widgets/base_view/base_response_model.dart';
class MyMobileCardListViewModel extends RestfulApiViewModel {
final RxInt selectedTabIndex = 0.obs;
......@@ -37,6 +37,7 @@ class MyMobileCardListViewModel extends RestfulApiViewModel {
}
Future<void> freshData({bool isRefresh = false}) async {
isLoading.value = true;
if (isRefresh) {
showLoading();
}
......@@ -64,6 +65,7 @@ class MyMobileCardListViewModel extends RestfulApiViewModel {
if (isRefresh) {
hideLoading();
}
isLoading.value = false;
}
}
......
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import '../../../base/base_screen.dart';
import '../../../base/basic_state.dart';
import '../../../shared/widgets/base_view/base_screen.dart';
import '../../../shared/widgets/base_view/basic_state.dart';
import '../../../shared/router_gage.dart';
import '../../../widgets/custom_empty_widget.dart';
import '../../../widgets/custom_navigation_bar.dart';
import '../../../widgets/image_loader.dart';
import '../../../shared/widgets/custom_empty_widget.dart';
import '../../../shared/widgets/custom_navigation_bar.dart';
import '../../../shared/widgets/image_loader.dart';
import '../../mobile_card/models/usable_voucher_model.dart';
import '../../mobile_card/usable_mobile_card_popup.dart';
import 'my_mobile_card_list_viewmodel.dart';
......@@ -36,7 +36,6 @@ class _MyMobileCardListScreenState extends BaseState<MyMobileCardListScreen> wit
@override
Widget createBody() {
final screenWidth = MediaQuery.of(context).size.width;
return Scaffold(
appBar: CustomNavigationBar(title: 'Thẻ nạp của tôi',),
body: Obx(
......@@ -52,7 +51,9 @@ class _MyMobileCardListScreenState extends BaseState<MyMobileCardListScreen> wit
),
const Divider(height: 1),
if (_viewModel.myCardModels.isEmpty)
Expanded(child: EmptyWidget(size: Size(screenWidth / 2, screenWidth / 2)))
Expanded(
child: EmptyWidget(isLoading: _viewModel.isLoading.value),
)
else
Expanded(
child: RefreshIndicator(
......
import '../../mobile_card/models/product_mobile_card_model.dart';
import '../../mobile_card/models/usable_voucher_model.dart';
class MyVoucherResponse {
......
import 'package:flutter/foundation.dart';
import 'package:mypoint_flutter_app/extensions/datetime_extensions.dart';
import 'package:mypoint_flutter_app/extensions/string_extension.dart';
import '../../voucher/models/my_product_status_type.dart';
import 'package:mypoint_flutter_app/core/utils/extensions/datetime_extensions.dart';
import 'package:mypoint_flutter_app/core/utils/extensions/string_extension.dart';
import 'my_product_status_type.dart';
class MyProductModel {
final int? id;
......
import 'package:json_annotation/json_annotation.dart';
part 'product_brand_model.g.dart';
@JsonSerializable()
class ProductBrandModel {
final int? id;
......
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