Compare commits
2 Commits
| Author | SHA1 | Date |
|---|---|---|
|
|
9d7372ea4a | 3 weeks ago |
|
|
c0497201b6 | 3 weeks ago |
@ -0,0 +1,232 @@
|
|||||||
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_svg/flutter_svg.dart';
|
||||||
|
import 'package:mohem_flutter_app/app_state/app_state.dart';
|
||||||
|
import 'package:mohem_flutter_app/classes/colors.dart';
|
||||||
|
import 'package:mohem_flutter_app/classes/consts.dart';
|
||||||
|
import 'package:mohem_flutter_app/classes/utils.dart';
|
||||||
|
import 'package:mohem_flutter_app/config/routes.dart';
|
||||||
|
import 'package:mohem_flutter_app/extensions/int_extensions.dart';
|
||||||
|
import 'package:mohem_flutter_app/extensions/string_extensions.dart';
|
||||||
|
import 'package:mohem_flutter_app/extensions/widget_extensions.dart';
|
||||||
|
import 'package:mohem_flutter_app/generated/locale_keys.g.dart';
|
||||||
|
import 'package:mohem_flutter_app/models/offers_and_discounts/get_offers_list.dart';
|
||||||
|
import 'package:mohem_flutter_app/widgets/button/default_button.dart';
|
||||||
|
import 'package:mohem_flutter_app/widgets/dynamic_forms/dynamic_textfield_widget.dart';
|
||||||
|
|
||||||
|
class DashboardScreenForDependet extends StatefulWidget {
|
||||||
|
const DashboardScreenForDependet({Key? key}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<DashboardScreenForDependet> createState() => _DashboardScreenForDependetState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _DashboardScreenForDependetState extends State<DashboardScreenForDependet> {
|
||||||
|
List<OffersListModel> offersList = [];
|
||||||
|
List<OffersListModel> _filteredOffersList = [];
|
||||||
|
bool isLoading = false;
|
||||||
|
String searchQuery = "";
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
fetchOffers();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Offers API placeholder - will be connected when the endpoint is provided
|
||||||
|
Future<void> fetchOffers() async {
|
||||||
|
setState(() {
|
||||||
|
isLoading = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
try {
|
||||||
|
// TODO: Call Dependent Offers API here once provided
|
||||||
|
// Example:
|
||||||
|
// offersList = await OffersApiClient().getDependentOffers();
|
||||||
|
await Future.delayed(const Duration(milliseconds: 300));
|
||||||
|
_filteredOffersList = offersList;
|
||||||
|
} catch (e) {
|
||||||
|
print("Error fetching dependent offers: $e");
|
||||||
|
} finally {
|
||||||
|
if (mounted) {
|
||||||
|
setState(() {
|
||||||
|
isLoading = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _runFilter(String query) {
|
||||||
|
searchQuery = query;
|
||||||
|
if (query.isEmpty) {
|
||||||
|
_filteredOffersList = offersList;
|
||||||
|
} else {
|
||||||
|
bool isAr = AppState().isArabic(context);
|
||||||
|
_filteredOffersList =
|
||||||
|
offersList.where((offer) {
|
||||||
|
String title = isAr ? (offer.titleAr ?? "") : (offer.titleEn ?? "");
|
||||||
|
return title.toLowerCase().contains(query.toLowerCase());
|
||||||
|
}).toList();
|
||||||
|
}
|
||||||
|
setState(() {});
|
||||||
|
}
|
||||||
|
|
||||||
|
void _performLogout() {
|
||||||
|
Utils.confirmDialog(
|
||||||
|
context,
|
||||||
|
AppState().isArabic(context) ? "هل أنت متأكد من تسجيل الخروج؟" : "Are you sure you want to log out?",
|
||||||
|
onTap: () {
|
||||||
|
ApiConsts.selectedMemberType = MemberType.employee;
|
||||||
|
ApiConsts.ISDependetLogin = false;
|
||||||
|
Navigator.pushNamedAndRemoveUntil(context, AppRoutes.login, (Route<dynamic> route) => false);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
bool isAr = AppState().isArabic(context);
|
||||||
|
|
||||||
|
return Scaffold(
|
||||||
|
backgroundColor: MyColors.backgroundColor,
|
||||||
|
appBar: AppBar(
|
||||||
|
backgroundColor: Colors.white,
|
||||||
|
elevation: 0,
|
||||||
|
surfaceTintColor: Colors.transparent,
|
||||||
|
automaticallyImplyLeading: false,
|
||||||
|
title: Row(children: [(isAr ? "عروض التابعين" : "Offers & Discounts").toText20(color: MyColors.darkTextColor, isBold: true)]),
|
||||||
|
actions: [
|
||||||
|
// Logout button
|
||||||
|
Container(
|
||||||
|
margin: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
|
||||||
|
decoration: BoxDecoration(color: MyColors.redColor.withOpacity(0.08), borderRadius: BorderRadius.circular(8)),
|
||||||
|
child: InkWell(
|
||||||
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
onTap: _performLogout,
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6),
|
||||||
|
child: Row(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [const Icon(Icons.logout_rounded, size: 18, color: MyColors.redColor), 6.width, (isAr ? "خروج" : "Logout").toText13(color: MyColors.redColor)],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
body: RefreshIndicator(
|
||||||
|
onRefresh: fetchOffers,
|
||||||
|
color: MyColors.textMixColor,
|
||||||
|
child: SingleChildScrollView(
|
||||||
|
physics: const AlwaysScrollableScrollPhysics(parent: BouncingScrollPhysics()),
|
||||||
|
padding: const EdgeInsets.all(21),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
// Search input
|
||||||
|
DynamicTextFieldWidget(
|
||||||
|
LocaleKeys.search.tr(),
|
||||||
|
LocaleKeys.searchItems.tr(),
|
||||||
|
isEnable: true,
|
||||||
|
suffixIconData: Icons.search,
|
||||||
|
isPopup: false,
|
||||||
|
lines: 1,
|
||||||
|
isInputTypeNum: false,
|
||||||
|
isReadOnly: false,
|
||||||
|
onChange: (String value) {
|
||||||
|
_runFilter(value);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
20.height,
|
||||||
|
|
||||||
|
// Header
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
(isAr ? "العروض المتاحة" : "Available Offers").toText18(isBold: true, color: MyColors.darkTextColor),
|
||||||
|
if (offersList.isNotEmpty) "${_filteredOffersList.length} ${isAr ? "عرض" : "offers"}".toText12(color: MyColors.grey70Color),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
16.height,
|
||||||
|
|
||||||
|
// Content Area
|
||||||
|
if (isLoading)
|
||||||
|
const Center(child: Padding(padding: EdgeInsets.symmetric(vertical: 60), child: CircularProgressIndicator(color: MyColors.textMixColor)))
|
||||||
|
else if (_filteredOffersList.isEmpty)
|
||||||
|
_buildEmptyOffersWidget(isAr)
|
||||||
|
else
|
||||||
|
GridView.builder(
|
||||||
|
shrinkWrap: true,
|
||||||
|
physics: const NeverScrollableScrollPhysics(),
|
||||||
|
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 2, childAspectRatio: 162 / 266, crossAxisSpacing: 12, mainAxisSpacing: 12),
|
||||||
|
itemCount: _filteredOffersList.length,
|
||||||
|
itemBuilder: (context, index) {
|
||||||
|
return _buildOfferCard(_filteredOffersList[index], isAr);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildEmptyOffersWidget(bool isAr) {
|
||||||
|
return Center(
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(vertical: 60, horizontal: 24),
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
width: 80,
|
||||||
|
height: 80,
|
||||||
|
decoration: BoxDecoration(color: MyColors.textMixColor.withOpacity(0.1), shape: BoxShape.circle),
|
||||||
|
child: const Icon(Icons.local_offer_outlined, size: 40, color: MyColors.textMixColor),
|
||||||
|
),
|
||||||
|
16.height,
|
||||||
|
(isAr ? "لا توجد عروض متاحة حالياً" : "No Offers Available Currently").toText16(isBold: true, color: MyColors.darkTextColor),
|
||||||
|
8.height,
|
||||||
|
(isAr ? "سيتم إتاحة العروض الخاصة بك قريباً" : "Exclusive offers for dependents will be available soon.").toText13(color: MyColors.grey70Color),
|
||||||
|
24.height,
|
||||||
|
DefaultButton(isAr ? "تحديث" : "Refresh", fetchOffers, colors: const [MyColors.gradiantStartColor, MyColors.gradiantEndColor]),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildOfferCard(OffersListModel item, bool isAr) {
|
||||||
|
return Container(
|
||||||
|
padding: const EdgeInsets.all(10.0),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.white,
|
||||||
|
borderRadius: BorderRadius.circular(10),
|
||||||
|
boxShadow: [BoxShadow(color: const Color(0xff000000).withOpacity(.05), blurRadius: 26, offset: const Offset(0, -3))],
|
||||||
|
),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
AspectRatio(
|
||||||
|
aspectRatio: 118 / 127,
|
||||||
|
child: ClipRRect(
|
||||||
|
borderRadius: BorderRadius.circular(6),
|
||||||
|
child:
|
||||||
|
(item.bannerImage != null && item.bannerImage!.isNotEmpty)
|
||||||
|
? Image.network(
|
||||||
|
item.bannerImage!,
|
||||||
|
fit: BoxFit.contain,
|
||||||
|
errorBuilder: (_, __, ___) => Container(color: MyColors.greyF7Color, child: const Icon(Icons.broken_image, color: MyColors.grey70Color)),
|
||||||
|
)
|
||||||
|
: Container(color: MyColors.greyF7Color, child: const Icon(Icons.image_outlined, color: MyColors.grey70Color)),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
8.height,
|
||||||
|
(isAr ? (item.titleAr ?? "") : (item.titleEn ?? "")).toText16(isBold: true, color: MyColors.darkTextColor, maxlines: 1),
|
||||||
|
if (item.discountDescription != null && item.discountDescription!.isNotEmpty) ...[4.height, item.discountDescription!.toText14(isBold: true, maxlines: 1)],
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue