2026-01-31 15:23:18 +05:30
// lib/screens/booking_screen.dart
import ' package:flutter/material.dart ' ;
feat: Phase 1 critical gaps — gamification API, Razorpay checkout, Google OAuth, notifications
- Fix gamification endpoints to use Node.js server (app.eventifyplus.com)
- Replace 6 mock gamification methods with real API calls (dashboard, leaderboard, shop, redeem, submit)
- Add booking models, service, payment service (Razorpay), checkout provider
- Add 3-step CheckoutScreen with Razorpay native modal integration
- Add Google OAuth login (Flutter + Django backend)
- Add full notifications system (Django model + 3 endpoints + Flutter UI)
- Register CheckoutProvider, NotificationProvider in main.dart MultiProvider
- Wire notification bell in HomeScreen app bar
- Add razorpay_flutter ^1.3.7 and google_sign_in ^6.2.2 packages
2026-04-04 15:46:53 +05:30
import ' checkout_screen.dart ' ;
2026-01-31 15:23:18 +05:30
class BookingScreen extends StatefulWidget {
final VoidCallback ? onBook ;
final String image ;
feat: Phase 1 critical gaps — gamification API, Razorpay checkout, Google OAuth, notifications
- Fix gamification endpoints to use Node.js server (app.eventifyplus.com)
- Replace 6 mock gamification methods with real API calls (dashboard, leaderboard, shop, redeem, submit)
- Add booking models, service, payment service (Razorpay), checkout provider
- Add 3-step CheckoutScreen with Razorpay native modal integration
- Add Google OAuth login (Flutter + Django backend)
- Add full notifications system (Django model + 3 endpoints + Flutter UI)
- Register CheckoutProvider, NotificationProvider in main.dart MultiProvider
- Wire notification bell in HomeScreen app bar
- Add razorpay_flutter ^1.3.7 and google_sign_in ^6.2.2 packages
2026-04-04 15:46:53 +05:30
final int ? eventId ;
final String ? eventName ;
2026-01-31 15:23:18 +05:30
const BookingScreen ( {
Key ? key ,
this . onBook ,
this . image = ' assets/images/event1.jpg ' ,
feat: Phase 1 critical gaps — gamification API, Razorpay checkout, Google OAuth, notifications
- Fix gamification endpoints to use Node.js server (app.eventifyplus.com)
- Replace 6 mock gamification methods with real API calls (dashboard, leaderboard, shop, redeem, submit)
- Add booking models, service, payment service (Razorpay), checkout provider
- Add 3-step CheckoutScreen with Razorpay native modal integration
- Add Google OAuth login (Flutter + Django backend)
- Add full notifications system (Django model + 3 endpoints + Flutter UI)
- Register CheckoutProvider, NotificationProvider in main.dart MultiProvider
- Wire notification bell in HomeScreen app bar
- Add razorpay_flutter ^1.3.7 and google_sign_in ^6.2.2 packages
2026-04-04 15:46:53 +05:30
this . eventId ,
this . eventName ,
2026-01-31 15:23:18 +05:30
} ) : super ( key: key ) ;
@ override
State < BookingScreen > createState ( ) = > _BookingScreenState ( ) ;
}
class _BookingScreenState extends State < BookingScreen > {
// small gallery placeholder
final List < String > gallery = [
' assets/images/event1.jpg ' ,
' assets/images/event2.jpg ' ,
' assets/images/event3.jpeg ' ,
' assets/images/event1.jpg ' ,
] ;
// long about text
final String aboutText = '''
Some voices don ' t just sing, they awaken something deep within. Sid Sriram is one of those rare artists who doesn ' t just perform music . . . he becomes it .
This concert isn ' t just about a setlist or a stage, it ' s a journey . A moment suspended in time . A powerful collective experience where every note pulls at memory , every silence says what words never could , and every crescendo feels like it was meant just for you .
From the moment the lights go down , you ' re no longer in the real world — you ' re in his world: a place shaped by melody and intimacy , where familiar songs are reborn and new ones carve out space in your memory . Expect an award - calibre voice that melts into orchestration , fragile acoustic passages that make the room hold its breath , and thunderous climaxes that lift everyone to their feet .
Whether you ' re a longtime fan or hearing him live for the first time, this evening promises to linger long after the last chord fades — a night of shared emotion, artistry, and music that stays with you.
''' ;
bool _booked = false ;
void _performLocalBooking ( ) {
feat: Phase 1 critical gaps — gamification API, Razorpay checkout, Google OAuth, notifications
- Fix gamification endpoints to use Node.js server (app.eventifyplus.com)
- Replace 6 mock gamification methods with real API calls (dashboard, leaderboard, shop, redeem, submit)
- Add booking models, service, payment service (Razorpay), checkout provider
- Add 3-step CheckoutScreen with Razorpay native modal integration
- Add Google OAuth login (Flutter + Django backend)
- Add full notifications system (Django model + 3 endpoints + Flutter UI)
- Register CheckoutProvider, NotificationProvider in main.dart MultiProvider
- Wire notification bell in HomeScreen app bar
- Add razorpay_flutter ^1.3.7 and google_sign_in ^6.2.2 packages
2026-04-04 15:46:53 +05:30
// If event data is available, navigate to real checkout
if ( widget . eventId ! = null ) {
Navigator . of ( context ) . push ( MaterialPageRoute (
builder: ( _ ) = > CheckoutScreen (
eventId: widget . eventId ! ,
eventName: widget . eventName ? ? ' Event ' ,
eventImage: widget . image ,
) ,
) ) ;
return ;
}
// Fallback: demo booking for events without IDs
2026-01-31 15:23:18 +05:30
if ( ! _booked ) {
setState ( ( ) = > _booked = true ) ;
ScaffoldMessenger . of ( context ) . showSnackBar (
feat: Phase 1 critical gaps — gamification API, Razorpay checkout, Google OAuth, notifications
- Fix gamification endpoints to use Node.js server (app.eventifyplus.com)
- Replace 6 mock gamification methods with real API calls (dashboard, leaderboard, shop, redeem, submit)
- Add booking models, service, payment service (Razorpay), checkout provider
- Add 3-step CheckoutScreen with Razorpay native modal integration
- Add Google OAuth login (Flutter + Django backend)
- Add full notifications system (Django model + 3 endpoints + Flutter UI)
- Register CheckoutProvider, NotificationProvider in main.dart MultiProvider
- Wire notification bell in HomeScreen app bar
- Add razorpay_flutter ^1.3.7 and google_sign_in ^6.2.2 packages
2026-04-04 15:46:53 +05:30
const SnackBar ( content: Text ( ' Tickets booked (demo) ' ) ) ,
2026-01-31 15:23:18 +05:30
) ;
}
}
void _openLearnMoreSheet ( ) {
showModalBottomSheet (
context: context ,
isScrollControlled: true ,
backgroundColor: Colors . transparent ,
builder: ( ctx ) {
return DraggableScrollableSheet (
expand: false ,
initialChildSize: 0.78 ,
minChildSize: 0.35 ,
maxChildSize: 0.95 ,
builder: ( context , scrollController ) {
return Container (
decoration: BoxDecoration (
color: Colors . white ,
borderRadius: BorderRadius . vertical ( top: Radius . circular ( 24.0 ) ) ,
boxShadow: [ BoxShadow ( color: Colors . black26 , blurRadius: 8 ) ] ,
) ,
child: SingleChildScrollView (
controller: scrollController ,
child: Padding (
padding: const EdgeInsets . fromLTRB ( 20 , 18 , 20 , 24 ) ,
child: Column (
crossAxisAlignment: CrossAxisAlignment . start ,
children: [
// drag handle
Center (
child: Container (
width: 48 ,
height: 6 ,
decoration: BoxDecoration (
color: Colors . grey [ 300 ] ,
borderRadius: BorderRadius . circular ( 6 ) ,
) ,
) ,
) ,
SizedBox ( height: 16 ) ,
Text (
" The Homecoming Tour | Sid Sriram Live in Concert " ,
style: TextStyle ( fontSize: 20 , fontWeight: FontWeight . bold ) ,
) ,
SizedBox ( height: 12 ) ,
Row (
children: [
Icon ( Icons . calendar_today , size: 16 , color: Colors . blue ) ,
SizedBox ( width: 8 ) ,
Text ( " 22 Jan - 24 Jan, 2025 " , style: TextStyle ( color: Colors . black54 ) ) ,
SizedBox ( width: 14 ) ,
Icon ( Icons . access_time , size: 16 , color: Colors . blue ) ,
SizedBox ( width: 8 ) ,
Text ( " 04:00 PM - 11:00 PM " , style: TextStyle ( color: Colors . black54 ) ) ,
] ,
) ,
SizedBox ( height: 14 ) ,
Container (
height: 120 ,
decoration: BoxDecoration (
color: Colors . grey [ 200 ] ,
borderRadius: BorderRadius . circular ( 12 ) ,
) ,
child: Center ( child: Text ( ' Map placeholder — Cultural Hall ' , style: TextStyle ( color: Colors . black45 ) ) ) ,
) ,
SizedBox ( height: 18 ) ,
Text ( ' About the Event ' , style: TextStyle ( fontSize: 16 , fontWeight: FontWeight . bold ) ) ,
SizedBox ( height: 8 ) ,
Text ( aboutText , style: TextStyle ( color: Colors . black54 , height: 1.45 ) ) ,
SizedBox ( height: 18 ) ,
Text ( ' Gallery ' , style: TextStyle ( fontSize: 16 , fontWeight: FontWeight . bold ) ) ,
SizedBox ( height: 12 ) ,
SizedBox (
height: 78 ,
child: ListView . separated (
scrollDirection: Axis . horizontal ,
itemCount: gallery . length ,
separatorBuilder: ( _ , __ ) = > SizedBox ( width: 12 ) ,
itemBuilder: ( context , idx ) {
final path = gallery [ idx ] ;
return ClipRRect (
borderRadius: BorderRadius . circular ( 12 ) ,
child: Container (
width: 78 ,
height: 78 ,
color: Colors . grey [ 200 ] ,
child: Image . asset (
path ,
fit: BoxFit . cover ,
errorBuilder: ( ctx , err , st ) = > Center ( child: Icon ( Icons . image , color: Colors . grey ) ) ,
) ,
) ,
) ;
} ,
) ,
) ,
SizedBox ( height: 22 ) ,
// If already booked, show booked UI inside the sheet too (optional)
if ( _booked ) . . . [
_bookedRow ( ) ,
SizedBox ( height: 12 ) ,
] else . . . [
// Book button inside sheet — now does in-place booking (no navigation)
SizedBox (
width: double . infinity ,
child: ElevatedButton (
style: ElevatedButton . styleFrom (
padding: EdgeInsets . symmetric ( vertical: 16 ) ,
shape: RoundedRectangleBorder ( borderRadius: BorderRadius . circular ( 12 ) ) ,
backgroundColor: Color ( 0xFF0B63D6 ) ,
foregroundColor: Colors . white ,
) ,
onPressed: ( ) {
// mark booked and close the sheet (no removal from home)
_performLocalBooking ( ) ;
Navigator . of ( context ) . pop ( ) ;
} ,
child: Text ( ' Book Your Spot ' , style: TextStyle ( fontSize: 16 , color: Colors . white ) ) ,
) ,
) ,
] ,
SizedBox ( height: 12 ) ,
] ,
) ,
) ,
) ,
) ;
} ,
) ;
} ,
) ;
}
// row shown after booking: left green pill + three action icons on right
Widget _bookedRow ( ) {
final Color primary = Color ( 0xFF0B63D6 ) ;
return Row (
children: [
// Tickets Booked pill (left)
Container (
padding: EdgeInsets . symmetric ( horizontal: 18 , vertical: 12 ) ,
decoration: BoxDecoration (
color: Color ( 0xFFDFF5DF ) , // light green background
borderRadius: BorderRadius . circular ( 12 ) ,
) ,
child: Text ( ' Tickets Booked ' , style: TextStyle ( color: Color ( 0xFF2E7D32 ) , fontWeight: FontWeight . bold ) ) ,
) ,
Spacer ( ) ,
// action icons (scanner / chat / call)
_iconSquare ( primary , Icons . qr_code_scanner , onTap: ( ) {
ScaffoldMessenger . of ( context ) . showSnackBar ( SnackBar ( content: Text ( ' Scanner tapped (demo) ' ) ) ) ;
} ) ,
SizedBox ( width: 12 ) ,
_iconSquare ( primary , Icons . chat , onTap: ( ) {
ScaffoldMessenger . of ( context ) . showSnackBar ( SnackBar ( content: Text ( ' Chat tapped (demo) ' ) ) ) ;
} ) ,
SizedBox ( width: 12 ) ,
_iconSquare ( primary , Icons . call , onTap: ( ) {
ScaffoldMessenger . of ( context ) . showSnackBar ( SnackBar ( content: Text ( ' Call tapped (demo) ' ) ) ) ;
} ) ,
] ,
) ;
}
Widget _iconSquare ( Color bg , IconData icon , { required VoidCallback onTap } ) {
return InkWell (
onTap: onTap ,
borderRadius: BorderRadius . circular ( 12 ) ,
child: Container (
width: 52 ,
height: 52 ,
decoration: BoxDecoration (
color: bg ,
borderRadius: BorderRadius . circular ( 12 ) ,
boxShadow: [ BoxShadow ( color: Colors . black12 , blurRadius: 6 , offset: Offset ( 0 , 4 ) ) ] ,
) ,
child: Icon ( icon , color: Colors . white , size: 24 ) ,
) ,
) ;
}
void _confirmBookingFromMain ( ) {
// book in-place (no navigation and no removal from home)
_performLocalBooking ( ) ;
}
@ override
Widget build ( BuildContext context ) {
// full-bleed image behind status bar
return Scaffold (
extendBodyBehindAppBar: true ,
backgroundColor: Colors . black ,
body: Stack (
children: [
// full background image
Positioned . fill (
child: Image . asset (
widget . image ,
fit: BoxFit . cover ,
errorBuilder: ( ctx , err , st ) = > Container ( color: Colors . grey [ 900 ] ) ,
) ,
) ,
// subtle gradient to make bottom white text readable
Positioned . fill (
child: Container (
decoration: BoxDecoration (
gradient: LinearGradient (
colors: [ Colors . transparent , Colors . black87 ] ,
begin: Alignment . topCenter ,
end: Alignment . bottomCenter ,
stops: [ 0.45 , 1.0 ] ,
) ,
) ,
) ,
) ,
// top safe area controls
SafeArea (
child: Padding (
padding: const EdgeInsets . symmetric ( horizontal: 12 , vertical: 10 ) ,
child: Row (
mainAxisAlignment: MainAxisAlignment . spaceBetween ,
children: [
_smallRoundedButton ( icon: Icons . arrow_back , onTap: ( ) = > Navigator . pop ( context ) ) ,
_smallRoundedButton ( icon: Icons . favorite_border , onTap: ( ) { } ) ,
] ,
) ,
) ,
) ,
// bottom anchored overlay: title, details, either book button or booked row, learn more
Align (
alignment: Alignment . bottomCenter ,
child: SafeArea (
bottom: true ,
child: Padding (
padding: const EdgeInsets . fromLTRB ( 20 , 12 , 20 , 16 ) ,
child: Column (
mainAxisSize: MainAxisSize . min ,
children: [
// Title & details
Container (
width: double . infinity ,
child: Column (
crossAxisAlignment: CrossAxisAlignment . start ,
children: [
Text (
' The Homecoming Tour | Sid Sriram Live in Concert ' ,
style: TextStyle ( color: Colors . white , fontSize: 22 , fontWeight: FontWeight . bold ) ,
) ,
SizedBox ( height: 10 ) ,
Row (
children: [
Icon ( Icons . calendar_today , size: 16 , color: Colors . white70 ) ,
SizedBox ( width: 8 ) ,
Text ( ' 22 Jan - 24 Jan ' , style: TextStyle ( color: Colors . white70 ) ) ,
SizedBox ( width: 12 ) ,
Icon ( Icons . location_on , size: 16 , color: Colors . white70 ) ,
SizedBox ( width: 8 ) ,
Expanded ( child: Text ( ' Cultural Hall, Brookefield ' , style: TextStyle ( color: Colors . white70 ) ) ) ,
] ,
) ,
] ,
) ,
) ,
SizedBox ( height: 16 ) ,
// If booked: show green pill + icons in-place.
// Otherwise show the large Book button.
if ( _booked ) . . . [
_bookedRow ( ) ,
SizedBox ( height: 12 ) ,
] else . . . [
SizedBox (
width: double . infinity ,
child: ElevatedButton (
onPressed: _confirmBookingFromMain ,
style: ElevatedButton . styleFrom (
padding: EdgeInsets . symmetric ( vertical: 16 ) ,
shape: RoundedRectangleBorder ( borderRadius: BorderRadius . circular ( 12 ) ) ,
backgroundColor: Color ( 0xFF0B63D6 ) ,
foregroundColor: Colors . white ,
) ,
child: Text ( ' Book Your Spot ' , style: TextStyle ( fontSize: 16 , color: Colors . white ) ) ,
) ,
) ,
SizedBox ( height: 12 ) ,
] ,
// Learn more handle (tappable)
GestureDetector (
onTap: _openLearnMoreSheet ,
child: Column (
children: [
Text ( ' Learn More ' , style: TextStyle ( color: Colors . white70 ) ) ,
SizedBox ( height: 6 ) ,
Icon ( Icons . keyboard_double_arrow_up , color: Colors . white70 ) ,
] ,
) ,
) ,
] ,
) ,
) ,
) ,
) ,
] ,
) ,
) ;
}
Widget _smallRoundedButton ( { required IconData icon , required VoidCallback onTap } ) {
return InkWell (
onTap: onTap ,
borderRadius: BorderRadius . circular ( 12 ) ,
child: Container (
width: 44 ,
height: 44 ,
decoration: BoxDecoration ( color: Colors . white24 , borderRadius: BorderRadius . circular ( 12 ) ) ,
child: Icon ( icon , color: Colors . white ) ,
) ,
) ;
}
}