diff --git a/lib/data/core/router/registry/paths.dart b/lib/data/core/router/registry/paths.dart index 9061e227..07573dd2 100644 --- a/lib/data/core/router/registry/paths.dart +++ b/lib/data/core/router/registry/paths.dart @@ -15,4 +15,5 @@ class AppPathsRegistry { static const String coupon = 'coupon'; static const String weekMenu = 'weekMenu'; static const String leavesAndRebate = 'leavesAndRebate'; + static const String feedback = 'feedback'; } diff --git a/lib/data/core/router/registry/routes.dart b/lib/data/core/router/registry/routes.dart index bd607b08..c9d949fc 100644 --- a/lib/data/core/router/registry/routes.dart +++ b/lib/data/core/router/registry/routes.dart @@ -51,6 +51,10 @@ class AppRoutesRegistry { path: AppPathsRegistry.notification, page: NotificationRoute.page, ), + CustomRoute( + path: AppPathsRegistry.feedback, + page: FeedbackRoute.page, + ), ], ), ]; diff --git a/lib/domain/models/menu/week_menu_tmp.dart b/lib/domain/models/menu/week_menu_tmp.dart index 9680fc9d..5bbb548d 100644 --- a/lib/domain/models/menu/week_menu_tmp.dart +++ b/lib/domain/models/menu/week_menu_tmp.dart @@ -223,7 +223,7 @@ class Meal { hostelName: json['hostel_name'], secretCode: json['secret_code'], isOutdated: - !DateTimeUtils.getDateTimeFromDateAndTime(date, json['start_time']) + !DateTimeUtils.getDateTimeFromDateAndTime(date, json['end_time']) .isAfter(DateTime.now()), isLeaveToggleOutdated: !DateTimeUtils.getDateTimeFromDateAndTime(date, json['start_time']) diff --git a/lib/presentation/coupons/components/coupon_card.dart b/lib/presentation/coupons/components/coupon_card.dart index 869488af..3dfb00f7 100644 --- a/lib/presentation/coupons/components/coupon_card.dart +++ b/lib/presentation/coupons/components/coupon_card.dart @@ -1,6 +1,7 @@ import 'package:appetizer/app_theme.dart'; import 'package:appetizer/data/core/theme/dimensional/dimensional.dart'; import 'package:appetizer/domain/models/coupon/coupon.dart'; +import 'package:appetizer/utils/date_time_utils.dart'; import 'package:flutter/material.dart'; import 'package:flutter_svg/flutter_svg.dart'; @@ -25,7 +26,7 @@ class CouponCard extends StatelessWidget { child: SvgPicture.asset('assets/images/coupon.svg'), ), Container( - width: 101.toAutoScaledWidth, + width: 110.toAutoScaledWidth, padding: EdgeInsets.only( top: 12.toAutoScaledHeight, left: 8.toAutoScaledWidth, @@ -67,7 +68,7 @@ class CouponCard extends StatelessWidget { ), 6.toVerticalSizedBox, Text( - coupon.mealType, + "${coupon.mealType}, ${DateTimeUtils.getFormattedDate(coupon.mealDate)}", style: TextStyle( color: const Color(0xFF2E2E2E), fontSize: 10.toAutoScaledFont, diff --git a/lib/presentation/coupons/coupons_view.dart b/lib/presentation/coupons/coupons_view.dart index ee02a748..e59a601a 100644 --- a/lib/presentation/coupons/coupons_view.dart +++ b/lib/presentation/coupons/coupons_view.dart @@ -1,6 +1,7 @@ import 'package:appetizer/data/core/theme/dimensional/dimensional.dart'; import 'package:appetizer/domain/models/coupon/coupon.dart'; import 'package:appetizer/domain/repositories/coupon_repository.dart'; +import 'package:appetizer/presentation/components/loading_indicator.dart'; import 'package:appetizer/presentation/components/no_data_found_container.dart'; import 'package:appetizer/presentation/coupons/bloc/coupons_page_bloc.dart'; import 'package:appetizer/presentation/coupons/components/coupon_banner.dart'; @@ -27,8 +28,8 @@ class CouponsScreen extends StatelessWidget { child: BlocBuilder( builder: (context, state) { if (state is CouponsPageInitialState) { - return const NoDataFoundContainer( - title: 'Cannot find the user !'); + return const Expanded( + child: Center(child: LoadingIndicator())); } if (state is CouponsPageFailedState) { // TODO: add logic to handle fail @@ -61,7 +62,7 @@ class CouponsScreen extends StatelessWidget { ); } return const NoDataFoundContainer( - title: 'No coupons selected !'); + title: 'No coupons selected!'); }, ), ), diff --git a/lib/presentation/feedback/components/feedback_banner.dart b/lib/presentation/feedback/components/feedback_banner.dart index 97ff5c94..a2ee48cb 100644 --- a/lib/presentation/feedback/components/feedback_banner.dart +++ b/lib/presentation/feedback/components/feedback_banner.dart @@ -1,6 +1,7 @@ import 'package:appetizer/app_theme.dart'; import 'package:appetizer/data/core/theme/dimensional/dimensional.dart'; import 'package:appetizer/presentation/components/app_banner.dart'; +import 'package:auto_route/auto_route.dart'; import 'package:flutter/material.dart'; class FeedbackBanner extends StatelessWidget { @@ -9,18 +10,11 @@ class FeedbackBanner extends StatelessWidget { @override Widget build(BuildContext context) { return AppBanner( - height: 120.toAutoScaledHeight, + height: 140.toAutoScaledHeight, child: Row( children: [ IconButton( - onPressed: () { - // TODO: navigate to menu page - // BaseApp.router.navigateToPage( - // YourWeekMenuRoute( - // weekMenu: const WeekMenu(), - // ), - // ); - }, + onPressed: context.router.pop, icon: const Icon( Icons.arrow_back, color: Colors.white, diff --git a/lib/presentation/feedback/feedback_view.dart b/lib/presentation/feedback/feedback_view.dart index 020388ce..3998aec8 100644 --- a/lib/presentation/feedback/feedback_view.dart +++ b/lib/presentation/feedback/feedback_view.dart @@ -1,14 +1,17 @@ +import 'package:appetizer/app_theme.dart'; import 'package:appetizer/data/core/theme/dimensional/dimensional.dart'; import 'package:appetizer/domain/repositories/feedback_repository.dart'; import 'package:appetizer/presentation/components/black_button.dart'; import 'package:appetizer/presentation/feedback/bloc/feedback_page_bloc.dart'; import 'package:appetizer/presentation/feedback/components/FeedbackTile/feedback_tile.dart'; import 'package:appetizer/presentation/feedback/components/feedback_banner.dart'; +import 'package:auto_route/auto_route.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; -class FeedbackPage extends StatelessWidget { - FeedbackPage({super.key}); +@RoutePage() +class FeedbackScreen extends StatelessWidget { + FeedbackScreen({super.key}); final TextEditingController textController = TextEditingController(); static const List feedbackHeadings = [ "Ambience", @@ -21,31 +24,23 @@ class FeedbackPage extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( + backgroundColor: AppTheme.white, body: BlocProvider( create: (context) => FeedbackPageBloc(repo: context.read()), child: BlocBuilder( builder: (context, state) { - if (!state.submitted) { - // TODO: navigate to menu page - // BaseApp.router.navigateToPage( - // YourWeekMenuRoute( - // weekMenu: const WeekMenu(), - // ), - // ); - } return Column( children: [ const FeedbackBanner(), // TODO: fix the top edge of SCSV where top elements get hidden Expanded( child: SingleChildScrollView( - padding: const EdgeInsets.only(left: 24, right: 26), + padding: 24.toHorizontalPadding, child: Column( mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: [ - 9.toVerticalSizedBox, Text( 'Kindly provide us with your feedback to improve your mess experienWeekly Menuce.', style: TextStyle( @@ -66,7 +61,7 @@ class FeedbackPage extends StatelessWidget { index: ind, ), ); - }), + }, growable: false), 2.toVerticalSizedBox, Text( 'If any other feeback, please describe below', @@ -107,10 +102,11 @@ class FeedbackPage extends StatelessWidget { Align( alignment: Alignment.bottomRight, child: BlackIconButton( - onTap: () => context.read().add( - FeedbackPageSubmitEvent( - rating: state.rating, - description: state.description)), + onTap: context.router.pop, + // onTap: () => context.read().add( + // FeedbackPageSubmitEvent( + // rating: state.rating, + // description: state.description)), title: "SUBMIT", width: 102, icon: Icons.keyboard_double_arrow_right_sharp, diff --git a/lib/presentation/notifications/components/notification_card.dart b/lib/presentation/notifications/components/notification_card.dart index d2b3c373..8d51c079 100644 --- a/lib/presentation/notifications/components/notification_card.dart +++ b/lib/presentation/notifications/components/notification_card.dart @@ -1,4 +1,5 @@ import 'package:appetizer/data/core/theme/dimensional/dimensional.dart'; +import 'package:appetizer/utils/date_time_utils.dart'; import 'package:flutter/material.dart'; import 'package:appetizer/domain/models/user/notification.dart' as notification; @@ -12,6 +13,7 @@ class NotificationCard extends StatelessWidget { @override Widget build(BuildContext context) { + String date = DateTimeUtils.dateTimeWithoutSeconds(data.dateCreated); return Container( height: 127.toAutoScaledHeight, width: 312.toAutoScaledWidth, @@ -56,7 +58,7 @@ class NotificationCard extends StatelessWidget { ), Expanded( child: Text( - '${data.dateCreated}', + date, style: TextStyle( color: const Color(0xFF2E2E2E), fontSize: 10.toAutoScaledFont, diff --git a/lib/presentation/notifications/notification_view.dart b/lib/presentation/notifications/notification_view.dart index d49bed8f..ea2fcfb6 100644 --- a/lib/presentation/notifications/notification_view.dart +++ b/lib/presentation/notifications/notification_view.dart @@ -59,10 +59,11 @@ class NotificationScreen extends StatelessWidget { Container( height: 656.toAutoScaledHeight, padding: EdgeInsets.only( - left: 24.toAutoScaledWidth, - right: 25.toAutoScaledWidth, - top: 32.toAutoScaledHeight), + left: 24.toAutoScaledWidth, + right: 25.toAutoScaledWidth, + ), child: ListView.builder( + padding: EdgeInsets.zero, itemCount: state.notifications.length, itemBuilder: (context, index) { return Column( diff --git a/lib/presentation/profile/profile_view.dart b/lib/presentation/profile/profile_view.dart index ebf6a2ad..7f620ca5 100644 --- a/lib/presentation/profile/profile_view.dart +++ b/lib/presentation/profile/profile_view.dart @@ -22,135 +22,137 @@ class ProfileScreen extends StatelessWidget { @override Widget build(BuildContext context) { - return BlocBuilder( - builder: (context, state) { - if (state is ProfilePageFetchedState) { - return SingleChildScrollView( - child: Column( - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - const ProfileBanner(), - Transform.translate( - offset: const Offset(0, -60), - child: Column( - children: [ - ProfilePhoto( - imageUri: state.user.imageUrl ?? '', - ), - 10.toVerticalSizedBox, - Text( - state.user.name, - style: GoogleFonts.notoSans( - color: const Color(0xFF111111), - fontSize: 25.toAutoScaledFont, - fontWeight: FontWeight.w600, - ), - ), - Container( - padding: EdgeInsets.only( - left: 33.toAutoScaledWidth, - right: 34.toAutoScaledWidth, - top: 22.toAutoScaledHeight, - ), - child: ProfileCard(data: state.user), - ), - Container( - padding: EdgeInsets.only( - top: 24.toAutoScaledHeight, - bottom: 24.toAutoScaledHeight), - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - ProfileTextButton( - title: 'Edit Profile', - onPressed: () { - const snackBar = SnackBar( - content: Text('Coming soon!'), - duration: Duration(milliseconds: 500), - ); - ScaffoldMessenger.of(context) - .showSnackBar(snackBar); - }, + return SingleChildScrollView( + child: Column( + children: [ + const ProfileBanner(), + BlocBuilder( + builder: (context, state) { + if (state is ProfilePageFetchedState) { + return Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Transform.translate( + offset: const Offset(0, -60), + child: Column( + children: [ + ProfilePhoto( + imageUri: state.user.imageUrl ?? '', + ), + 10.toVerticalSizedBox, + Text( + state.user.name, + style: GoogleFonts.notoSans( + color: const Color(0xFF111111), + fontSize: 25.toAutoScaledFont, + fontWeight: FontWeight.w600, ), - 10.toHorizontalSizedBox, - ProfileTextButton( - title: 'Reset Password', - onPressed: () { - const snackBar = SnackBar( - content: Text('Coming soon!'), - duration: Duration(milliseconds: 500), - ); - ScaffoldMessenger.of(context) - .showSnackBar(snackBar); - }, + ), + Container( + padding: EdgeInsets.only( + left: 33.toAutoScaledWidth, + right: 34.toAutoScaledWidth, + top: 22.toAutoScaledHeight, ), - ], - ), - ), - Divider( - height: 2.toAutoScaledHeight, - thickness: 2, - color: const Color.fromARGB(255, 189, 189, 189), - indent: 30.toAutoScaledWidth, - endIndent: 30.toAutoScaledWidth, - ), - Container( - padding: EdgeInsets.only(top: 24.toAutoScaledHeight), - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - // TODO: add bookmark button - // ProfileIconButton( - // title: 'Bookmark', - // onPressed: () {}, - // icon: Icons.bookmark_border_outlined, - // ), - // 48.toHorizontalSizedBox, - ProfileIconButton( - title: 'Coupons', - onPressed: () => - context.router.push(const CouponsRoute()), - icon: Icons.bookmark_border_outlined, + child: ProfileCard(data: state.user), + ), + Container( + padding: EdgeInsets.only( + top: 24.toAutoScaledHeight, + bottom: 24.toAutoScaledHeight), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + ProfileTextButton( + title: 'Edit Profile', + onPressed: () { + const snackBar = SnackBar( + content: Text('Coming soon!'), + duration: Duration(milliseconds: 500), + ); + ScaffoldMessenger.of(context) + .showSnackBar(snackBar); + }, + ), + 10.toHorizontalSizedBox, + ProfileTextButton( + title: 'Reset Password', + onPressed: () { + const snackBar = SnackBar( + content: Text('Coming soon!'), + duration: Duration(milliseconds: 500), + ); + ScaffoldMessenger.of(context) + .showSnackBar(snackBar); + }, + ), + ], ), - ], - ), - ), - SizedBox(height: 40.toAutoScaledHeight), - BlackButton( - title: 'LOGOUT', - onTap: () { - LocalStorageService.setValue( - key: AppConstants.LOGGED_IN, value: false); - LocalStorageService.setValue( - key: AppConstants.AUTH_TOKEN, value: null); - context - .read() - .add(const NavigateToLoginScreen()); - }, - width: 101, + ), + Divider( + height: 2.toAutoScaledHeight, + thickness: 2, + color: const Color.fromARGB(255, 189, 189, 189), + indent: 30.toAutoScaledWidth, + endIndent: 30.toAutoScaledWidth, + ), + Container( + padding: + EdgeInsets.only(top: 24.toAutoScaledHeight), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + // TODO: add bookmark button + // ProfileIconButton( + // title: 'Bookmark', + // onPressed: () {}, + // icon: Icons.bookmark_border_outlined, + // ), + // 48.toHorizontalSizedBox, + ProfileIconButton( + title: 'Coupons', + onPressed: () => + context.router.push(const CouponsRoute()), + icon: Icons.bookmark_border_outlined, + ), + ], + ), + ), + SizedBox(height: 40.toAutoScaledHeight), + BlackButton( + title: 'LOGOUT', + onTap: () { + LocalStorageService.setValue( + key: AppConstants.LOGGED_IN, value: false); + LocalStorageService.setValue( + key: AppConstants.AUTH_TOKEN, value: null); + context + .read() + .add(const NavigateToLoginScreen()); + }, + width: 101, + ), + SizedBox(height: 18.toAutoScaledHeight), + const RaiseQueryButton(), + ], ), - SizedBox(height: 18.toAutoScaledHeight), - const RaiseQueryButton(), - ], - ), - ), - ], - ), - ); - } + ), + ], + ); + } - return const Scaffold( - body: Column( - children: [ - ProfileBanner(), - Center( - child: LoadingIndicator(), - ), - ], + return SizedBox( + height: 200.toAutoScaledHeight, + child: const Align( + alignment: Alignment.bottomCenter, + child: LoadingIndicator(), + ), + ); + }, ), - ); - }, + ], + ), ); } } diff --git a/lib/presentation/week_menu/components/DayMenu/menu_card.dart b/lib/presentation/week_menu/components/DayMenu/menu_card.dart index cef8dc72..a7fa904b 100644 --- a/lib/presentation/week_menu/components/DayMenu/menu_card.dart +++ b/lib/presentation/week_menu/components/DayMenu/menu_card.dart @@ -1,4 +1,5 @@ import 'package:appetizer/app_theme.dart'; +import 'package:appetizer/data/core/router/intrinsic_router/intrinsic_router.gr.dart'; import 'package:appetizer/data/core/theme/dimensional/dimensional.dart'; import 'package:appetizer/domain/models/menu/week_menu_tmp.dart'; import 'package:appetizer/presentation/app/bloc/app_bloc.dart'; @@ -40,26 +41,38 @@ class FeedbackAndCouponWidget extends StatelessWidget { color: AppTheme.white, shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(6)), ), - child: Row( - mainAxisAlignment: (coupon && taken) - ? MainAxisAlignment.spaceBetween - : MainAxisAlignment.center, - children: [ - // if (coupon && taken) ...[ - // SvgPicture.asset('assets/icons/coupon_taken_tick.svg') - // ], - Text( - coupon ? "COUPON ${taken ? 'TAKEN' : ''}" : "Give Feedback", - textAlign: TextAlign.center, - style: AppTheme.button.copyWith( - height: 1.toAutoScaledHeight, - fontSize: 11.toAutoScaledFont, - fontWeight: FontWeight.w600, - color: AppTheme.black11, - ), - ) - ], + child: Center( + child: Text( + coupon ? "COUPON ${taken ? 'TAKEN' : ''}" : "Give Feedback", + textAlign: TextAlign.center, + style: AppTheme.button.copyWith( + height: 1.toAutoScaledHeight, + fontSize: 11.toAutoScaledFont, + fontWeight: FontWeight.w600, + color: AppTheme.black11, + ), + ), ), + // child: Row( + // mainAxisAlignment: (coupon && taken) + // ? MainAxisAlignment.spaceBetween + // : MainAxisAlignment.center, + // children: [ + // if (coupon && taken) ...[ + // SvgPicture.asset('assets/icons/coupon_taken_tick.svg') + // ], + // Text( + // coupon ? "COUPON" : "Give Feedback", + // textAlign: TextAlign.center, + // style: AppTheme.button.copyWith( + // height: 1.toAutoScaledHeight, + // fontSize: 11.toAutoScaledFont, + // fontWeight: FontWeight.w600, + // color: AppTheme.black11, + // ), + // ), + // ], + // ), ), ); } @@ -69,7 +82,7 @@ void showCouponDialog(String text, BuildContext context) { showDialog( context: context, builder: (BuildContext context) { - return Expanded(child: CouponDialogBox(text: text)); + return CouponDialogBox(text: text); }, ); } @@ -80,39 +93,33 @@ class CouponDialogBox extends StatelessWidget { @override Widget build(BuildContext context) { - return AlertDialog( - content: Container( - width: 310.toAutoScaledWidth, - height: 83.toAutoScaledHeight, - decoration: ShapeDecoration( - color: Colors.amber, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(10.toAutoScaledWidth), - ), - ), - child: Stack( - children: [ - Padding( - padding: EdgeInsets.symmetric(horizontal: 60.toAutoScaledWidth), - child: Center( - child: Text( - text, - style: AppTheme.headline3.copyWith( - fontSize: 17.toAutoScaledFont, - fontWeight: FontWeight.w400, - ), - ), + return Dialog( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(10.toAutoScaledWidth), + ), + backgroundColor: const Color(0xFFFFCB74), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Align( + alignment: Alignment.topRight, + child: GestureDetector( + onTap: context.router.pop, + child: const Padding( + padding: EdgeInsets.all(2.0), + child: Icon(Icons.close), ), ), - Positioned( - right: 0, - child: GestureDetector( - onTap: context.router.pop, - child: const Icon(Icons.close), - ), - ) - ], - ), + ), + Text( + text, + style: AppTheme.headline3.copyWith( + fontSize: 17.toAutoScaledFont, + fontWeight: FontWeight.w600, + ), + ), + 20.toVerticalSizedBox, + ], ), ); } @@ -220,7 +227,7 @@ class MealCard extends StatelessWidget { meal.isOutdated ? GestureDetector( onTap: () { - //TODO: lead to feedback page + context.router.navigate(FeedbackRoute()); }, child: const FeedbackAndCouponWidget( taken: false, coupon: false), @@ -248,6 +255,14 @@ class MealCard extends StatelessWidget { "Coupon no: ${meal.couponStatus.id!}", context, ); + } else { + const snackBar = SnackBar( + content: Text( + "Time's up, coupon applications closed", + ), + ); + ScaffoldMessenger.of(context) + .showSnackBar(snackBar); } }, child: FeedbackAndCouponWidget( diff --git a/lib/utils/date_time_utils.dart b/lib/utils/date_time_utils.dart index a62c1d19..8eae7c8e 100644 --- a/lib/utils/date_time_utils.dart +++ b/lib/utils/date_time_utils.dart @@ -29,11 +29,20 @@ class DateTimeUtils { .format(DateTime.fromMillisecondsSinceEpoch(timeStamp)); } + static String dateTimeWithoutSeconds(int timeStamp) { + return DateFormat('yyyy-MM-dd') + .format(DateTime.fromMillisecondsSinceEpoch(timeStamp)); + } + static DateTime getWeekStartDate(DateTime dateTime) { return dateTime .subtract(Duration(days: dateTime.weekday - DateTime.monday)); } + static String getFormattedDate(String yMd) { + return DateFormat("d MMM''yy").format(DateTime.parse(yMd)); + } + static bool compareDate(DateTime date1, DateTime date2) { return date1.year == date2.year && date1.month == date2.month &&