You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
mohemm-flutter-app/lib/ui/landing/dashboard_screen_for_depend...

233 lines
9.1 KiB
Dart

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)],
],
),
);
}
}