diff --git a/lib/features/booking_system/presentation/blocs/past_bookings_bloc/past_bookings_bloc.dart b/lib/features/booking_system/presentation/blocs/past_bookings_bloc/past_bookings_bloc.dart new file mode 100644 index 0000000..f6bcbf7 --- /dev/null +++ b/lib/features/booking_system/presentation/blocs/past_bookings_bloc/past_bookings_bloc.dart @@ -0,0 +1,32 @@ +import 'package:bloc/bloc.dart'; +import 'package:equatable/equatable.dart'; + +import '../../../domain/booking_model.dart'; +import '../../../domain/booking_service.dart'; + +part 'past_bookings_event.dart'; +part 'past_bookings_state.dart'; + +class PastBookingsBloc extends Bloc { + final BookingService _bookingService; + + PastBookingsBloc(this._bookingService) : super(PastBookingsInitial()) { + on(_onGetPastBookingsEvent); + } + _onGetPastBookingsEvent( + GetPastBookingsEvent event, + Emitter emit, + ) async { + emit(PastBookingLoadingState()); + try { + final pastBookings = await _bookingService.get(); + emit( + PastBookingLoadedState(pastBookings: pastBookings), + ); + } catch (e) { + emit( + PastBookingErrorState(e.toString()), + ); + } + } +} diff --git a/lib/features/booking_system/presentation/blocs/past_bookings_bloc/past_bookings_event.dart b/lib/features/booking_system/presentation/blocs/past_bookings_bloc/past_bookings_event.dart new file mode 100644 index 0000000..70b831d --- /dev/null +++ b/lib/features/booking_system/presentation/blocs/past_bookings_bloc/past_bookings_event.dart @@ -0,0 +1,10 @@ +part of 'past_bookings_bloc.dart'; + +sealed class PastBookingsEvent extends Equatable { + const PastBookingsEvent(); + + @override + List get props => []; +} + +class GetPastBookingsEvent extends PastBookingsEvent {} diff --git a/lib/features/booking_system/presentation/blocs/past_bookings_bloc/past_bookings_state.dart b/lib/features/booking_system/presentation/blocs/past_bookings_bloc/past_bookings_state.dart new file mode 100644 index 0000000..9604025 --- /dev/null +++ b/lib/features/booking_system/presentation/blocs/past_bookings_bloc/past_bookings_state.dart @@ -0,0 +1,24 @@ +part of 'past_bookings_bloc.dart'; + +sealed class PastBookingsState extends Equatable { + const PastBookingsState(); + + @override + List get props => []; +} + +final class PastBookingsInitial extends PastBookingsState {} + +final class PastBookingLoadingState extends PastBookingsState {} + +final class PastBookingLoadedState extends PastBookingsState { + final List pastBookings; + const PastBookingLoadedState({ + required this.pastBookings, + }); +} + +final class PastBookingErrorState extends PastBookingsState { + final String errorMsg; + const PastBookingErrorState(this.errorMsg); +} diff --git a/lib/features/booking_system/presentation/blocs/upcoming_bookings_bloc/upcoming_bookings_bloc.dart b/lib/features/booking_system/presentation/blocs/upcoming_bookings_bloc/upcoming_bookings_bloc.dart new file mode 100644 index 0000000..b2fcbb0 --- /dev/null +++ b/lib/features/booking_system/presentation/blocs/upcoming_bookings_bloc/upcoming_bookings_bloc.dart @@ -0,0 +1,32 @@ +import 'package:equatable/equatable.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:syncrow_app/features/booking_system/domain/booking_model.dart'; +import 'package:syncrow_app/features/booking_system/domain/booking_service.dart'; + +part 'upcoming_bookings_event.dart'; +part 'upcoming_bookings_state.dart'; + +class UpcomingBookingsBloc + extends Bloc { + final BookingService _bookingService; + UpcomingBookingsBloc(this._bookingService) + : super(UpcomingBookingsInitial()) { + on(_onGetUpcomingBookingsEvent); + } + _onGetUpcomingBookingsEvent( + GetUpcomingBookingsEvent event, + Emitter emit, + ) async { + emit(UpcomingBookingLoadingState()); + try { + final upcomingBookings = await _bookingService.get(); + emit( + UpcomingBookingLoadedState(upcomingBookings: upcomingBookings), + ); + } catch (e) { + emit( + UpcomingBookingErrorState(e.toString()), + ); + } + } +} diff --git a/lib/features/booking_system/presentation/blocs/upcoming_bookings_bloc/upcoming_bookings_event.dart b/lib/features/booking_system/presentation/blocs/upcoming_bookings_bloc/upcoming_bookings_event.dart new file mode 100644 index 0000000..5365cdc --- /dev/null +++ b/lib/features/booking_system/presentation/blocs/upcoming_bookings_bloc/upcoming_bookings_event.dart @@ -0,0 +1,10 @@ +part of 'upcoming_bookings_bloc.dart'; + +sealed class UpcomingBookingsEvent extends Equatable { + const UpcomingBookingsEvent(); + + @override + List get props => []; +} + +class GetUpcomingBookingsEvent extends UpcomingBookingsEvent {} diff --git a/lib/features/booking_system/presentation/blocs/upcoming_bookings_bloc/upcoming_bookings_state.dart b/lib/features/booking_system/presentation/blocs/upcoming_bookings_bloc/upcoming_bookings_state.dart new file mode 100644 index 0000000..3f2a09b --- /dev/null +++ b/lib/features/booking_system/presentation/blocs/upcoming_bookings_bloc/upcoming_bookings_state.dart @@ -0,0 +1,24 @@ +part of 'upcoming_bookings_bloc.dart'; + +sealed class UpcomingBookingsState extends Equatable { + const UpcomingBookingsState(); + + @override + List get props => []; +} + +final class UpcomingBookingsInitial extends UpcomingBookingsState {} + +final class UpcomingBookingLoadingState extends UpcomingBookingsState {} + +final class UpcomingBookingLoadedState extends UpcomingBookingsState { + final List upcomingBookings; + const UpcomingBookingLoadedState({ + required this.upcomingBookings, + }); +} + +final class UpcomingBookingErrorState extends UpcomingBookingsState { + final String errorMsg; + const UpcomingBookingErrorState(this.errorMsg); +} diff --git a/lib/features/booking_system/presentation/screens/booking_system_page.dart b/lib/features/booking_system/presentation/screens/booking_system_page.dart index e15733c..71f4065 100644 --- a/lib/features/booking_system/presentation/screens/booking_system_page.dart +++ b/lib/features/booking_system/presentation/screens/booking_system_page.dart @@ -1,57 +1,71 @@ import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:syncrow_app/features/app_layout/bloc/home_cubit.dart'; +import 'package:syncrow_app/features/booking_system/data/booking_dummy_source.dart'; +import 'package:syncrow_app/features/booking_system/presentation/blocs/upcoming_bookings_bloc/upcoming_bookings_bloc.dart'; +import 'package:syncrow_app/features/shared_widgets/default_button.dart'; import 'package:syncrow_app/features/shared_widgets/default_scaffold.dart'; import 'package:syncrow_app/utils/helpers/app_size.dart'; import 'package:syncrow_app/utils/resource_manager/color_manager.dart'; +import '../blocs/past_bookings_bloc/past_bookings_bloc.dart'; import '../widgets/booking_appbar_widget.dart'; import '../widgets/current_balance_widget.dart'; +import '../widgets/past_booking_widget.dart'; +import '../widgets/upcoming_bookings_widget.dart'; class BookingSystemPage extends StatelessWidget { const BookingSystemPage({super.key}); @override Widget build(BuildContext context) { - return DefaultScaffold( - appBar: BookingAppBar(), - child: Padding( - padding: EdgeInsets.symmetric(horizontal: 10), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - SizedBox( - height: 20, - ), - Expanded( - child: CurrentBalanceWidget( - userBalance: HomeCubit.user!.points == null - ? '0' - : HomeCubit.user!.points.toString(), - ), - ), - SizedBox( - height: 10, - ), - Expanded( - child: UpcomingBookingsWidget(), - ), - SizedBox( - height: 10, - ), - Expanded(child: Container() - // PastBookingsWidget(), + return MultiBlocProvider( + providers: [ + BlocProvider( + create: (_) => UpcomingBookingsBloc(BookingDummySource()) + ..add(GetUpcomingBookingsEvent()), + ), + BlocProvider( + create: (_) => PastBookingsBloc(BookingDummySource()) + ..add(GetPastBookingsEvent()), + ) + ], + child: DefaultScaffold( + appBar: BookingAppBar(), + child: Padding( + padding: EdgeInsets.symmetric(horizontal: 10), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SizedBox( + height: 20, ), - ], - ), - ), - ); + Expanded( + flex: 2, + child: CurrentBalanceWidget( + userBalance: HomeCubit.user!.points == null + ? '0' + : HomeCubit.user!.points.toString(), + ), + ), + SizedBox( + height: 20, + ), + Expanded( + flex: 8, + child: Column( + children: [ + UpcomingBookingsWidget(), + SizedBox( + height: 10, + ), + PastBookingsWidget(), + ], + ), + ) + ], + ), + ), + )); } } -class UpcomingBookingsWidget extends StatelessWidget { - const UpcomingBookingsWidget({super.key}); - - @override - Widget build(BuildContext context) { - return const Placeholder(); - } -} \ No newline at end of file diff --git a/lib/features/booking_system/presentation/widgets/booking_card_widget.dart b/lib/features/booking_system/presentation/widgets/booking_card_widget.dart new file mode 100644 index 0000000..897f545 --- /dev/null +++ b/lib/features/booking_system/presentation/widgets/booking_card_widget.dart @@ -0,0 +1,105 @@ +import 'package:flutter/material.dart'; + +import '../../../../utils/resource_manager/color_manager.dart'; +import '../../domain/booking_model.dart'; + +class BookingCardWidget extends StatelessWidget { + const BookingCardWidget({ + super.key, + required this.bookingModel, + }); + + final BookingModel bookingModel; + + @override + Widget build(BuildContext context) { + return Container( + padding: EdgeInsets.all(15), + decoration: BoxDecoration( + borderRadius: BorderRadius.all(Radius.circular(20)), + color: ColorsManager.onPrimaryColor, + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + bookingModel.roomName, + style: TextStyle( + color: ColorsManager.blackColor, + fontSize: 17, + fontWeight: FontWeight.bold, + ), + ), + SizedBox( + height: 15, + ), + Text( + 'Booking Date', + style: TextStyle( + color: ColorsManager.grayColor, + fontSize: 15, + ), + ), + Text( + bookingModel.date, + style: TextStyle( + color: ColorsManager.blackColor, + fontSize: 15, + fontWeight: FontWeight.w500, + ), + ), + SizedBox( + height: 15, + ), + Row( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'Time slot', + style: TextStyle( + color: ColorsManager.grayColor, + fontSize: 15, + ), + ), + Text( + bookingModel.timeSlot, + style: TextStyle( + color: ColorsManager.blackColor, + fontSize: 15, + fontWeight: FontWeight.w500, + ), + ), + ], + ), + SizedBox( + width: 80, + ), + Column( + children: [ + Text( + 'cost', + style: TextStyle( + color: ColorsManager.grayColor, + fontSize: 15, + ), + ), + Text( + bookingModel.cost.toString(), + style: TextStyle( + color: ColorsManager.blackColor, + fontSize: 15, + fontWeight: FontWeight.w500, + ), + ), + ], + ), + ], + ) + ], + ), + ); + } +} diff --git a/lib/features/booking_system/presentation/widgets/current_balance_widget.dart b/lib/features/booking_system/presentation/widgets/current_balance_widget.dart index 6210ae2..24759db 100644 --- a/lib/features/booking_system/presentation/widgets/current_balance_widget.dart +++ b/lib/features/booking_system/presentation/widgets/current_balance_widget.dart @@ -21,7 +21,7 @@ class CurrentBalanceWidget extends StatelessWidget { child: Row( children: [ Expanded( - flex: 7, + flex: 75, child: Padding( padding: EdgeInsets.all(12), child: Column( @@ -31,6 +31,7 @@ class CurrentBalanceWidget extends StatelessWidget { child: Text( 'Current Balance', style: TextStyle( + color: ColorsManager.blackColor, fontWeight: FontWeight.bold, fontSize: 17, ), @@ -40,6 +41,7 @@ class CurrentBalanceWidget extends StatelessWidget { ), Expanded( child: Row( + crossAxisAlignment: CrossAxisAlignment.end, mainAxisAlignment: MainAxisAlignment.start, children: [ Text( @@ -47,7 +49,7 @@ class CurrentBalanceWidget extends StatelessWidget { style: TextStyle( color: ColorsManager.blueColor1, fontWeight: FontWeight.bold, - fontSize: 25), + fontSize: 50), ), SizedBox( width: 5, @@ -65,7 +67,7 @@ class CurrentBalanceWidget extends StatelessWidget { ), )), Expanded( - flex: 3, + flex: 25, child: Container( alignment: Alignment.center, padding: EdgeInsets.only(left: 15), diff --git a/lib/features/booking_system/presentation/widgets/past_booking_widget.dart b/lib/features/booking_system/presentation/widgets/past_booking_widget.dart new file mode 100644 index 0000000..4b8eeae --- /dev/null +++ b/lib/features/booking_system/presentation/widgets/past_booking_widget.dart @@ -0,0 +1,66 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; + +import '../../../../utils/helpers/app_size.dart'; +import '../../../../utils/resource_manager/color_manager.dart'; +import '../../../shared_widgets/default_button.dart'; +import '../blocs/past_bookings_bloc/past_bookings_bloc.dart'; +import 'booking_card_widget.dart'; + +class PastBookingsWidget extends StatelessWidget { + const PastBookingsWidget({super.key}); + + @override + Widget build(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'Past Bookings', + style: TextStyle( + fontSize: 15, + color: ColorsManager.grayColor, + fontWeight: FontWeight.bold, + ), + ), + SizedBox( + height: 10, + ), + BlocBuilder( + builder: (context, state) { + if (state is PastBookingLoadingState) { + //should use CustomLoadingWidget + return CircularProgressIndicator(); + } else if (state is PastBookingErrorState) { +//shold use CustomErrorWidget + return DefaultButton( + onPressed: () => context + .read() + .add(GetPastBookingsEvent()), + child: Text('Try again'), + ); + } else if (state is PastBookingLoadedState) { + return SizedBox( + height: deviceHeight(context) * 0.3, + child: state.pastBookings.isEmpty + ? Text('You Dont Have past Bookings') + : ListView.separated( + separatorBuilder: (context, index) => SizedBox( + height: 10, + ), + itemCount: state.pastBookings.length, + itemBuilder: (context, index) { + final pastBooking = state.pastBookings[index]; + return BookingCardWidget(bookingModel: pastBooking); + }, + ), + ); + } else { + return SizedBox(); + } + }, + ) + ], + ); + } +} diff --git a/lib/features/booking_system/presentation/widgets/upcoming_bookings_widget.dart b/lib/features/booking_system/presentation/widgets/upcoming_bookings_widget.dart new file mode 100644 index 0000000..0d697a6 --- /dev/null +++ b/lib/features/booking_system/presentation/widgets/upcoming_bookings_widget.dart @@ -0,0 +1,66 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import '../../../../utils/helpers/app_size.dart'; +import '../../../../utils/resource_manager/color_manager.dart'; +import '../../../shared_widgets/default_button.dart'; +import '../blocs/upcoming_bookings_bloc/upcoming_bookings_bloc.dart'; +import 'booking_card_widget.dart'; + +class UpcomingBookingsWidget extends StatelessWidget { + const UpcomingBookingsWidget({super.key}); + + @override + Widget build(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'Upcoming Bookings', + style: TextStyle( + fontSize: 15, + color: ColorsManager.grayColor, + fontWeight: FontWeight.bold, + ), + ), + SizedBox( + height: 10, + ), + BlocBuilder( + builder: (context, state) { + if (state is UpcomingBookingLoadingState) { + //should use CustomLoadingWidget + return CircularProgressIndicator(); + } else if (state is UpcomingBookingErrorState) { +//shold use CustomErrorWidget + return DefaultButton( + onPressed: () => context + .read() + .add(GetUpcomingBookingsEvent()), + child: Text('Try again'), + ); + } else if (state is UpcomingBookingLoadedState) { + return SizedBox( + height: deviceHeight(context) * 0.3, + child: state.upcomingBookings.isEmpty + ? Text('You Dont Have Upcoming Bookings') + : ListView.separated( + separatorBuilder: (context, index) => SizedBox( + height: 10, + ), + itemCount: state.upcomingBookings.length, + itemBuilder: (context, index) { + final upcomingBooking = state.upcomingBookings[index]; + return BookingCardWidget( + bookingModel: upcomingBooking); + }, + ), + ); + } else { + return SizedBox(); + } + }, + ) + ], + ); + } +}