diff --git a/lib/core/components/buttons.dart b/lib/core/components/buttons.dart index e763f81..e0614b1 100644 --- a/lib/core/components/buttons.dart +++ b/lib/core/components/buttons.dart @@ -20,6 +20,8 @@ class Button extends StatelessWidget { this.fontSize = 16.0, this.elevation, this.labelStyle, + this.mainAxisAlignment = MainAxisAlignment.center, + this.crossAxisAlignment = CrossAxisAlignment.center, }); const Button.outlined({ @@ -37,6 +39,8 @@ class Button extends StatelessWidget { this.fontSize = 16.0, this.elevation, this.labelStyle, + this.mainAxisAlignment = MainAxisAlignment.center, + this.crossAxisAlignment = CrossAxisAlignment.center, }); final Function() onPressed; @@ -52,6 +56,8 @@ class Button extends StatelessWidget { final bool disabled; final double fontSize; final TextStyle? labelStyle; + final MainAxisAlignment mainAxisAlignment; + final CrossAxisAlignment crossAxisAlignment; @override Widget build(BuildContext context) { @@ -70,8 +76,8 @@ class Button extends StatelessWidget { padding: const EdgeInsets.symmetric(horizontal: 16.0), ), child: Row( - mainAxisAlignment: MainAxisAlignment.center, - mainAxisSize: MainAxisSize.min, + mainAxisAlignment: mainAxisAlignment, + crossAxisAlignment: crossAxisAlignment, children: [ icon ?? const SizedBox.shrink(), if (icon != null) const SizedBox(width: 10.0), @@ -104,7 +110,8 @@ class Button extends StatelessWidget { padding: const EdgeInsets.symmetric(horizontal: 16.0), ), child: Row( - mainAxisAlignment: MainAxisAlignment.center, + mainAxisAlignment: mainAxisAlignment, + crossAxisAlignment: crossAxisAlignment, mainAxisSize: MainAxisSize.min, children: [ icon ?? const SizedBox.shrink(), diff --git a/lib/core/components/custom_modal_dialog.dart b/lib/core/components/custom_modal_dialog.dart new file mode 100644 index 0000000..f6cac75 --- /dev/null +++ b/lib/core/components/custom_modal_dialog.dart @@ -0,0 +1,96 @@ +import 'package:enaklo_pos/core/components/spaces.dart'; +import 'package:enaklo_pos/core/constants/colors.dart'; +import 'package:flutter/material.dart'; + +class CustomModalDialog extends StatelessWidget { + final String title; + final String? subtitle; + final Widget child; + final VoidCallback? onClose; + + const CustomModalDialog( + {super.key, + required this.title, + this.subtitle, + required this.child, + this.onClose}); + + @override + Widget build(BuildContext context) { + return Dialog( + backgroundColor: AppColors.white, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(16), + ), + child: ConstrainedBox( + constraints: BoxConstraints( + minWidth: 200, + maxWidth: 600, + minHeight: 200, + maxHeight: 600, + ), + child: Column( + children: [ + Container( + padding: const EdgeInsets.all(16), + width: double.infinity, + decoration: BoxDecoration( + gradient: LinearGradient( + colors: [ + AppColors.primary, + const Color.fromARGB(255, 67, 69, 195) + ], + begin: Alignment.topLeft, + end: Alignment.bottomRight, + ), + borderRadius: BorderRadius.vertical( + top: Radius.circular(16), + ), + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + title, + style: TextStyle( + color: AppColors.white, + fontSize: 20, + fontWeight: FontWeight.bold, + ), + ), + if (subtitle != null) + Text( + subtitle ?? '', + style: TextStyle( + color: AppColors.grey, + fontSize: 16, + ), + ), + ], + ), + ), + SpaceWidth(12), + IconButton( + icon: Icon(Icons.close, color: AppColors.white), + onPressed: () { + if (onClose != null) { + onClose!(); + } else { + Navigator.of(context).pop(); + } + }, + ), + ], + ), + ), + child, + ], + ), + ), + ); + } +} diff --git a/lib/core/constants/theme.dart b/lib/core/constants/theme.dart new file mode 100644 index 0000000..ca1c990 --- /dev/null +++ b/lib/core/constants/theme.dart @@ -0,0 +1,38 @@ +import 'package:enaklo_pos/core/constants/colors.dart'; +import 'package:flutter/material.dart'; +import 'package:google_fonts/google_fonts.dart'; + +ThemeData getApplicationTheme = ThemeData( + primaryColor: AppColors.primary, + scaffoldBackgroundColor: AppColors.white, + appBarTheme: AppBarTheme( + color: AppColors.white, + elevation: 0, + titleTextStyle: GoogleFonts.quicksand( + color: AppColors.primary, + fontSize: 16.0, + fontWeight: FontWeight.w500, + ), + iconTheme: const IconThemeData( + color: AppColors.primary, + ), + ), + fontFamily: GoogleFonts.quicksand().fontFamily, + colorScheme: ColorScheme.fromSeed(seedColor: AppColors.primary), + useMaterial3: true, + inputDecorationTheme: InputDecorationTheme( + contentPadding: const EdgeInsets.symmetric(horizontal: 16.0), + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(8.0), + borderSide: BorderSide(color: AppColors.primary), + ), + focusedBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(8.0), + borderSide: BorderSide(color: AppColors.primary), + ), + enabledBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(8.0), + borderSide: BorderSide(color: AppColors.primary), + ), + ), +); diff --git a/lib/main.dart b/lib/main.dart index fd244fe..d7f5452 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,4 +1,5 @@ import 'dart:developer'; +import 'package:enaklo_pos/core/constants/theme.dart'; import 'package:flutter/material.dart'; import 'package:enaklo_pos/data/datasources/auth_local_datasource.dart'; import 'package:enaklo_pos/data/datasources/auth_remote_datasource.dart'; @@ -57,7 +58,6 @@ import 'package:flutter_bloc/flutter_bloc.dart'; import 'presentation/home/pages/dashboard_page.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; - void main() async { WidgetsFlutterBinding.ensureInitialized(); // await LamanPrint.init(); @@ -110,7 +110,8 @@ class _MyAppState extends State { LocalProductBloc(ProductLocalDatasource.instance), ), BlocProvider( - create: (context) => CheckoutBloc(settingsLocalDatasource: SettingsLocalDatasource()), + create: (context) => + CheckoutBloc(settingsLocalDatasource: SettingsLocalDatasource()), ), BlocProvider( create: (context) => TaxSettingsBloc(SettingsLocalDatasource()), @@ -186,7 +187,8 @@ class _MyAppState extends State { create: (context) => QrisBloc(MidtransRemoteDatasource()), ), BlocProvider( - create: (context) => PaymentMethodsBloc(PaymentMethodsRemoteDatasource()), + create: (context) => + PaymentMethodsBloc(PaymentMethodsRemoteDatasource()), ), BlocProvider( create: (context) => OnlineCheckerBloc(), @@ -216,25 +218,7 @@ class _MyAppState extends State { child: MaterialApp( debugShowCheckedModeBanner: false, title: 'POS Resto App', - theme: ThemeData( - colorScheme: ColorScheme.fromSeed(seedColor: AppColors.primary), - useMaterial3: true, - textTheme: GoogleFonts.quicksandTextTheme( - Theme.of(context).textTheme, - ), - appBarTheme: AppBarTheme( - color: AppColors.white, - elevation: 0, - titleTextStyle: GoogleFonts.quicksand( - color: AppColors.primary, - fontSize: 16.0, - fontWeight: FontWeight.w500, - ), - iconTheme: const IconThemeData( - color: AppColors.primary, - ), - ), - ), + theme: getApplicationTheme, home: FutureBuilder( future: AuthLocalDataSource().isAuthDataExists(), builder: (context, snapshot) { diff --git a/lib/presentation/home/pages/home_page.dart b/lib/presentation/home/pages/home_page.dart index 4512fc0..daed74e 100644 --- a/lib/presentation/home/pages/home_page.dart +++ b/lib/presentation/home/pages/home_page.dart @@ -8,7 +8,6 @@ import 'package:enaklo_pos/core/extensions/int_ext.dart'; import 'package:enaklo_pos/core/extensions/string_ext.dart'; import 'package:enaklo_pos/data/models/response/table_model.dart'; import 'package:enaklo_pos/presentation/home/bloc/local_product/local_product_bloc.dart'; -import 'package:enaklo_pos/presentation/home/dialog/discount_dialog.dart'; import 'package:enaklo_pos/presentation/home/pages/confirm_payment_page.dart'; import 'package:enaklo_pos/data/datasources/product_local_datasource.dart'; import 'package:enaklo_pos/presentation/setting/bloc/sync_product/sync_product_bloc.dart'; @@ -19,7 +18,6 @@ import '../../../core/components/buttons.dart'; import '../../../core/components/spaces.dart'; import '../../../core/constants/colors.dart'; import '../bloc/checkout/checkout_bloc.dart'; -import '../dialog/service_dialog.dart'; import '../widgets/custom_tab_bar.dart'; import '../widgets/home_title.dart'; import '../widgets/order_menu.dart'; @@ -29,10 +27,10 @@ class HomePage extends StatefulWidget { final bool isTable; final TableModel? table; const HomePage({ - Key? key, + super.key, required this.isTable, this.table, - }) : super(key: key); + }); @override State createState() => _HomePageState(); @@ -94,7 +92,7 @@ class _HomePageState extends State { return Hero( tag: 'confirmation_screen', child: Scaffold( - backgroundColor: AppColors.background, + backgroundColor: AppColors.white, body: BlocListener( listener: (context, state) { state.maybeWhen( @@ -320,47 +318,61 @@ class _HomePageState extends State { color: Colors.white, child: Column( children: [ - Column( - children: [ - HomeRightTitle( - table: widget.table, - ), - Container( - padding: const EdgeInsets.all(16.0), - decoration: BoxDecoration( - border: Border( - bottom: BorderSide( - color: AppColors.grey, - width: 1.0, - ), - ), - ), - child: const Row( + HomeRightTitle( + table: widget.table, + ), + Padding( + padding: const EdgeInsets.all(16.0) + .copyWith(bottom: 0, top: 27), + child: Column( + children: [ + const Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( - "Order #", + 'Item', style: TextStyle( + color: AppColors.primary, fontSize: 16, - fontWeight: FontWeight.bold, + fontWeight: FontWeight.w600, ), ), - Text( - "Total: 0", - style: TextStyle( - fontSize: 16, - fontWeight: FontWeight.bold, + SizedBox( + width: 130, + ), + SizedBox( + width: 50.0, + child: Text( + 'Qty', + style: TextStyle( + color: AppColors.primary, + fontSize: 16, + fontWeight: FontWeight.w600, + ), + ), + ), + SizedBox( + child: Text( + 'Price', + style: TextStyle( + color: AppColors.primary, + fontSize: 16, + fontWeight: FontWeight.w600, + ), ), ), ], ), - ), - ], + const SpaceHeight(8), + const Divider(), + ], + ), ), Expanded( child: SingleChildScrollView( - padding: const EdgeInsets.all(16.0), + padding: + const EdgeInsets.all(16.0).copyWith(top: 0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -404,260 +416,109 @@ class _HomePageState extends State { ), ), ), - Column( - children: [ - Padding( - padding: const EdgeInsets.all(24.0), - child: Column( + Padding( + padding: const EdgeInsets.all(16.0).copyWith(top: 0), + child: Column( + children: [ + const Divider(), + const SpaceHeight(16.0), + Row( + mainAxisAlignment: + MainAxisAlignment.spaceBetween, children: [ - // Row( - // mainAxisAlignment: - // MainAxisAlignment.spaceEvenly, - // children: [ - // ColumnButton( - // label: 'Diskon', - // svgGenImage: Assets.icons.diskon, - // onPressed: () => showDialog( - // context: context, - // barrierDismissible: false, - // builder: (context) => - // const DiscountDialog(), - // ), - // ), - // ColumnButton( - // label: 'Pajak PB1', - // svgGenImage: Assets.icons.pajak, - // onPressed: () => showDialog( - // context: context, - // builder: (context) => - // const TaxDialog(), - // ), - // ), - // ColumnButton( - // label: 'Layanan', - // svgGenImage: Assets.icons.layanan, - // onPressed: () => showDialog( - // context: context, - // builder: (context) => - // const ServiceDialog(), - // ), - // ), - // ], - // ), - // const SpaceHeight(8.0), - // const Divider(), - // const SpaceHeight(8.0), - - Row( - mainAxisAlignment: - MainAxisAlignment.spaceBetween, - children: [ - const Text( - 'Sub total', - style: TextStyle( - color: AppColors.black, - fontWeight: FontWeight.bold, - ), - ), - BlocBuilder( - builder: (context, state) { - final price = state.maybeWhen( - orElse: () => 0, - loaded: (products, - discountModel, - discount, - discountAmount, - tax, - serviceCharge, - totalQuantity, - totalPrice, - draftName, - orderType) { - if (products.isEmpty) { - return 0; - } - return products - .map((e) => - e.product.price! - .toIntegerFromText * - e.quantity) - .reduce((value, element) => - value + element); - }); - - return Text( - price.currencyFormatRp, - style: const TextStyle( - color: AppColors.primary, - fontWeight: FontWeight.w900, - ), - ); - }, - ), - ], + const Text( + 'Pajak', + style: TextStyle( + color: AppColors.black, + fontWeight: FontWeight.bold, + ), ), - const SpaceHeight(8.0), - Row( - mainAxisAlignment: - MainAxisAlignment.spaceBetween, - children: [ - const Text( - 'Pajak PB1', - style: TextStyle( - color: AppColors.black, - fontWeight: FontWeight.bold, + BlocBuilder( + builder: (context, state) { + final tax = state.maybeWhen( + orElse: () => 0, + loaded: (products, + discountModel, + discount, + discountAmount, + tax, + serviceCharge, + totalQuantity, + totalPrice, + draftName, + orderType) { + if (products.isEmpty) { + return 0; + } + return tax; + }); + return Text( + '$tax %', + style: const TextStyle( + color: AppColors.primary, + fontWeight: FontWeight.w600, ), - ), - BlocBuilder( - builder: (context, state) { - final tax = state.maybeWhen( - orElse: () => 0, - loaded: (products, - discountModel, - discount, - discountAmount, - tax, - serviceCharge, - totalQuantity, - totalPrice, - draftName, - orderType) { - if (products.isEmpty) { - return 0; - } - return tax; - }); - return Text( - '$tax %', - style: const TextStyle( - color: AppColors.primary, - fontWeight: FontWeight.w600, - ), - ); - }, - ), - ], - ), - const SpaceHeight(8.0), - Row( - mainAxisAlignment: - MainAxisAlignment.spaceBetween, - children: [ - const Text( - 'Layanan', - style: TextStyle( - color: AppColors.black, - fontWeight: FontWeight.bold, - ), - ), - BlocBuilder( - builder: (context, state) { - final serviceCharge = state.maybeWhen( - orElse: () => 0, - loaded: (products, - discountModel, - discount, - discountAmount, - tax, - serviceCharge, - totalQuantity, - totalPrice, - draftName, - orderType) { - return serviceCharge; - }); - return Text( - '$serviceCharge %', - style: const TextStyle( - color: AppColors.primary, - fontWeight: FontWeight.w600, - ), - ); - }, - ), - ], - ), - const SpaceHeight(8.0), - Row( - mainAxisAlignment: MainAxisAlignment.end, - crossAxisAlignment: CrossAxisAlignment.end, - children: [ - _buildSmallButton( - onTap: () => showDialog( - context: context, - builder: (context) => - const ServiceDialog(), - ), - label: 'Layanan', - ), - SpaceWidth(8), - _buildSmallButton( - onTap: () => showDialog( - context: context, - builder: (context) => - const DiscountDialog(), - ), - label: 'Diskon', - ), - ], - ), - const SpaceHeight(8.0), - Row( - mainAxisAlignment: - MainAxisAlignment.spaceBetween, - children: [ - const Text( - 'Diskon', - style: TextStyle( - color: AppColors.black, - fontWeight: FontWeight.bold, - ), - ), - BlocBuilder( - builder: (context, state) { - final discount = state.maybeWhen( - orElse: () => 0, - loaded: (products, - discountModel, - discount, - discountAmount, - tax, - serviceCharge, - totalQuantity, - totalPrice, - draftName, - orderType) { - if (discountModel == null) { - return 0; - } - return discountModel.value! - .replaceAll('.00', '') - .toIntegerFromText; - }); - return Text( - '$discount %', - style: const TextStyle( - color: AppColors.primary, - fontWeight: FontWeight.w600, - ), - ); - }, - ), - ], + ); + }, ), ], ), - ), - Align( - alignment: Alignment.bottomCenter, - child: Container( - height: context.deviceHeight * 0.09, - width: double.infinity, - color: AppColors.white, + const SpaceHeight(16.0), + Row( + mainAxisAlignment: + MainAxisAlignment.spaceBetween, + children: [ + const Text( + 'Sub total', + style: TextStyle( + color: AppColors.black, + fontWeight: FontWeight.bold, + ), + ), + BlocBuilder( + builder: (context, state) { + final price = state.maybeWhen( + orElse: () => 0, + loaded: (products, + discountModel, + discount, + discountAmount, + tax, + serviceCharge, + totalQuantity, + totalPrice, + draftName, + orderType) { + if (products.isEmpty) { + return 0; + } + return products + .map((e) => + e.product.price! + .toIntegerFromText * + e.quantity) + .reduce((value, element) => + value + element); + }); + + return Text( + price.currencyFormatRp, + style: const TextStyle( + color: AppColors.primary, + fontWeight: FontWeight.w900, + ), + ); + }, + ), + ], + ), + SpaceHeight(16.0), + Align( + alignment: Alignment.bottomCenter, child: Expanded( child: Button.filled( - borderRadius: 0, - elevation: 0, + borderRadius: 12, + elevation: 1, onPressed: () { context.push(ConfirmPaymentPage( isTable: widget.isTable, @@ -668,8 +529,8 @@ class _HomePageState extends State { ), ), ), - ), - ], + ], + ), ), ], ), @@ -682,33 +543,6 @@ class _HomePageState extends State { ), ); } - - GestureDetector _buildSmallButton({ - required Function() onTap, - required String label, - }) { - return GestureDetector( - onTap: onTap, - child: Container( - padding: const EdgeInsets.symmetric( - horizontal: 10.0, - vertical: 6.0, - ), - decoration: BoxDecoration( - color: AppColors.primary.withOpacity(0.1), - borderRadius: BorderRadius.circular(8.0), - ), - child: Text( - label, - style: TextStyle( - color: AppColors.primary, - fontWeight: FontWeight.bold, - fontSize: 12.0, - ), - ), - ), - ); - } } class _IsEmpty extends StatelessWidget { diff --git a/lib/presentation/home/widgets/custom_tab_bar.dart b/lib/presentation/home/widgets/custom_tab_bar.dart index ba1bdcc..dd3d51b 100644 --- a/lib/presentation/home/widgets/custom_tab_bar.dart +++ b/lib/presentation/home/widgets/custom_tab_bar.dart @@ -105,17 +105,15 @@ class CustomTabBarV2 extends StatelessWidget { child: TabBar( isScrollable: true, tabAlignment: TabAlignment.start, - labelColor: Colors.white, + labelColor: AppColors.primary, labelStyle: TextStyle( fontWeight: FontWeight.bold, ), - dividerColor: Colors.transparent, + dividerColor: AppColors.primary, unselectedLabelColor: AppColors.primary, - indicator: BoxDecoration( - color: AppColors.primary, // Warna button saat aktif - borderRadius: BorderRadius.circular(8), - ), - indicatorColor: Colors.transparent, + indicatorSize: TabBarIndicatorSize.label, + indicatorWeight: 4, + indicatorColor: AppColors.primary, tabs: tabTitles .map((title) => Padding( padding: const EdgeInsets.symmetric(horizontal: 16), diff --git a/lib/presentation/home/widgets/home_right_title.dart b/lib/presentation/home/widgets/home_right_title.dart index ed4fdbd..b539f02 100644 --- a/lib/presentation/home/widgets/home_right_title.dart +++ b/lib/presentation/home/widgets/home_right_title.dart @@ -22,36 +22,92 @@ class HomeRightTitle extends StatelessWidget { ), ), ), - child: Row( + child: Column( + mainAxisSize: MainAxisSize.min, children: [ - Expanded( - child: Button.filled( - width: 180.0, - height: context.deviceHeight, - elevation: 0, - onPressed: () {}, - label: 'List Order', - ), + Row( + children: [ + Expanded( + child: Button.filled( + width: 180.0, + height: 40, + elevation: 0, + onPressed: () {}, + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + icon: Icon( + Icons.list, + color: Colors.white, + size: 24, + ), + label: 'Daftar Pesanan', + ), + ), + Expanded( + child: Button.filled( + width: 180.0, + height: 40, + elevation: 0, + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + icon: Icon( + Icons.person_outline, + color: Colors.white, + size: 24, + ), + onPressed: () { + if (table == null) { + context.push(DashboardPage( + index: 1, + )); + } + }, + label: 'Pelanggan', + ), + ), + ], ), - Container( - width: 1, - height: context.deviceHeight, - color: Colors.white, - ), - Expanded( - child: Button.filled( - width: 180.0, - height: context.deviceHeight, - elevation: 0, - onPressed: () { - if (table == null) { - context.push(DashboardPage( - index: 1, - )); - } - }, - label: table == null ? 'Pilih Meja' : '${table!.id}', - ), + Row( + children: [ + Expanded( + child: Button.filled( + width: 180.0, + height: 40, + elevation: 0, + onPressed: () {}, + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + icon: Icon( + Icons.dinner_dining_outlined, + color: Colors.white, + size: 24, + ), + label: 'Dine In', + ), + ), + Expanded( + child: Button.filled( + width: 180.0, + height: 40, + elevation: 0, + icon: Icon( + Icons.table_restaurant_outlined, + color: Colors.white, + size: 24, + ), + onPressed: () { + if (table == null) { + context.push(DashboardPage( + index: 1, + )); + } + }, + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + label: table == null ? 'Pilih Meja' : '${table!.id}', + ), + ), + ], ), ], ), diff --git a/lib/presentation/home/widgets/home_title.dart b/lib/presentation/home/widgets/home_title.dart index 356c232..135051d 100644 --- a/lib/presentation/home/widgets/home_title.dart +++ b/lib/presentation/home/widgets/home_title.dart @@ -1,6 +1,5 @@ import 'package:enaklo_pos/core/extensions/build_context_ext.dart'; import 'package:flutter/material.dart'; -import 'package:enaklo_pos/core/extensions/date_time_ext.dart'; import '../../../core/components/search_input.dart'; import '../../../core/constants/colors.dart'; @@ -21,37 +20,18 @@ class HomeTitle extends StatelessWidget { height: context.deviceHeight * 0.1, padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 12.0), decoration: BoxDecoration( - color: AppColors.primary, + color: AppColors.white, ), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Row( - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Icon(Icons.store, color: AppColors.white, size: 32.0), - SizedBox(width: 12), - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text( - 'Enaklo POS', - style: TextStyle( - color: AppColors.white, - fontSize: 22, - fontWeight: FontWeight.w600, - ), - ), - Text( - DateTime.now().toFormattedDate(), - style: TextStyle( - color: Colors.grey.shade300, - fontSize: 16, - ), - ), - ], - ), - ], + const Text( + 'DEFAULT OUTLET', + style: TextStyle( + color: AppColors.primary, + fontSize: 28, + fontWeight: FontWeight.w600, + ), ), SizedBox( width: 300.0, diff --git a/lib/presentation/home/widgets/order_menu.dart b/lib/presentation/home/widgets/order_menu.dart index 62629a0..a46bfa7 100644 --- a/lib/presentation/home/widgets/order_menu.dart +++ b/lib/presentation/home/widgets/order_menu.dart @@ -6,174 +6,41 @@ import 'package:enaklo_pos/core/extensions/int_ext.dart'; import 'package:enaklo_pos/core/extensions/string_ext.dart'; import 'package:enaklo_pos/presentation/home/bloc/checkout/checkout_bloc.dart'; import 'package:enaklo_pos/presentation/home/models/product_quantity.dart'; -import 'package:enaklo_pos/presentation/home/widgets/item_notes_dialog.dart'; import '../../../core/components/spaces.dart'; import '../../../core/constants/colors.dart'; -class OrderMenu extends StatelessWidget { +class OrderMenu extends StatefulWidget { final ProductQuantity data; const OrderMenu({super.key, required this.data}); @override - Widget build(BuildContext context) { - return Container( - padding: EdgeInsets.all(16.0), - margin: EdgeInsets.only(bottom: 8.0), - decoration: BoxDecoration( - color: AppColors.primary.withOpacity(0.1), - borderRadius: BorderRadius.circular(8.0), - ), - child: Column( - children: [ - Row( - children: [ - Expanded( - child: Text( - data.product.name ?? "_", - overflow: TextOverflow.ellipsis, - maxLines: 2, - style: const TextStyle( - fontSize: 16, - fontWeight: FontWeight.bold, - ), - ), - ), - SizedBox(width: 12.0), - _buildIconButton( - onTap: () { - showDialog( - context: context, - builder: (context) => ItemNotesDialog(item: data), - ); - }, - icon: Icons.edit_note, - ), - SizedBox(width: 8.0), - _buildIconButton( - onTap: () {}, - icon: Icons.delete_outline, - iconColor: AppColors.red, - ), - ], - ), - const SpaceHeight(12.0), - Row( - children: [ - Expanded( - child: Text( - (data.product.price!.toIntegerFromText * data.quantity) - .currencyFormatRp, - overflow: TextOverflow.ellipsis, - maxLines: 2, - style: const TextStyle( - color: AppColors.primary, - fontWeight: FontWeight.bold, - ), - ), - ), - SpaceWidth(16), - Container( - padding: const EdgeInsets.all(4), - decoration: BoxDecoration( - color: AppColors.white, - borderRadius: BorderRadius.circular(50.0), - ), - child: Row( - children: [ - _buildIconButton( - onTap: () { - context - .read() - .add(CheckoutEvent.removeItem(data.product)); - }, - icon: Icons.remove, - iconColor: AppColors.primary, - bgColor: Colors.grey.shade300, - ), - SizedBox( - width: 30.0, - child: Center( - child: Text( - data.quantity.toString(), - style: const TextStyle( - fontWeight: FontWeight.bold, - ), - ), - ), - ), - _buildIconButton( - onTap: () { - context - .read() - .add(CheckoutEvent.addItem(data.product)); - }, - icon: Icons.add, - iconColor: AppColors.white, - bgColor: AppColors.primary, - ), - ], - ), - ), - ], - ), - if (data.notes.isNotEmpty) ...[ - SpaceHeight(8.0), - Divider(), - SpaceHeight(8.0), - Container( - width: double.infinity, - padding: const EdgeInsets.symmetric( - horizontal: 8.0, - vertical: 4.0, - ), - decoration: BoxDecoration( - color: AppColors.white, - borderRadius: BorderRadius.circular(8.0), - ), - child: Text( - 'Notes: ${data.notes}', - style: const TextStyle( - fontSize: 14, - color: AppColors.black, - fontWeight: FontWeight.w500, - fontStyle: FontStyle.italic, - ), - ), - ), - ], - ], - ), - ); - } - - GestureDetector _buildIconButton({ - required Function()? onTap, - Color iconColor = AppColors.black, - Color bgColor = AppColors.white, - required IconData icon, - }) { - return GestureDetector( - onTap: onTap, - child: Container( - padding: const EdgeInsets.all(4.0), - decoration: BoxDecoration( - color: bgColor, - shape: BoxShape.circle, - ), - child: Icon( - icon, - size: 20, - color: iconColor, - ), - ), - ); - } + State createState() => _OrderMenuState(); } -class OrderMenuOld extends StatelessWidget { - final ProductQuantity data; - const OrderMenuOld({super.key, required this.data}); +class _OrderMenuState extends State { + final _controller = TextEditingController(); + + @override + void initState() { + super.initState(); + _controller.text = widget.data.notes; + + _controller.addListener(() { + context.read().add( + CheckoutEvent.updateItemNotes( + widget.data.product, + _controller.text, + ), + ); + }); + } + + @override + void dispose() { + _controller.dispose(); + super.dispose(); + } @override Widget build(BuildContext context) { @@ -193,9 +60,9 @@ class OrderMenuOld extends StatelessWidget { // color: AppColors.primary, // ), CachedNetworkImage( - imageUrl: data.product.image!.contains('http') - ? data.product.image! - : '${Variables.baseUrl}/${data.product.image}', + imageUrl: widget.data.product.image!.contains('http') + ? widget.data.product.image! + : '${Variables.baseUrl}/${widget.data.product.image}', width: 50.0, height: 50.0, fit: BoxFit.cover, @@ -206,55 +73,21 @@ class OrderMenuOld extends StatelessWidget { title: Row( children: [ Expanded( - child: Text(data.product.name ?? "-", - maxLines: 2, + child: Text(widget.data.product.name ?? "-", + maxLines: 1, overflow: TextOverflow.ellipsis, style: const TextStyle( fontSize: 14, fontWeight: FontWeight.bold, )), ), - GestureDetector( - onTap: () { - showDialog( - context: context, - builder: (context) => ItemNotesDialog(item: data), - ); - }, - child: const Icon( - Icons.edit_note, - size: 20, - color: AppColors.primary, - ), - ), ], ), subtitle: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text( - data.product.price!.toIntegerFromText.currencyFormatRp), - if (data.notes.isNotEmpty) ...[ - const SpaceHeight(4.0), - Container( - padding: const EdgeInsets.symmetric( - horizontal: 8.0, - vertical: 4.0, - ), - decoration: BoxDecoration( - color: AppColors.primary.withOpacity(0.1), - borderRadius: BorderRadius.circular(4.0), - ), - child: Text( - 'Notes: ${data.notes}', - style: const TextStyle( - fontSize: 12, - color: AppColors.primary, - fontStyle: FontStyle.italic, - ), - ), - ), - ], + Text(widget.data.product.price!.toIntegerFromText + .currencyFormatRp), ], ), ), @@ -265,7 +98,7 @@ class OrderMenuOld extends StatelessWidget { onTap: () { context .read() - .add(CheckoutEvent.removeItem(data.product)); + .add(CheckoutEvent.removeItem(widget.data.product)); }, child: Container( width: 30, @@ -281,14 +114,14 @@ class OrderMenuOld extends StatelessWidget { width: 30.0, child: Center( child: Text( - data.quantity.toString(), + widget.data.quantity.toString(), )), ), GestureDetector( onTap: () { context .read() - .add(CheckoutEvent.addItem(data.product)); + .add(CheckoutEvent.addItem(widget.data.product)); }, child: Container( width: 30, @@ -306,7 +139,8 @@ class OrderMenuOld extends StatelessWidget { SizedBox( width: 80.0, child: Text( - (data.product.price!.toIntegerFromText * data.quantity) + (widget.data.product.price!.toIntegerFromText * + widget.data.quantity) .currencyFormatRp, textAlign: TextAlign.right, style: const TextStyle( @@ -317,6 +151,40 @@ class OrderMenuOld extends StatelessWidget { ), ], ), + SpaceHeight(8.0), + SizedBox( + height: 40, + child: Row( + children: [ + Flexible( + child: TextFormField( + cursorColor: AppColors.primary, + controller: _controller, + style: const TextStyle( + fontSize: 12, + color: AppColors.black, + ), + decoration: InputDecoration( + hintText: 'Catatan Pesanan', + ), + ), + ), + const SpaceWidth(16.0), + Container( + height: 40, + width: 40, + decoration: BoxDecoration( + color: AppColors.primary, + borderRadius: BorderRadius.circular(8.0), + ), + child: Icon( + Icons.delete_outline, + color: AppColors.white, + ), + ), + ], + ), + ) ], ); } diff --git a/lib/presentation/home/widgets/product_card.dart b/lib/presentation/home/widgets/product_card.dart index c8d4bdd..78655e9 100644 --- a/lib/presentation/home/widgets/product_card.dart +++ b/lib/presentation/home/widgets/product_card.dart @@ -1,5 +1,4 @@ import 'package:cached_network_image/cached_network_image.dart'; -import 'package:enaklo_pos/core/extensions/build_context_ext.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:enaklo_pos/core/constants/variables.dart'; @@ -8,97 +7,14 @@ import 'package:enaklo_pos/core/extensions/string_ext.dart'; import 'package:enaklo_pos/data/models/response/product_response_model.dart'; import 'package:enaklo_pos/presentation/home/bloc/checkout/checkout_bloc.dart'; -import '../../../core/assets/assets.gen.dart'; import '../../../core/components/spaces.dart'; import '../../../core/constants/colors.dart'; class ProductCard extends StatelessWidget { final Product data; final VoidCallback onCartButton; - const ProductCard( - {super.key, required this.data, required this.onCartButton}); - @override - Widget build(BuildContext context) { - return GestureDetector( - onTap: () { - context.read().add(CheckoutEvent.addItem(data)); - }, - child: Container( - padding: const EdgeInsets.all(8.0), - decoration: BoxDecoration( - color: AppColors.white, - borderRadius: BorderRadius.circular(12.0), - ), - child: Column( - children: [ - AspectRatio( - aspectRatio: 1.2, - child: ClipRRect( - borderRadius: BorderRadius.circular(12), - child: CachedNetworkImage( - imageUrl: data.image!.contains('http') - ? data.image! - : '${Variables.baseUrl}/${data.image}', - width: double.infinity, - height: context.deviceHeight * 0.18, - fit: BoxFit.cover, - errorWidget: (context, url, error) => Container( - width: double.infinity, - height: context.deviceHeight * 0.18, - decoration: BoxDecoration( - color: AppColors.grey.withOpacity(0.1), - borderRadius: BorderRadius.circular(12), - ), - child: const Icon( - Icons.image_outlined, - color: AppColors.grey, - size: 40, - ), - ), - ), - ), - ), - const SpaceHeight(8.0), - Row( - children: [ - Expanded( - child: Text( - "${data.name}", - style: const TextStyle( - fontSize: 14, - fontWeight: FontWeight.w700, - ), - maxLines: 2, - overflow: TextOverflow.ellipsis, - ), - ), - ], - ), - Spacer(), - const SpaceHeight(4.0), - Align( - alignment: Alignment.centerRight, - child: Text( - data.price!.toIntegerFromText.currencyFormatRp, - style: const TextStyle( - fontWeight: FontWeight.bold, - fontSize: 13, - color: AppColors.primary, - ), - ), - ), - ], - ), - )); - } -} - -class ProductCardOld extends StatelessWidget { - final Product data; - final VoidCallback onCartButton; - - const ProductCardOld({ + const ProductCard({ super.key, required this.data, required this.onCartButton, @@ -115,6 +31,9 @@ class ProductCardOld extends StatelessWidget { decoration: BoxDecoration( color: AppColors.white, borderRadius: BorderRadius.circular(12.0), + border: Border.all( + color: AppColors.disabled, + ), ), child: Stack( children: [ @@ -160,28 +79,29 @@ class ProductCardOld extends StatelessWidget { overflow: TextOverflow.ellipsis, ), const Spacer(), - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Flexible( - child: Text( - data.category?.name ?? '-', - style: const TextStyle( - color: AppColors.grey, - fontSize: 12, - ), - ), + Align( + alignment: Alignment.center, + child: Text( + data.category?.name ?? '-', + style: const TextStyle( + fontSize: 14, + color: AppColors.grey, + fontWeight: FontWeight.w500, ), - Flexible( - child: Text( - data.price!.toIntegerFromText.currencyFormatRp, - style: const TextStyle( - fontWeight: FontWeight.bold, - fontSize: 13, - ), - ), + maxLines: 2, + overflow: TextOverflow.ellipsis, + ), + ), + const Spacer(), + Align( + alignment: Alignment.center, + child: Text( + data.price!.toIntegerFromText.currencyFormatRp, + style: const TextStyle( + fontWeight: FontWeight.bold, + fontSize: 13, ), - ], + ), ), const Spacer(), ], @@ -232,34 +152,8 @@ class ProductCardOld extends StatelessWidget { ), ), ) - : Align( - alignment: Alignment.topRight, - child: Container( - width: 36, - height: 36, - padding: const EdgeInsets.all(6), - decoration: const BoxDecoration( - borderRadius: - BorderRadius.all(Radius.circular(9.0)), - color: AppColors.primary, - ), - child: Assets.icons.shoppingBasket.svg(), - ), - ) - : Align( - alignment: Alignment.topRight, - child: Container( - width: 36, - height: 36, - padding: const EdgeInsets.all(6), - decoration: const BoxDecoration( - borderRadius: - BorderRadius.all(Radius.circular(9.0)), - color: AppColors.primary, - ), - child: Assets.icons.shoppingBasket.svg(), - ), - ); + : SizedBox.shrink() + : SizedBox.shrink(); }, ); }, diff --git a/lib/presentation/setting/widgets/menu_product_item.dart b/lib/presentation/setting/widgets/menu_product_item.dart index 734e02d..1e1d67b 100644 --- a/lib/presentation/setting/widgets/menu_product_item.dart +++ b/lib/presentation/setting/widgets/menu_product_item.dart @@ -102,79 +102,79 @@ class MenuProductItem extends StatelessWidget { child: GestureDetector( onTap: () { showDialog( - context: context, - // backgroundColor: AppColors.white, - builder: (context) { - //container for product detail - return AlertDialog( - contentPadding: const EdgeInsets.all(16.0), - content: Column( - mainAxisSize: MainAxisSize.min, - children: [ - Row( - mainAxisAlignment: - MainAxisAlignment.spaceBetween, - children: [ - Text( - data.name!, - style: const TextStyle( - fontSize: 20, - ), + context: context, + builder: (context) { + //container for product detail + return AlertDialog( + backgroundColor: AppColors.white, + contentPadding: const EdgeInsets.all(16.0), + content: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Row( + mainAxisAlignment: + MainAxisAlignment.spaceBetween, + children: [ + Text( + data.name!, + style: const TextStyle( + fontSize: 20, ), - IconButton( - onPressed: () { - Navigator.pop(context); - }, - icon: const Icon(Icons.close), - ), - ], - ), - const SpaceHeight(10.0), - ClipRRect( - borderRadius: const BorderRadius.all( - Radius.circular(10.0)), - child: CachedNetworkImage( - imageUrl: - '${Variables.baseUrl}${data.image}', - placeholder: (context, url) => const Center( - child: CircularProgressIndicator()), - errorWidget: (context, url, error) => - const Icon( - Icons.food_bank_outlined, - size: 80, - ), - width: 80, ), - ), - const SpaceHeight(10.0), - Text( - data.category?.name ?? '-', - style: const TextStyle( - fontSize: 12, - color: Colors.grey, + IconButton( + onPressed: () { + Navigator.pop(context); + }, + icon: const Icon(Icons.close), ), - ), - const SpaceHeight(10.0), - Text( - data.price.toString(), - style: const TextStyle( - fontSize: 12, - color: Colors.grey, + ], + ), + const SpaceHeight(10.0), + ClipRRect( + borderRadius: const BorderRadius.all( + Radius.circular(10.0)), + child: CachedNetworkImage( + imageUrl: '${Variables.baseUrl}${data.image}', + placeholder: (context, url) => const Center( + child: CircularProgressIndicator()), + errorWidget: (context, url, error) => + const Icon( + Icons.food_bank_outlined, + size: 80, ), + width: 80, ), - const SpaceHeight(10.0), - Text( - data.stock.toString(), - style: const TextStyle( - fontSize: 12, - color: Colors.grey, - ), + ), + const SpaceHeight(10.0), + Text( + data.category?.name ?? '-', + style: const TextStyle( + fontSize: 12, + color: Colors.grey, ), - const SpaceHeight(10.0), - ], - ), - ); - }); + ), + const SpaceHeight(10.0), + Text( + data.price.toString(), + style: const TextStyle( + fontSize: 12, + color: Colors.grey, + ), + ), + const SpaceHeight(10.0), + Text( + data.stock.toString(), + style: const TextStyle( + fontSize: 12, + color: Colors.grey, + ), + ), + const SpaceHeight(10.0), + ], + ), + ); + }, + ); }, child: Container( padding: const EdgeInsets.symmetric(vertical: 4),