import 'package:comwell_key_app/.generated/assets/assets.gen.dart';
import 'package:comwell_key_app/common/components/comwell_app_bar.dart';
import 'package:comwell_key_app/common/components/shimmer_loader/booking_details_shimmer_loader.dart';
import 'package:comwell_key_app/overview/models/booking.dart';
import 'package:comwell_key_app/presentation/screens/booking_details/components/booking_details_bottom_sheet.dart';
import 'package:comwell_key_app/presentation/screens/booking_details/components/check_in_button_timer.dart';
import 'package:comwell_key_app/presentation/screens/booking_details/components/get_keys_button.dart';
import 'package:comwell_key_app/presentation/screens/booking_details/components/preregister_button.dart';
import 'package:comwell_key_app/presentation/screens/booking_details/components/room_number_container.dart';
import 'package:comwell_key_app/presentation/screens/booking_details/components/share_button.dart';
import 'package:comwell_key_app/routing/app_routes.dart';
import 'package:comwell_key_app/services/mappers/booking_mapper.dart';
import 'package:comwell_key_app/themes/light_theme.dart';
import 'package:comwell_key_app/up_sales/models/room_upgrade_list.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:go_router/go_router.dart';
import 'bloc/booking_details_cubit.dart';
import 'bloc/booking_details_state.dart';
import 'components/unlock_room_button.dart';
class BookingDetailsPage extends StatelessWidget {
const BookingDetailsPage({super.key});
@override
Widget build(BuildContext context) {
return BlocConsumer<BookingDetailsCubit, BookingDetailsState>(
listener: (context, state) {},
builder: (context, state) {
final cubit = context.read<BookingDetailsCubit>();
return Scaffold(
extendBodyBehindAppBar: true,
backgroundColor: colorBackground,
appBar: const ComwellAppBar(),
body: Builder(
builder: (context) {
if (state.isLoading) {
return const Center(
child: BookingDetailsShimmerLoader(),
);
} else {
return _buildBookingDetailsPage(context, state, cubit);
}
},
),
);
},
);
}
Widget _buildBookingDetailsPage(
BuildContext context,
BookingDetailsState state,
BookingDetailsCubit cubit,
) {
final theme = Theme.of(context);
final screenHeight = MediaQuery.of(context).size.height;
final isPreregistered =
cubit.booking.reservationStatus == ReservationStatus.preregistered ||
cubit.booking.reservationStatus == ReservationStatus.preregistrationfinalized;
final isCheckedIn = cubit.booking.reservationStatus == ReservationStatus.checkedin;
final isPrimaryGuest = cubit.booking.isPrimaryGuest;
final shouldShowShareButton = isPrimaryGuest && isCheckedIn || isPreregistered;
return Stack(
children: [
// Background image - fixed
Container(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage(Assets.images.bookingBackground.path),
fit: BoxFit.cover,
),
),
),
// Gradient overlay - fixed
Container(
decoration: const BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [
Colors.black26,
Colors.black54,
],
),
),
),
// Share button - fixed at top
SafeArea(
child: shouldShowShareButton
? ShareButton(guests: cubit.booking.guests)
: const SizedBox(),
),
// Scrollable content with haptic feedback
_ScrollableBookingContent(
screenHeight: screenHeight,
cubit: cubit,
state: state,
theme: theme,
buildBookingDetailsInformation: () =>
_buildBookingDetailsInformation(context, state, cubit, theme),
),
],
);
}
Widget _buildBookingDetailsInformation(
BuildContext context,
BookingDetailsState state,
BookingDetailsCubit cubit,
ThemeData theme,
) {
return InkWell(
onTap: () async {
await context.push(AppRoutes.myBooking, extra: cubit.booking);
},
child: Container(
width: double.infinity,
height: 50,
decoration: BoxDecoration(
color: Colors.transparent,
borderRadius: BorderRadius.circular(4),
),
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
child: Row(
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
cubit.booking.confirmationNumber,
style: theme.textTheme.labelLarge?.copyWith(color: colorBackground),
),
Text(
cubit.booking.toRoomType(),
style: theme.textTheme.headlineMedium?.copyWith(
color: colorBackground,
),
),
],
),
],
),
],
),
),
const Icon(
Icons.chevron_right,
color: colorBackground,
size: 36,
),
],
),
),
),
);
}
}
class _ScrollableBookingContent extends StatefulWidget {
final double screenHeight;
final BookingDetailsCubit cubit;
final BookingDetailsState state;
final ThemeData theme;
final Widget Function() buildBookingDetailsInformation;
const _ScrollableBookingContent({
required this.screenHeight,
required this.cubit,
required this.state,
required this.theme,
required this.buildBookingDetailsInformation,
});
@override
State<_ScrollableBookingContent> createState() => _ScrollableBookingContentState();
}
class _ScrollableBookingContentState extends State<_ScrollableBookingContent> {
bool _hasTriggeredHaptic = false;
void _onScroll(double offset) {
if (offset > 0 && !_hasTriggeredHaptic) {
HapticFeedback.lightImpact();
_hasTriggeredHaptic = true;
} else if (offset == 0) {
_hasTriggeredHaptic = false;
}
}
@override
Widget build(BuildContext context) {
final keys = widget.state.keys;
final isKeyLoadedForBooking = keys.any((key) => key.label == widget.cubit.booking.roomNumber);
final isKeysEmpty = keys.isEmpty;
final hasRoomNumber = widget.cubit.booking.roomNumber != '';
final isPreregistered =
widget.cubit.booking.reservationStatus == ReservationStatus.preregistered ||
widget.cubit.booking.reservationStatus == ReservationStatus.preregistrationfinalized;
return NotificationListener<ScrollNotification>(
onNotification: (notification) {
_onScroll(notification.metrics.pixels);
return false;
},
child: SingleChildScrollView(
child: Column(
children: [
// Top section with room info - leaves 100px for sheet peek
SizedBox(
height: widget.screenHeight - 100,
child: SafeArea(
bottom: false,
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.end,
children: [
if (widget.cubit.booking.roomNumber != '')
RoomNumberContainer(cubit: widget.cubit),
widget.buildBookingDetailsInformation(),
const Padding(
padding: EdgeInsets.symmetric(horizontal: 16.0),
child: Divider(color: colorDivider),
),
const SizedBox(height: 10),
if (!isKeysEmpty && hasRoomNumber && isKeyLoadedForBooking)
UnlockRoomButton(roomNumber: widget.cubit.booking.roomNumber)
else if (widget.cubit.booking.reservationStatus == ReservationStatus.checkedin)
const GetKeysButton()
else if (isPreregistered)
CheckInButtonTimer(
buyEarlyCheckin: () async {
final earlyCheckin = widget.cubit.state.upSales?.addOnUpgrades
.where((upgrade) => upgrade.id == 'EARCHI')
.firstOrNull;
final roomUpgradeList = RoomUpgradeList(
booking: widget.cubit.booking,
addOnUpgrade: earlyCheckin,
isRoomUpgradeSelected: false,
isSinglePurchase: true,
);
final result = await context.push(
AppRoutes.servicesUpgrade,
extra: roomUpgradeList,
);
if (result == true && context.mounted) {
widget.cubit.init();
}
},
)
else if (widget.cubit.booking.reservationStatus ==
ReservationStatus.newreservation)
const PreregisterButton()
else
const SizedBox(),
const SizedBox(height: 24),
],
),
),
),
// Bottom sheet content (scrollable, styled like a sheet)
BookingDetailsBottomSheet(cubit: widget.cubit, state: widget.state),
],
),
),
);
}
}