Files
CityCards_Partner_Flutter/lib/recurring/views/recurring_block.dart
2025-10-29 18:55:48 +05:30

1212 lines
46 KiB
Dart

import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:provider/provider.dart';
import 'package:syncfusion_flutter_datepicker/datepicker.dart';
import '../viewmodels/recurring_block_viewmodel.dart';
class RecurringBlockPage extends StatelessWidget {
const RecurringBlockPage({super.key});
@override
Widget build(BuildContext context) {
return ChangeNotifierProvider(
create: (_) => RecurringBlockViewModel(),
child: Consumer<RecurringBlockViewModel>(
builder: (context, viewModel, _) {
final step = viewModel.currentStep;
return Scaffold(
backgroundColor: Colors.white,
body: SafeArea(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_buildHeader(context, viewModel),
const SizedBox(height: 42),
_buildProgressIndicator(step),
const SizedBox(height: 24),
Expanded(
child: AnimatedSwitcher(
duration: const Duration(milliseconds: 400),
transitionBuilder: (child, animation) {
final offsetAnimation = Tween<Offset>(
begin: const Offset(0.2, 0),
end: Offset.zero,
).animate(animation);
return SlideTransition(
position: offsetAnimation,
child: FadeTransition(
opacity: animation,
child: child,
),
);
},
// 👇 This prevents the default centering and pins content to the top
layoutBuilder: (currentChild, previousChildren) {
return Stack(
alignment: Alignment.topCenter,
children: <Widget>[
...previousChildren,
if (currentChild != null)
Positioned.fill(
child: Align(
alignment: Alignment.topCenter,
child: currentChild,
),
),
],
);
},
// 👇 also top-align the active child itself
child: Align(
alignment: Alignment.topCenter,
child: _buildStep(step, viewModel),
),
),
),
step == 3
? Padding(
padding: const EdgeInsets.symmetric(
horizontal: 20,
vertical: 14,
),
child: Row(
children: [
Expanded(
child: OutlinedButton(
onPressed: () {},
style: OutlinedButton.styleFrom(
side: const BorderSide(
color: Color(0xffF95F62),
),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
padding: const EdgeInsets.symmetric(
vertical: 16,
),
),
child: Text(
"Cancel",
style: GoogleFonts.poppins(
fontWeight: FontWeight.w600,
fontSize: 15,
color: const Color(0xffF95F62),
),
),
),
),
const SizedBox(width: 10),
Expanded(
child: ElevatedButton(
onPressed: () {},
style: ElevatedButton.styleFrom(
backgroundColor: const Color(0xffF95F62),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
padding: const EdgeInsets.symmetric(
vertical: 16,
),
),
child: Text(
"Create Block",
style: GoogleFonts.poppins(
fontWeight: FontWeight.w600,
fontSize: 15,
color: Colors.white,
),
),
),
),
],
),
)
: Padding(
padding: const EdgeInsets.symmetric(
horizontal: 20,
vertical: 10,
),
child: SizedBox(
width: double.infinity,
child: ElevatedButton(
onPressed: viewModel.nextStep,
style: ElevatedButton.styleFrom(
backgroundColor: const Color(0xffF95F62),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16),
),
padding: const EdgeInsets.symmetric(
vertical: 16,
),
),
child: Text(
"Next",
style: GoogleFonts.poppins(
fontWeight: FontWeight.w600,
fontSize: 15,
color: Colors.white,
),
),
),
),
),
],
),
),
);
},
),
);
}
Widget _buildHeader(BuildContext context, RecurringBlockViewModel viewModel) {
return Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Padding(
padding: const EdgeInsets.only(left: 20.0),
child: GestureDetector(
onTap: () {
viewModel.previousStep(context);
},
child: CircleAvatar(
radius: 20,
backgroundColor: const Color(0xffF95F62),
child: const Icon(Icons.arrow_back, color: Colors.white),
),
),
),
Text(
"Recurring block",
style: GoogleFonts.poppins(
fontWeight: FontWeight.w600,
fontSize: 32,
color: Colors.black,
),
),
SizedBox(width: 26),
],
),
SizedBox(height: 6),
Align(
alignment: Alignment.center,
child: Text(
viewModel.currentStep == 0
? "Basic Information"
: viewModel.currentStep == 1
? "Recurrence Pattern"
: viewModel.currentStep == 2
? "Time Slots"
: viewModel.currentStep == 3
? "Review & Confirm"
: "",
style: GoogleFonts.poppins(
fontWeight: FontWeight.w400,
fontSize: 16,
),
),
),
],
);
}
Widget _buildProgressIndicator(int step) {
return Row(
mainAxisAlignment: MainAxisAlignment.center,
children: List.generate(4, (index) {
final isActive = index == step;
return AnimatedContainer(
duration: const Duration(milliseconds: 300),
margin: const EdgeInsets.symmetric(horizontal: 4),
width: 59,
height: 10,
decoration: BoxDecoration(
color: isActive ? const Color(0xffF95F62) : const Color(0xffFCE7E7),
borderRadius: BorderRadius.circular(6),
),
);
}),
);
}
Widget _buildStep(int step, RecurringBlockViewModel viewModel) {
switch (step) {
case 0:
return _buildBasicInfo();
case 1:
return _buildRecurrenceType();
case 2:
return _buildTimeSlots();
case 3:
return _buildReviewConfirm();
default:
return const SizedBox.shrink();
}
}
Widget _buildBasicInfo() {
final categories = [
"Tourist Attraction",
"Museum & Gallery",
"Outdoor Activity",
"Entertainment",
"Food Experience",
"Cultural Site",
];
final imagePath = [
"assets/recurring/culture.png",
"assets/recurring/Entertainment.png",
"assets/recurring/food.png",
"assets/recurring/musuem.png",
"assets/recurring/outdoor.png",
"assets/recurring/tourist.png",
];
return Consumer<RecurringBlockViewModel>(builder: (context, viewModel, _) {
return SingleChildScrollView(key: const ValueKey("basic_info"),
padding: const EdgeInsets.symmetric(horizontal: 20),
child: Column(crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text("Category", style: GoogleFonts.poppins(
fontWeight: FontWeight.w600, fontSize: 24,),),
const SizedBox(height: 10),
GridView.builder(shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
itemCount: categories.length,
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
crossAxisSpacing: 10,
mainAxisSpacing: 10,
childAspectRatio: 2.8,),
itemBuilder: (context, index) {
final category = categories[index];
final image = imagePath[index];
final isSelected = viewModel.selectedCategory == category;
return GestureDetector(
onTap: () => viewModel.selectCategory(category),
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 24),
decoration: BoxDecoration(color: isSelected ? const Color(
0xffFFEDE6) : Colors.white,
borderRadius: BorderRadius.circular(10),
border: Border.all(color: isSelected ? const Color(
0xffFFEDE6) : Colors.grey.shade300, width: 1.5,),),
child: Row(mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Padding(padding: const EdgeInsets.only(right: 8.0),
child: Image.asset(image, width: 32, height: 32,),),
Expanded(child: Text(
category, textAlign: TextAlign.left,
maxLines: 2,
overflow: TextOverflow.visible,
style: GoogleFonts.poppins(fontSize: 16.0,
fontWeight: FontWeight.w500,
color: Colors.black,
height: 1.2,),),),
],),),);
},),
const SizedBox(height: 20),
_inputField("Attraction Name", "Enter attraction name"),
_inputField("Location", "Enter location"),
_inputField(
"Description (Optional)", "Brief description", maxLines: 3,),
const SizedBox(height: 12),
Row(children: [
Expanded(child: _dateField("Start Date")),
const SizedBox(width: 10),
Expanded(child: _dateField("End Date")),
],),
],),);
},);
}
// --- Step 1: Recurrence Type ---
Widget _buildRecurrenceType() {
final days = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
return Consumer<RecurringBlockViewModel>(
builder: (context, viewModel, _) {
return SingleChildScrollView(
key: const ValueKey("recurrence_type"),
padding: const EdgeInsets.symmetric(horizontal: 20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Recurrence Type",
style: GoogleFonts.poppins(
fontWeight: FontWeight.w600,
fontSize: 24,
),
),
const SizedBox(height: 10),
// Recurrence Options (Daily, Weekly, Monthly)
...["Daily", "Weekly", "Monthly"].map((type) {
final subtitle = type == "Daily"
? "Every Day"
: type == "Weekly"
? "Specific days of the week"
: "Same dates each month";
final isSelected = viewModel.selectedRecurrence == type;
return SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
GestureDetector(
onTap: () => viewModel.selectRecurrence(type),
child: Container(
margin: const EdgeInsets.only(bottom: 12),
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: isSelected
? const Color(0xFFFFF1EE)
: Colors.white,
border: Border.all(
color: isSelected
? const Color(0xffF95F62)
: Colors.grey.shade300,
),
borderRadius: BorderRadius.circular(10),
),
child: Row(
children: [
Image.asset(
"assets/recurring/lets-icons_date-fill.png",
scale: 4,
),
const SizedBox(width: 12),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
type,
style: GoogleFonts.poppins(
fontWeight: FontWeight.w500,
fontSize: 16,
),
),
Text(
subtitle,
style: GoogleFonts.poppins(
fontSize: 12,
fontWeight: FontWeight.w400,
color: Colors.black54,
),
),
],
),
],
),
),
),
// 🟩 WEEKLY SECTION (appears directly under Weekly card)
if (isSelected && type == "Weekly") ...[
const SizedBox(height: 8),
Text(
"Select Days",
style: GoogleFonts.poppins(
fontWeight: FontWeight.w600,
fontSize: 24,
),
),
const SizedBox(height: 8),
Wrap(
spacing: 8,
runSpacing: 8,
children: days.map((day) {
final isDaySelected = viewModel.selectedDays
.contains(day);
return GestureDetector(
onTap: () => viewModel.toggleDay(day),
child: Container(
padding: const EdgeInsets.symmetric(
horizontal: 14,
vertical: 8,
),
decoration: BoxDecoration(
color: isDaySelected
? const Color(0xFFFFF1EE)
: Colors.white,
border: Border.all(
color: isDaySelected
? const Color(0xffF95F62)
: Colors.grey.shade400,
),
borderRadius: BorderRadius.circular(8),
),
child: Text(
day,
style: GoogleFonts.poppins(
fontSize: 15,
fontWeight: FontWeight.w500,
color: isDaySelected
? const Color(0xffF95F62)
: Colors.black,
),
),
),
);
}).toList(),
),
const SizedBox(height: 16),
SizedBox(
child: Text(
"Every ${viewModel.repeatWeek} week(s)",
style: GoogleFonts.poppins(
fontWeight: FontWeight.w600,
fontSize: 24,
),
),
),
const SizedBox(height: 8),
Container(
padding: const EdgeInsets.symmetric(
horizontal: 16,
vertical: 10,
),
decoration: BoxDecoration(
color: const Color(0xffF6F6F6),
borderRadius: BorderRadius.circular(12),
),
child: Row(
children: [
_roundButton(
Icons.remove,
viewModel.decrementWeek,
),
Padding(
padding: const EdgeInsets.symmetric(
horizontal: 12.0,
),
child: Center(
child: Text(
"${viewModel.repeatWeek}",
style: GoogleFonts.poppins(
fontSize: 16,
fontWeight: FontWeight.w600,
),
),
),
),
_roundButton(Icons.add, viewModel.incrementWeek),
const SizedBox(width: 8),
Text(
"repeats 1 ",
style: GoogleFonts.poppins(
fontSize: 13,
color: Colors.black54,
),
),
],
),
),
const SizedBox(height: 20),
],
// 🟦 MONTHLY SECTION (calendar starts immediately under Monthly card)
if (isSelected && type == "Monthly") ...[
const SizedBox(height: 8),
Text(
"Select Dates",
style: GoogleFonts.poppins(
fontWeight: FontWeight.w600,
fontSize: 24,
),
),
const SizedBox(height: 8),
Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12),
color: Colors.white,
boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.1),
spreadRadius: 1,
blurRadius: 2,
offset: const Offset(0, 1),
),
],
),
child: SfDateRangePicker(
// 🔴 Selection & Range Colors
startRangeSelectionColor: const Color(0xffF95F62),
endRangeSelectionColor: const Color(0xffF95F62),
rangeSelectionColor: const Color(0xFFFFF1EE),
selectionTextStyle: GoogleFonts.poppins(
color: Colors.white,
fontWeight: FontWeight.w600,
),
selectionMode: DateRangePickerSelectionMode.range,
// 🧭 Navigation & Layout
backgroundColor: Colors.white,
showNavigationArrow: true,
initialDisplayDate: viewModel.focusedMonth,
toggleDaySelection: false,
todayHighlightColor: const Color(0xffF95F62),
minDate: DateTime(2020),
maxDate: DateTime(2030),
// 📅 Header (Month / Year)
headerStyle: DateRangePickerHeaderStyle(
backgroundColor: Colors.white,
textAlign: TextAlign.center,
textStyle: GoogleFonts.poppins(
color: Colors.black,
fontWeight: FontWeight.w700,
fontSize: 18,
),
),
// 📆 Month View Settings
monthViewSettings:
const DateRangePickerMonthViewSettings(
// firstDayOfWeek: 1,
viewHeaderStyle:
DateRangePickerViewHeaderStyle(
textStyle: TextStyle(
fontWeight: FontWeight.w600,
fontSize: 14,
color: Colors.black,
),
),
showTrailingAndLeadingDates: true,
),
// 🗓️ Customize Month Cells
monthCellStyle: DateRangePickerMonthCellStyle(
todayTextStyle: GoogleFonts.poppins(
color: const Color(0xffF95F62),
fontWeight: FontWeight.w600,
),
textStyle: GoogleFonts.poppins(
color: Colors.black,
fontWeight: FontWeight.w500,
),
trailingDatesTextStyle: GoogleFonts.poppins(
color: Colors.grey.shade400,
fontWeight: FontWeight.w400,
),
leadingDatesTextStyle: GoogleFonts.poppins(
color: Colors.grey.shade400,
fontWeight: FontWeight.w400,
),
),
// 🔁 Handle Selections
onSelectionChanged: (args) {
if (args.value is PickerDateRange) {
viewModel.selectedDates.clear();
final PickerDateRange range = args.value;
final start = range.startDate;
final end = range.endDate ?? start;
// if (start != null && end != null) {
// for (var date = start;
// date.isBefore(end.add(const Duration(days: 1)));
// date = date.add(const Duration(days: 1))) {
// viewModel.selectedDates.add(date);
// }
// }
viewModel.notifyListeners();
} else if (args.value is DateTime) {
viewModel.selectedDates.clear();
viewModel.selectedDates.add(args.value);
viewModel.notifyListeners();
}
},
),
),
const SizedBox(height: 16),
Text(
"Every ${viewModel.repeatWeek} Month(s)",
style: GoogleFonts.poppins(
fontWeight: FontWeight.w600,
fontSize: 24,
),
),
const SizedBox(height: 8),
Container(
padding: const EdgeInsets.symmetric(
horizontal: 16,
vertical: 10,
),
decoration: BoxDecoration(
color: const Color(0xffF6F6F6),
borderRadius: BorderRadius.circular(12),
),
child: Row(
children: [
_roundButton(
Icons.remove,
viewModel.decrementWeek,
),
Center(
child: Padding(
padding: const EdgeInsets.symmetric(
horizontal: 12.0,
),
child: Text(
"${viewModel.repeatWeek}",
style: GoogleFonts.poppins(
fontSize: 16,
fontWeight: FontWeight.w600,
),
),
),
),
_roundButton(Icons.add, viewModel.incrementWeek),
const SizedBox(width: 8),
Text(
"repeats 1 Month",
style: GoogleFonts.poppins(
fontSize: 13,
color: Colors.black54,
),
),
],
),
),
const SizedBox(height: 20),
],
],
),
);
}),
],
),
);
},
);
}
Widget _roundButton(IconData icon, VoidCallback onPressed) {
return GestureDetector(
onTap: onPressed,
child: Container(
width: 36,
height: 36,
decoration: const BoxDecoration(
color: Color(0xffF95F62),
shape: BoxShape.circle,
),
child: Icon(icon, color: Colors.white, size: 20),
),
);
}
// --- Step 2: Time Slots ---
Widget _buildTimeSlots() {
return Consumer<RecurringBlockViewModel>(
builder: (context, viewModel, _) {
return SingleChildScrollView(
key: const ValueKey("time_slots"),
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 10),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// ---------------- Title & Add Timing ----------------
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
"Time Slots Available",
style: GoogleFonts.poppins(
fontWeight: FontWeight.w600,
fontSize: 20,
color: Colors.black,
),
),
Container(
padding: const EdgeInsets.symmetric(
horizontal: 14,
vertical: 6,
),
decoration: BoxDecoration(
border: Border.all(color: const Color(0xffF95F62)),
borderRadius: BorderRadius.circular(8),
),
child: Text(
"+ Add timing",
style: GoogleFonts.poppins(
color: const Color(0xffF95F62),
fontWeight: FontWeight.w600,
fontSize: 14,
),
),
),
],
),
const SizedBox(height: 20),
// ---------------- Slot Card ----------------
Container(
width: double.infinity,
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: const Color(0xffF6F6F6),
borderRadius: BorderRadius.circular(12),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Slot 1",
style: GoogleFonts.poppins(
fontWeight: FontWeight.w500,
fontSize: 16,
color: Colors.black,
),
),
const SizedBox(height: 10),
Row(
children: [
Expanded(child: _timeBox("Start Time", "9:00 AM")),
const SizedBox(width: 12),
Expanded(child: _timeBox("End Time", "12:00 PM")),
],
),
],
),
),
const SizedBox(height: 24),
// ---------------- Capacity ----------------
Text(
"Capacity per Time Slot",
style: GoogleFonts.poppins(
fontWeight: FontWeight.w700,
fontSize: 20,
color: Colors.black,
),
),
const SizedBox(height: 12),
Container(
width: double.infinity,
padding: const EdgeInsets.symmetric(
horizontal: 20,
vertical: 16,
),
decoration: BoxDecoration(
color: const Color(0xffF6F6F6),
borderRadius: BorderRadius.circular(12),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Expanded(child: _capacityButton(Icons.remove, () {})),
const SizedBox(width: 24),
Column(
children: [
Text(
"50",
style: GoogleFonts.poppins(
fontWeight: FontWeight.w600,
fontSize: 18,
color: Colors.black,
),
),
Text(
"people",
style: GoogleFonts.poppins(
color: Colors.black45,
fontSize: 13,
),
),
],
),
const SizedBox(width: 24),
Expanded(child: _capacityButton(Icons.add, () {})),
],
),
),
const SizedBox(height: 20),
// ---------------- Create Slot Button ----------------
SizedBox(
width: double.infinity,
child: ElevatedButton(
onPressed: () {},
style: ElevatedButton.styleFrom(
backgroundColor: Colors.black,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
),
padding: const EdgeInsets.symmetric(vertical: 16),
),
child: Text(
"Create Slot",
style: GoogleFonts.poppins(
color: Colors.white,
fontWeight: FontWeight.w600,
fontSize: 15,
),
),
),
),
const SizedBox(height: 24),
Text(
"Preview",
style: GoogleFonts.poppins(
fontWeight: FontWeight.w700,
fontSize: 20,
color: Colors.black,
),
),
const SizedBox(height: 12),
Container(
width: double.infinity,
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: const Color(0xffEAF8EF),
borderRadius: BorderRadius.circular(12),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
const CircleAvatar(
radius: 6,
backgroundColor: Color(0xff4CAF50),
),
const SizedBox(width: 8),
Text(
"The Enchanted Garden Adventure Park",
style: GoogleFonts.poppins(
fontWeight: FontWeight.w600,
fontSize: 14,
color: Colors.black,
),
),
],
),
const SizedBox(height: 8),
Container(
padding: const EdgeInsets.symmetric(
horizontal: 12,
vertical: 6,
),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(8),
),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Text(
"9:00am - 12:00pm ",
style: GoogleFonts.poppins(
fontSize: 13,
color: Colors.black,
fontWeight: FontWeight.w500,
),
),
Container(
decoration: BoxDecoration(
color: Color(0xffF0F0F0),
borderRadius: BorderRadius.circular(6),
),
child: Padding(
padding: const EdgeInsets.symmetric(
horizontal: 12.0,
vertical: 8,
),
child: Text(
"0/50",
style: GoogleFonts.poppins(
fontSize: 13,
color: Colors.black,
fontWeight: FontWeight.w500,
),
),
),
),
],
),
),
],
),
),
],
),
);
},
);
}
Widget _inputField(String label, String hint, {int maxLines = 1}) {
return Padding(
padding: const EdgeInsets.only(bottom: 16), child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(label, style: GoogleFonts.poppins(
fontWeight: FontWeight.w700, fontSize: 24,),),
const SizedBox(height: 6),
TextField(
maxLines: maxLines, decoration: InputDecoration(
hintText: hint,
hintStyle: GoogleFonts.poppins(color: Colors.grey, fontSize: 13),
filled: true,
fillColor: const Color(0xffF6F6F6),
contentPadding: const EdgeInsets.symmetric(
horizontal: 12, vertical: 14,),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
borderSide: BorderSide.none,),),),
],),);
}
Widget _dateField(String label) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(label, style: GoogleFonts.poppins(
fontWeight: FontWeight.w600, fontSize: 24),),
const SizedBox(height: 6),
Container(
width: double.infinity,
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 14),
decoration: BoxDecoration(
color: const Color(0xffF6F6F6),
borderRadius: BorderRadius.circular(10),),
child: Text("mm/dd/yyyy", style: GoogleFonts.poppins(fontSize: 14,
color: Colors.black87,
fontWeight: FontWeight.w600),),),
],);
}
}
// ---------------- Reusable UI Helpers ----------------
Widget _timeBox(String label, String value) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
label,
style: GoogleFonts.poppins(
fontWeight: FontWeight.w500,
color: Colors.black54,
fontSize: 13,
),
),
const SizedBox(height: 6),
Container(
height: 48,
alignment: Alignment.centerLeft,
padding: const EdgeInsets.symmetric(horizontal: 14),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(8),
border: Border.all(color: Colors.grey.shade300),
),
child: Text(
value,
style: GoogleFonts.poppins(
color: Colors.black,
fontWeight: FontWeight.w600,
fontSize: 14,
),
),
),
],
);
}
Widget _capacityButton(IconData icon, VoidCallback onTap) {
return GestureDetector(
onTap: onTap,
child: Container(
width: 48,
height: 36,
alignment: Alignment.center,
decoration: BoxDecoration(
color: const Color(0xFFFFF1EE),
border: Border.all(color: const Color(0xffF95F62)),
borderRadius: BorderRadius.circular(8),
),
child: Icon(icon, color: const Color(0xffF95F62), size: 20),
),
);
}
// --- Step 3: Review & Confirm ---
Widget _buildReviewConfirm() {
return SingleChildScrollView(
key: const ValueKey("review_confirm"),
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 10),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Basic Information
Container(
width: double.infinity,
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: const Color(0xffF6F6F6),
borderRadius: BorderRadius.circular(12),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Basic Information",
style: GoogleFonts.poppins(
fontWeight: FontWeight.w500,
fontSize: 16,
),
),
const SizedBox(height: 12),
_reviewRow("Name:", "The Enchanted Garden"),
_reviewRow("Location:", "Dubai"),
_reviewRow("Category:", "Tourist Attraction"),
_reviewRow("Duration:", "01/02/2025 to 02/02/2025"),
],
),
),
const SizedBox(height: 16),
// Schedule Information
Container(
width: double.infinity,
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: const Color(0xffF6F6F6),
borderRadius: BorderRadius.circular(12),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Schedule Information",
style: GoogleFonts.poppins(
fontWeight: FontWeight.w500,
fontSize: 16,
),
),
const SizedBox(height: 12),
_reviewRow("Pattern:", "Weekly"),
_reviewRow("Days:", "Sun, Mon, Tues"),
_reviewRow("Time Slots:", "1 slot"),
_reviewRow("Capacity:", "50 people per slot"),
],
),
),
const SizedBox(height: 16),
// Preview Section
Container(
width: double.infinity,
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: const Color(0xffF6F6F6),
borderRadius: BorderRadius.circular(12),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Preview (First 10 days)",
style: GoogleFonts.poppins(
fontWeight: FontWeight.w500,
fontSize: 16,
),
),
const SizedBox(height: 12),
Wrap(
spacing: 8,
runSpacing: 8,
children:
[
"Dec 4",
"Dec 7",
"Dec 8",
"Dec 9",
"Dec 10",
"Dec 11",
"Dec 12",
"Dec 13",
"Dec 14",
"Dec 15",
]
.map(
(date) =>
Container(
padding: const EdgeInsets.symmetric(
horizontal: 14,
vertical: 8,
),
decoration: BoxDecoration(
color: Colors.white,
border: Border.all(color: Colors.grey.shade300),
borderRadius: BorderRadius.circular(10),
),
child: Text(
date,
style: GoogleFonts.poppins(
fontSize: 16,
fontWeight: FontWeight.w500,
color: Colors.black,
),
),
),
)
.toList(),
),
],
),
),
const SizedBox(height: 30),
// Bottom Buttons (Cancel / Create Block)
const SizedBox(height: 20),
],
),
);
}
Widget _reviewRow(String label, String value) {
return Padding(
padding: const EdgeInsets.only(bottom: 6),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(
width: 90,
child: Text(
label,
style: GoogleFonts.poppins(
fontSize: 14,
fontWeight: FontWeight.w400,
color: Colors.black,
),
),
),
Expanded(
child: Text(
value,
style: GoogleFonts.poppins(
fontWeight: FontWeight.w400,
fontSize: 14,
color: Color(0xff767676),
),
),
),
],
),
);
}