diff --git a/assets/icons/delete_icon.png b/assets/icons/delete_icon.png new file mode 100644 index 0000000..d0a3962 Binary files /dev/null and b/assets/icons/delete_icon.png differ diff --git a/assets/icons/edit_icon.png b/assets/icons/edit_icon.png new file mode 100644 index 0000000..4404be7 Binary files /dev/null and b/assets/icons/edit_icon.png differ diff --git a/assets/icons/send_icon.png b/assets/icons/send_icon.png new file mode 100644 index 0000000..cc5538d Binary files /dev/null and b/assets/icons/send_icon.png differ diff --git a/assets/images/post_card_intro.png b/assets/images/post_card_intro.png index 70abe1b..1712bf0 100644 Binary files a/assets/images/post_card_intro.png and b/assets/images/post_card_intro.png differ diff --git a/lib/attractions/views/attractions_page_view.dart b/lib/attractions/views/attractions_page_view.dart index f927f5f..e941d57 100644 --- a/lib/attractions/views/attractions_page_view.dart +++ b/lib/attractions/views/attractions_page_view.dart @@ -29,8 +29,6 @@ class AttractionsPage extends StatelessWidget { children: [ // App bar CommonAppBar(isWhiteLogo: false, isProfilePage: false), - SizedBox(height: 12.h), - Divider(height: 1.h, color: const Color(0xFFD9D9D9)), SizedBox(height: 22.h), // Back row diff --git a/lib/postcard/blocs/postcard_creation_bloc.dart b/lib/postcard/blocs/postcard_creation_bloc.dart index 85ee218..749dcaf 100644 --- a/lib/postcard/blocs/postcard_creation_bloc.dart +++ b/lib/postcard/blocs/postcard_creation_bloc.dart @@ -6,7 +6,7 @@ import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:image_picker/image_picker.dart'; import 'package:image/image.dart' as img; -enum PostcardStep { uploadPhoto, addFilter, writeMessage, preview } +enum PostcardStep { uploadPhoto, addFilter, writeMessage, preview, purchase, checkout, orderSuccess, myOrders, myOrderPostcardPreview} class PostcardCreationBloc extends Bloc { diff --git a/lib/postcard/views/my_orders_page_view.dart b/lib/postcard/views/my_orders_page_view.dart new file mode 100644 index 0000000..abd6cf1 --- /dev/null +++ b/lib/postcard/views/my_orders_page_view.dart @@ -0,0 +1,403 @@ +import 'dart:io'; + +import 'package:citycards_customer/common_packages/app_bar.dart'; +import 'package:citycards_customer/postcard/blocs/postcard_creation_events.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:google_fonts/google_fonts.dart'; + +import '../blocs/postcard_creation_bloc.dart'; +import '../blocs/postcard_creation_state.dart'; + +class MyOrdersPageView extends StatefulWidget { + const MyOrdersPageView({super.key}); + + @override + State createState() => _MyOrdersPageViewState(); +} + +class _MyOrdersPageViewState extends State { + bool showDrafts = true; + + @override + Widget build(BuildContext context) { + return BlocBuilder( + builder: (context, state) { + final bloc = context.read(); + return SafeArea( + child: Padding( + padding: const EdgeInsets.all(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // ๐Ÿ™๏ธ Header + CommonAppBar(isWhiteLogo: false, isProfilePage: false), + + Row( + children: [ + Expanded( + child: GestureDetector( + onTap: () => setState(() => showDrafts = true), + child: Container( + padding: const EdgeInsets.symmetric(vertical: 12), + decoration: BoxDecoration( + color: showDrafts + ? const Color(0xffF95F62).withOpacity(0.24) + : Colors.transparent, + borderRadius: BorderRadius.circular(12), + border: Border.all( + color: showDrafts + ? const Color(0xffF95F62).withOpacity(0.4) + : const Color(0xffE0E0E0), + ), + ), + child: Center( + child: Text( + "My drafts", + style: TextStyle( + fontWeight: FontWeight.w400, + fontSize: 14.sp, + color: showDrafts + ? Colors.black + : Colors.black.withOpacity(0.56), + ), + ), + ), + ), + ), + ), + const SizedBox(width: 12), + Expanded( + child: GestureDetector( + onTap: () => setState(() => showDrafts = false), + child: Container( + padding: const EdgeInsets.symmetric(vertical: 12), + decoration: BoxDecoration( + color: !showDrafts + ? const Color(0xffF95F62).withOpacity(0.24) + : Colors.transparent, + borderRadius: BorderRadius.circular(12), + border: Border.all( + color: !showDrafts + ? const Color(0xffF95F62).withOpacity(0.4) + : const Color(0xffE0E0E0), + ), + ), + child: Center( + child: Text( + "My orders", + style: TextStyle( + fontWeight: FontWeight.w400, + fontSize: 14.sp, + color: !showDrafts + ? Colors.black + : Colors.black.withOpacity(0.56), + ), + ), + ), + ), + ), + ), + ], + ), + const SizedBox(height: 24), + + // ๐Ÿ“ฌ Postcard List + showDrafts + ? Expanded( + child: ListView.builder( + itemCount: 5, + itemBuilder: (context, index) { + return Container( + margin: const EdgeInsets.only(bottom: 16), + padding: const EdgeInsets.fromLTRB( + 10, + 10, + 10, + 10, + ), + decoration: BoxDecoration( + color: const Color(0xFFFFF5F5), + borderRadius: BorderRadius.circular(12), + border: Border.all( + color: const Color(0xffF1F5F7), + ), + ), + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + ClipRRect( + borderRadius: BorderRadius.circular(8), + child: Image.file( + File(state.imagePath ?? ""), + height: 90.h, + width: 90.w, + fit: BoxFit.cover, + ), + ), + const SizedBox(width: 20), + + Expanded( + child: SizedBox( + height: 90.h, + child: Stack( + children: [ + /// Centered texts + Align( + alignment: Alignment.centerLeft, + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: + CrossAxisAlignment.start, + children: [ + Text( + "#688574", + style: GoogleFonts.poppins( + fontSize: 14.sp, + fontWeight: FontWeight.w400, + color: Colors.black, + ), + ), + const SizedBox(height: 3), + Text( + "My postcard", + style: GoogleFonts.poppins( + fontSize: 16.sp, + fontWeight: FontWeight.w400, + color: Colors.black, + ), + ), + ], + ), + ), + + /// ๐Ÿงญ Bottom-right icons + Align( + alignment: Alignment.bottomRight, + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + InkWell( + onTap: () {}, + child: Image.asset( + "assets/icons/delete_icon.png", + scale: 4, + ), + ), + const SizedBox(width: 20), + InkWell( + onTap: () {}, + child: Image.asset( + "assets/icons/edit_icon.png", + scale: 4, + ), + ), + const SizedBox(width: 20), + InkWell( + onTap: () {}, + child: Image.asset( + "assets/icons/send_icon.png", + scale: 4, + ), + ), + const SizedBox(width: 10), + ], + ), + ), + ], + ), + ), + ), + ], + ), + ); + }, + ), + ) + : Expanded( + child: ListView.builder( + itemCount: 2, + itemBuilder: (context, index) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + "#688574", + style: GoogleFonts.poppins( + fontSize: 14.sp, + fontWeight: FontWeight.w400, + color: Colors.black, + ), + ), + const SizedBox(height: 3), + Container( + margin: const EdgeInsets.only(bottom: 16), + padding: const EdgeInsets.fromLTRB( + 10, + 10, + 10, + 10, + ), + decoration: BoxDecoration( + color: const Color(0xFFFFF5F5), + borderRadius: BorderRadius.circular(12), + border: Border.all( + color: const Color(0xffF1F5F7), + ), + ), + child: Row( + crossAxisAlignment: + CrossAxisAlignment.center, + children: [ + ClipRRect( + borderRadius: BorderRadius.circular(8), + child: Image.file( + File(state.imagePath ?? ""), + height: 70.h, + width: 70.w, + fit: BoxFit.cover, + ), + ), + const SizedBox(width: 20), + + Expanded( + child: SizedBox( + height: 60.h, + child: Row( + mainAxisAlignment: + MainAxisAlignment.spaceBetween, + children: [ + Column( + crossAxisAlignment: + CrossAxisAlignment.start, + mainAxisAlignment: + MainAxisAlignment.start, + children: [ + Text( + "My PostCard", + style: GoogleFonts.poppins( + color: Colors.black, + fontWeight: + FontWeight.w400, + fontSize: 16.sp, + ), + ), + const SizedBox(height: 6), + Text( + "5 Post cards", + style: GoogleFonts.poppins( + color: Colors.black, + fontWeight: + FontWeight.w400, + fontSize: 14.sp, + ), + ), + ], + ), + Column( + mainAxisAlignment: + MainAxisAlignment + .spaceBetween, + crossAxisAlignment: + CrossAxisAlignment.end, + children: [ + Container( + padding: EdgeInsets.fromLTRB(13, 7, 13, 7), + decoration: BoxDecoration( + color: Color( + 0xff00FFA6, + ).withOpacity(0.16), + border: Border.all( + color: Color( + 0xff439F6E, + ), + ), + borderRadius: + BorderRadius.circular( + 16, + ), + ), + child: Text( + "In Progress", + style: TextStyle( + color: Colors.black, + fontWeight: + FontWeight.w400, + fontSize: 8.54.sp, + ), + ), + ), + InkWell( + onTap: () { + bloc.add(GoToNextStep()); + }, + child: Row( + children: [ + Icon( + Icons + .remove_red_eye_outlined, + size: 15, + color: Color( + 0xffF95F62, + ), + ), + SizedBox(width: 5.w), + Text( + "Preview", + style: TextStyle( + fontWeight: + FontWeight.w400, + color: Color( + 0xffF95F62, + ), + ), + ), + ], + ), + ), + ], + ), + ], + ), + ), + ), + ], + ), + ), + ], + ); + }, + ), + ), + + // โž• Create postcard button + SizedBox( + width: double.infinity, + child: ElevatedButton( + onPressed: () {}, + style: ElevatedButton.styleFrom( + backgroundColor: const Color(0xffF95F62), + padding: EdgeInsets.symmetric(vertical: 16.h), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(40), + ), + ), + child: Text( + "Create post card", + style: GoogleFonts.poppins( + color: Colors.white, + fontSize: 14.sp, + fontWeight: FontWeight.w600, + ), + ), + ), + ), + ], + ), + ), + ); + }, + ); + } +} diff --git a/lib/postcard/views/order_postcard_preview_page_view.dart b/lib/postcard/views/order_postcard_preview_page_view.dart new file mode 100644 index 0000000..b4fe51b --- /dev/null +++ b/lib/postcard/views/order_postcard_preview_page_view.dart @@ -0,0 +1,165 @@ +import 'package:citycards_customer/postcard/blocs/postcard_creation_events.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; + +import '../../common_packages/app_bar.dart'; +import '../blocs/postcard_creation_bloc.dart'; +import '../blocs/postcard_creation_state.dart'; +import '../widgets/postcard_preview_widget.dart'; + +class OrderPostcardPreviewPageView extends StatefulWidget { + const OrderPostcardPreviewPageView({super.key}); + + @override + State createState() => _OrderPostcardPreviewPageViewState(); +} + +class _OrderPostcardPreviewPageViewState extends State { + + bool showImage = true; + + @override + Widget build(BuildContext context) { + return BlocBuilder( + builder: (context, state) { + final bloc = context.read(); + return SafeArea( + child: SingleChildScrollView( + padding: const EdgeInsets.all(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + CommonAppBar(isWhiteLogo: false, isProfilePage: false), + + Row( + children: [ + GestureDetector( + onTap: () { + bloc.add(GoToPreviousStep()); + }, + child: Icon(Icons.arrow_back, size: 24.sp), + ), + SizedBox(width: 8.w), + Text( + "Preview", + style: TextStyle( + fontSize: 14.sp, + fontWeight: FontWeight.w400, + color: Colors.black87, + ), + ), + ], + ), + + SizedBox(height: 25.h), + + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text("#688574", style: TextStyle( + color: Colors.black, + fontWeight: FontWeight.w400, + fontSize: 14.sp + )), + Row( + mainAxisSize: MainAxisSize.min, + children: [ + InkWell( + onTap: () {}, + child: Image.asset( + "assets/icons/delete_icon.png", + scale: 4, + ), + ), + const SizedBox(width: 20), + InkWell( + onTap: () {}, + child: Image.asset( + "assets/icons/edit_icon.png", + scale: 4, + ), + ), + const SizedBox(width: 20), + InkWell( + onTap: () {}, + child: Image.asset( + "assets/icons/send_icon.png", + scale: 4, + ), + ), + const SizedBox(width: 10), + ], + ) + ], + ), + + SizedBox(height: 50.h), + + // ๐Ÿ” Flip Buttons + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + TextButton.icon( + onPressed: showImage + ? () => setState(() => showImage = false) : null, + icon: Icon(Icons.arrow_back, + color: showImage + ? const Color(0xffF95F62) + : const Color(0xffC8C8C8), size: 18), + label: Text( + "Flip", + style: TextStyle( + color: showImage + ? const Color(0xffF95F62) + : const Color(0xffC8C8C8), + fontWeight: FontWeight.w500, + ), + ), + ), + TextButton.icon( + onPressed: showImage + ? null + : () => setState(() => showImage = true), + icon: Text( + "Flip", + style: TextStyle( + color: !showImage + ? const Color(0xffF95F62) + : const Color(0xffC8C8C8), + fontWeight: FontWeight.w500, + ), + ), + label: Icon(Icons.arrow_forward, + color: !showImage + ? const Color(0xffF95F62) + : const Color(0xffC8C8C8),size: 18), + ), + ], + ), + + showImage ? + ClipRRect( + borderRadius: BorderRadius.circular(8), + child: Image.asset( + "assets/images/post_card_intro.png", + width: double.infinity, + fit: BoxFit.cover, + ), + ): + PostCardPreviewWidget( + imagePath: state.imagePath ?? "", + message: state.message ?? "", + selectedFont: state.selectedFont, + ), + + const SizedBox(height: 24), + + ], + ), + ), + ); + }, + ); + } +} diff --git a/lib/postcard/views/order_success_page_view.dart b/lib/postcard/views/order_success_page_view.dart new file mode 100644 index 0000000..96fe16f --- /dev/null +++ b/lib/postcard/views/order_success_page_view.dart @@ -0,0 +1,125 @@ +import 'dart:io'; +import 'package:citycards_customer/postcard/blocs/postcard_creation_events.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:google_fonts/google_fonts.dart'; +import '../../common_packages/app_bar.dart'; +import '../blocs/postcard_creation_bloc.dart'; +import '../blocs/postcard_creation_state.dart'; +import '../widgets/postcard_preview_widget.dart'; + +class OrderSuccessPageView extends StatelessWidget { + const OrderSuccessPageView({super.key}); + + @override + Widget build(BuildContext context) { + return BlocBuilder( + builder: (context, state) { + final bloc = context.read(); + return SafeArea( + child: SingleChildScrollView( + padding: const EdgeInsets.all(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + CommonAppBar(isWhiteLogo: false, isProfilePage: false), + + Text( + "๐ŸŽ‰๐Ÿฅณ", + style: TextStyle(fontSize: 40.sp), + textAlign: TextAlign.center, + ), + const SizedBox(height: 20), + + Text( + "Order placed successful!", + style: TextStyle( + fontSize: 20.sp, + fontWeight: FontWeight.w500, + color: const Color(0xff1A1A1A), + ), + ), + const SizedBox(height: 8), + + RichText( + textAlign: TextAlign.center, + text: TextSpan( + style: GoogleFonts.poppins( + fontSize: 14.sp, + fontWeight: FontWeight.w400, + color: const Color(0xff585858), + ), + children: const [ + TextSpan(text: "Your order has been placed. Your order\nid is "), + TextSpan( + text: "#AG74563", + style: TextStyle( + fontWeight: FontWeight.w600, + color: Color(0xff585858), + ), + ), + ], + ), + ), + + const SizedBox(height: 10), + Text( + "It will be delivered in 2โ€“3 business \ndays.", + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 13.sp, + color: const Color(0xff585858), + ), + ), + + const SizedBox(height: 28), + + Container( + padding: EdgeInsets.fromLTRB(30, 10, 30, 10), + child: Transform.rotate( + angle: 0.08, + child: PostCardPreviewWidget( + imagePath: state.imagePath ?? "", + message: state.message ?? "", + selectedFont: state.selectedFont, + ), + ), + ), + + + const SizedBox(height: 20), + + + SizedBox( + width: double.infinity, + child: ElevatedButton( + onPressed: () { + bloc.add(GoToNextStep()); + }, + style: ElevatedButton.styleFrom( + backgroundColor: const Color(0xffF95F62), + padding: EdgeInsets.symmetric(vertical: 16.h), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(40), + ), + ), + child: Text( + "Go to My Orders", + style: TextStyle( + color: Colors.white, + fontSize: 14.sp, + fontWeight: FontWeight.w600, + ), + ), + ), + ), + ], + ), + ), + ); + }, + ); + } +} + diff --git a/lib/postcard/views/postcard_checkout_page_view.dart b/lib/postcard/views/postcard_checkout_page_view.dart new file mode 100644 index 0000000..c41d03c --- /dev/null +++ b/lib/postcard/views/postcard_checkout_page_view.dart @@ -0,0 +1,194 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:google_fonts/google_fonts.dart'; +import '../../common_packages/app_bar.dart'; +import '../blocs/postcard_creation_bloc.dart'; +import '../blocs/postcard_creation_events.dart'; +import '../blocs/postcard_creation_state.dart'; +import '../widgets/postcard_preview_widget.dart'; + +class PostcardCheckoutPageView extends StatelessWidget { + const PostcardCheckoutPageView({super.key}); + + @override + Widget build(BuildContext context) { + return BlocBuilder( + builder: (context, state) { + final bloc = context.read(); + return SafeArea( + child: SingleChildScrollView( + padding: const EdgeInsets.all(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + CommonAppBar(isWhiteLogo: false, isProfilePage: false), + // Header + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + "Checkout", + style: GoogleFonts.poppins( + fontSize: 20.sp, + fontWeight: FontWeight.w600, + color: const Color(0xff1A1A1A), + ), + ), + TextButton( + onPressed: () { + // TODO: Save as draft + }, + child: Text( + "Save as draft", + style: GoogleFonts.poppins( + fontSize: 14.sp, + fontWeight: FontWeight.w500, + color: const Color(0xffF95F62), + ), + ), + ), + ], + ), + + const SizedBox(height: 16), + + + PostCardPreviewWidget( + imagePath: state.imagePath ?? "", + message: state.message ?? "", + selectedFont: state.selectedFont, + ), + + SizedBox(height: 60.h), + + // ๐Ÿ’ฐ Payment Summary + Text( + "Payment summary", + style: TextStyle( + fontSize: 12.sp, + fontWeight: FontWeight.w400, + color: const Color(0xff999999), + ), + ), + Divider(color: Color(0xffEDEDED)), + const SizedBox(height: 5), + + _buildPaymentRow("Subtotal", "\$ 50"), + const SizedBox(height: 20), + _buildPaymentRow( + "Discount", + "\$ 20", + highlight: true, + ), + const SizedBox(height: 8), + Divider(color: Colors.black), + _buildPaymentRow("Grand Total", "\$ 30", size: 20.sp), + const SizedBox(height: 28), + Container( + color: Color(0xffFAFAFA), + height: 10, + ), + const SizedBox(height: 10), + Row( + children: [ + const Icon(Icons.home_outlined, + color: Color(0xffF95F62), size: 20), + const SizedBox(width: 10), + Expanded( + child: Text( + "Unit 7, Level 3, Dummy Towers 33.......", + style: GoogleFonts.poppins( + fontSize: 13.sp, + color: const Color(0xff2D3134), + ), + overflow: TextOverflow.ellipsis, + ), + ), + IconButton( + onPressed: () { + + }, + icon: const Icon(Icons.edit_outlined, + color: Color(0xffF95F62), size: 18), + ), + ], + ), + const SizedBox(height: 10), + Container( + color: Color(0xffFAFAFA), + height: 10, + ), + + const SizedBox(height: 40), + + // ๐Ÿงพ Pay Button + SizedBox( + width: double.infinity, + child: ElevatedButton( + onPressed: () { + bloc.add(GoToNextStep()); + }, + style: ElevatedButton.styleFrom( + backgroundColor: const Color(0xffF95F62), + padding: EdgeInsets.symmetric(vertical: 16.h), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(40), + ), + ), + child: Text( + "Pay \$30", + style: TextStyle( + color: Colors.white, + fontSize: 14.sp, + fontWeight: FontWeight.w600, + ), + ), + ), + ), + ], + ), + ), + ); + }, + ); + } + + /// ๐Ÿ’ต Helper for payment summary row + Widget _buildPaymentRow(String label, String value, + {bool highlight = false, double? size}) { + return Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + label, + style: GoogleFonts.poppins( + fontSize: 12.sp, + fontWeight: FontWeight.w400, + color: const Color(0xff2D3134), + ), + ), + Container( + decoration: highlight + ? BoxDecoration( + color: const Color(0xffFDCDCE), + borderRadius: BorderRadius.circular(6), + border: Border.all(color: Color(0xffEDEDED)) + ) + : null, + padding: + EdgeInsets.symmetric(horizontal: highlight ? 6 : 0, vertical: 2), + child: Text( + value, + style: GoogleFonts.poppins( + fontSize: size ?? 12.sp, + fontWeight: FontWeight.w400, + color: const Color(0xff2D3134), + ), + ), + ), + ], + ); + } +} + diff --git a/lib/postcard/views/postcard_creation_page_view.dart b/lib/postcard/views/postcard_creation_page_view.dart index 76b54a3..8f3ffc5 100644 --- a/lib/postcard/views/postcard_creation_page_view.dart +++ b/lib/postcard/views/postcard_creation_page_view.dart @@ -1,4 +1,7 @@ import 'package:citycards_customer/postcard/views/add_filter_step_page_view.dart'; +import 'package:citycards_customer/postcard/views/order_postcard_preview_page_view.dart'; +import 'package:citycards_customer/postcard/views/postcard_checkout_page_view.dart'; +import 'package:citycards_customer/postcard/views/postcard_purchase_form_page_view.dart'; import 'package:citycards_customer/postcard/views/preview_postcard_step_page_view.dart'; import 'package:citycards_customer/postcard/views/upload_photo_step_page_view.dart'; import 'package:citycards_customer/postcard/views/write_message_step_page_view.dart'; @@ -7,6 +10,8 @@ import 'package:flutter_bloc/flutter_bloc.dart'; import '../blocs/postcard_creation_bloc.dart'; import '../blocs/postcard_creation_state.dart'; +import 'my_orders_page_view.dart'; +import 'order_success_page_view.dart'; class PostcardCreationPage extends StatelessWidget { const PostcardCreationPage({super.key}); @@ -31,9 +36,21 @@ class PostcardCreationPage extends StatelessWidget { case PostcardStep.preview: stepWidget = const PreviewPostcardStepPageView(); break; - default: - stepWidget = const UploadPhotoStepPageView(); - } + case PostcardStep.purchase: + stepWidget = const PostcardPurchaseFormPageView(); + break; + case PostcardStep.checkout: + stepWidget = const PostcardCheckoutPageView(); + break; + case PostcardStep.orderSuccess: + stepWidget = const OrderSuccessPageView(); + break; + case PostcardStep.myOrders: + stepWidget = const MyOrdersPageView(); + break; + case PostcardStep.myOrderPostcardPreview: + stepWidget = const OrderPostcardPreviewPageView(); + } return Scaffold( backgroundColor: Colors.white, diff --git a/lib/postcard/views/postcard_purchase_form_page_view.dart b/lib/postcard/views/postcard_purchase_form_page_view.dart new file mode 100644 index 0000000..ad80259 --- /dev/null +++ b/lib/postcard/views/postcard_purchase_form_page_view.dart @@ -0,0 +1,262 @@ +import 'dart:io'; +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:google_fonts/google_fonts.dart'; +import '../../common_packages/app_bar.dart'; +import '../blocs/postcard_creation_bloc.dart'; +import '../blocs/postcard_creation_events.dart'; +import '../blocs/postcard_creation_state.dart'; + +class PostcardPurchaseFormPageView extends StatelessWidget { + const PostcardPurchaseFormPageView({super.key}); + + @override + Widget build(BuildContext context) { + return BlocBuilder( + builder: (context, state) { + final bloc = context.read(); + + return SafeArea( + child: SingleChildScrollView( + padding: const EdgeInsets.all(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + CommonAppBar(isWhiteLogo: false, isProfilePage: false), + + // Order ID + Text( + "#78895436", + style: TextStyle( + fontSize: 20.sp, + fontWeight: FontWeight.w600, + color: const Color(0xff1A1A1A), + ), + ), + const SizedBox(height: 20), + + // Postcard image + title + Row( + children: [ + ClipRRect( + borderRadius: BorderRadius.circular(8), + child: state.imagePath != null + ? Image.file( + File(state.imagePath!), + height: 70, + width: 70, + fit: BoxFit.cover, + ) + : Container( + height: 70, + width: 70, + color: const Color(0xffFEE7E7), + child: const Icon(Icons.image_outlined, + color: Color(0xffFDCDCE)), + ), + ), + const SizedBox(width: 16), + Expanded( + child: TextField( + decoration: InputDecoration( + hintText: "Add title", + hintStyle: GoogleFonts.poppins( + color: const Color(0xff999999), fontSize: 14.sp), + enabledBorder: const UnderlineInputBorder( + borderSide: + BorderSide(color: Color(0xffFDCDCE), width: 1), + ), + focusedBorder: const UnderlineInputBorder( + borderSide: + BorderSide(color: Color(0xffFDCDCE), width: 1), + ), + ), + style: GoogleFonts.poppins(fontSize: 14.sp), + onChanged: (val) { + // You can dispatch event here: bloc.add(UpdateTitle(val)); + }, + ), + ), + ], + ), + + const SizedBox(height: 28), + + // Personal details section + Text( + "Add personal details", + style: TextStyle( + fontSize: 16.sp, + fontWeight: FontWeight.w600, + color: const Color(0xff1A1A1A), + ), + ), + const SizedBox(height: 16), + + _buildInputField( + label: "Full Name", + hint: "Lorem Ipsum", + ), + _buildInputField( + label: "Email ID", + hint: "Lorem@gmail.com", + icon: Icons.email_outlined, + ), + _buildInputField( + label: "Phone number", + hint: "+91 9999 999 999", + icon: Icons.phone_outlined, + ), + + const SizedBox(height: 28), + + // Address details section + Text( + "Add address details", + style: TextStyle( + fontSize: 16.sp, + fontWeight: FontWeight.w600, + color: const Color(0xff1A1A1A), + ), + ), + const SizedBox(height: 16), + + _buildInputField(label: "City", hint: "Lorem Ipsum"), + _buildDropdownField(label: "Country", hint: "Lorem Ipsum"), + _buildDropdownField(label: "State", hint: "Lorem Ipsum"), + _buildInputField(label: "Zip Code", hint: "000000"), + + const SizedBox(height: 30), + + // Next Button + SizedBox( + width: double.infinity, + child: ElevatedButton( + onPressed: () { + bloc.add(GoToNextStep()); + }, + style: ElevatedButton.styleFrom( + backgroundColor: const Color(0xffF95F62), + padding: EdgeInsets.symmetric(vertical: 16.h), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(40), + ), + ), + child: Text( + "Next", + style: TextStyle( + color: Colors.white, + fontSize: 14.sp, + fontWeight: FontWeight.w600, + ), + ), + ), + ), + ], + ), + ), + ); + }, + ); + } + + /// ๐Ÿ”น Reusable text field widget + Widget _buildInputField({ + required String label, + required String hint, + IconData? icon, + }) { + return Padding( + padding: const EdgeInsets.only(bottom: 18), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + label, + style: GoogleFonts.poppins( + fontSize: 13.sp, + fontWeight: FontWeight.w500, + color: const Color(0xff1A1A1A), + ), + ), + const SizedBox(height: 6), + TextField( + decoration: InputDecoration( + hintText: hint, + hintStyle: GoogleFonts.poppins( + color: const Color(0xff999999), + fontSize: 14.sp, + ), + suffixIcon: icon != null + ? Icon(icon, color: Colors.black, size: 20) + : null, + contentPadding: + const EdgeInsets.symmetric(vertical: 14, horizontal: 12), + enabledBorder: OutlineInputBorder( + borderSide: const BorderSide(color: Color(0xffFDCDCE)), + borderRadius: BorderRadius.circular(8), + ), + focusedBorder: OutlineInputBorder( + borderSide: const BorderSide(color: Color(0xffFDCDCE)), + borderRadius: BorderRadius.circular(8), + ), + ), + ), + ], + ), + ); + } + + /// ๐Ÿ”น Dropdown input + Widget _buildDropdownField({ + required String label, + required String hint, + }) { + return Padding( + padding: const EdgeInsets.only(bottom: 18), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + label, + style: GoogleFonts.poppins( + fontSize: 13.sp, + fontWeight: FontWeight.w500, + color: const Color(0xff1A1A1A), + ), + ), + const SizedBox(height: 6), + DropdownButtonFormField( + value: null, + decoration: InputDecoration( + contentPadding: + const EdgeInsets.symmetric(vertical: 14, horizontal: 12), + enabledBorder: OutlineInputBorder( + borderSide: const BorderSide(color: Color(0xffFDCDCE)), + borderRadius: BorderRadius.circular(8), + ), + focusedBorder: OutlineInputBorder( + borderSide: const BorderSide(color: Color(0xffFDCDCE)), + borderRadius: BorderRadius.circular(8), + ), + ), + icon: const Icon(Icons.keyboard_arrow_down, + color: Color(0xffFDCDCE)), + hint: Text( + hint, + style: GoogleFonts.poppins( + color: const Color(0xff999999), + fontSize: 14.sp, + ), + ), + items: const [ + DropdownMenuItem(value: "Lorem Ipsum", child: Text("Lorem Ipsum")), + ], + onChanged: (val) {}, + ), + ], + ), + ); + } +} diff --git a/lib/postcard/views/preview_postcard_step_page_view.dart b/lib/postcard/views/preview_postcard_step_page_view.dart index fd1b9e5..5fb13bc 100644 --- a/lib/postcard/views/preview_postcard_step_page_view.dart +++ b/lib/postcard/views/preview_postcard_step_page_view.dart @@ -1,4 +1,5 @@ import 'dart:io'; +import 'package:citycards_customer/postcard/views/write_message_step_page_view.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; @@ -7,6 +8,7 @@ import 'package:google_fonts/google_fonts.dart'; import '../../common_packages/app_bar.dart'; import '../blocs/postcard_creation_bloc.dart'; import '../blocs/postcard_creation_state.dart'; +import '../widgets/postcard_preview_widget.dart'; import '../widgets/purchase_details_bottom_sheet.dart'; import '../widgets/step_progressbar.dart'; @@ -19,7 +21,7 @@ class PreviewPostcardStepPageView extends StatefulWidget { class _PreviewPostcardStepPageViewState extends State { - bool showImage = false; // โœ… tracks which side is visible + bool showImage = false; @override Widget build(BuildContext context) { @@ -55,51 +57,10 @@ class _PreviewPostcardStepPageViewState extends State false; -} diff --git a/lib/postcard/views/write_message_step_page_view.dart b/lib/postcard/views/write_message_step_page_view.dart index 5c50a12..6056744 100644 --- a/lib/postcard/views/write_message_step_page_view.dart +++ b/lib/postcard/views/write_message_step_page_view.dart @@ -6,6 +6,7 @@ import '../../common_packages/app_bar.dart'; import '../blocs/postcard_creation_bloc.dart'; import '../blocs/postcard_creation_events.dart'; import '../blocs/postcard_creation_state.dart'; +import '../widgets/postcard_preview_widget.dart'; import '../widgets/step_progressbar.dart'; class WriteMessageStepPageView extends StatefulWidget { @@ -81,7 +82,7 @@ class _WriteMessageStepPageViewState extends State { borderRadius: BorderRadius.circular(12), ), child: CustomPaint( - painter: _LinedPaperPainter(), + painter: LinedPaperPainter(), child: Padding( padding: const EdgeInsets.symmetric(horizontal: 8), child: TextField( @@ -210,20 +211,3 @@ class _WriteMessageStepPageViewState extends State { } } -/// ๐Ÿ–‹ Custom Painter for horizontal lines -class _LinedPaperPainter extends CustomPainter { - @override - void paint(Canvas canvas, Size size) { - final paint = Paint() - ..color = const Color(0xffE6DCDC) - ..strokeWidth = 1; - - const lineHeight = 36.0; // distance between lines - for (double y = 28; y < size.height; y += lineHeight) { - canvas.drawLine(Offset(0, y), Offset(size.width, y), paint); - } - } - - @override - bool shouldRepaint(covariant CustomPainter oldDelegate) => false; -} diff --git a/lib/postcard/widgets/postcard_preview_widget.dart b/lib/postcard/widgets/postcard_preview_widget.dart new file mode 100644 index 0000000..75e0a73 --- /dev/null +++ b/lib/postcard/widgets/postcard_preview_widget.dart @@ -0,0 +1,84 @@ +import 'dart:io'; + +import 'package:flutter/material.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:google_fonts/google_fonts.dart'; + +class PostCardPreviewWidget extends StatelessWidget { + final String imagePath; + final String message; + final String? selectedFont; + const PostCardPreviewWidget({super.key, required this.imagePath, required this.message, this.selectedFont}); + + @override + Widget build(BuildContext context) { + return Container( + padding: const EdgeInsets.all(12), + decoration: BoxDecoration( + color: const Color(0xFFFFF5F5), + borderRadius: BorderRadius.circular(12), + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + + ClipRRect( + borderRadius: BorderRadius.circular(8), + child: Image.file( + File(imagePath), + height: 140.h, + width: 140.w, + fit: BoxFit.cover, + ), + ), + const SizedBox(height: 12), + + CustomPaint( + painter: LinedPaperPainter(lineHeight: 28.0, topPadding: 38.0), + child: Container( + width: double.infinity, + padding: const EdgeInsets.symmetric( + horizontal: 10, + vertical: 12, + ), + child: Text( + message ?? "", + style: TextStyle( + fontFamily: selectedFont ?? + GoogleFonts.poppins().fontFamily, + fontSize: 16.sp, + color: const Color(0xff1A1A1A), + height: 1.6, + ), + ), + ), + ), + ], + ), + ); + } +} + +/// ๐Ÿ–‹ Custom Painter for horizontal lines +class LinedPaperPainter extends CustomPainter { + final double lineHeight; + final double topPadding; + + LinedPaperPainter({this.lineHeight = 26.0, this.topPadding = 18.0}); + + @override + void paint(Canvas canvas, Size size) { + final paint = Paint() + ..color = const Color(0xffE6DCDC) + ..strokeWidth = 1; + + // Draw lines spaced evenly based on text line height + for (double y = topPadding; y < size.height; y += lineHeight) { + canvas.drawLine(Offset(0, y), Offset(size.width, y), paint); + } + } + + @override + bool shouldRepaint(covariant CustomPainter oldDelegate) => false; +} + diff --git a/lib/postcard/widgets/purchase_details_bottom_sheet.dart b/lib/postcard/widgets/purchase_details_bottom_sheet.dart index 9b157ce..db0db34 100644 --- a/lib/postcard/widgets/purchase_details_bottom_sheet.dart +++ b/lib/postcard/widgets/purchase_details_bottom_sheet.dart @@ -22,6 +22,7 @@ class PurchaseDetailsBottomSheet { child: BlocBuilder( builder: (context, state) { final bloc = context.read(); + return Padding( padding: EdgeInsets.only( bottom: MediaQuery.of(context).viewInsets.bottom, @@ -106,7 +107,8 @@ class PurchaseDetailsBottomSheet { ), ElevatedButton( onPressed: () { - // TODO: Navigate to edit details screen + PurchaseDetailsBottomSheet.close(context); + bloc.add(GoToNextStep()); }, style: ElevatedButton.styleFrom( backgroundColor: const Color(0xffF95F62), @@ -180,4 +182,8 @@ class PurchaseDetailsBottomSheet { }, ); } + + static void close(BuildContext context) { + Navigator.of(context).pop(); + } }