diff --git a/app_petty_cash/lib/app/constant.dart b/app_petty_cash/lib/app/constant.dart index 1d8499b..4dd813f 100644 --- a/app_petty_cash/lib/app/constant.dart +++ b/app_petty_cash/lib/app/constant.dart @@ -10,7 +10,7 @@ class Constant { static double designWidthPhone = 390; static String bearerName = "petty-cash"; - static String version = "2.00"; + static String version = "1.00"; // static String baseUrl = "https://devregonline.pramita.co.id/one-api/xdoc/"; @@ -125,7 +125,7 @@ class Constant { // static String baseUrl_appdoctor = // "http://balikpapan.bisone2.pramitalab.id/one-api/app_doctor/"; - + // // * padang // static String baseUrl = // "http://padang.bisone4.pramitalab.id/one-api-doctor/doctor_mitra/"; @@ -154,12 +154,12 @@ class Constant { // static String baseUrl_appdoctor = // "http://manado.bisone2.pramitalab.id/one-api/app_doctor/"; - // * bekasi + // * bekasi // static String baseUrl = // "http://bekasiraya.bisone2.pramitalab.id/one-api-doctor/doctor_mitra/"; // static String baseUrl_appdoctor = - // "http://bekasiraya.bisone2.pramitalab.id/one-api/app_doctor/"; + // "http://bekasiraya.bisone2.pramitalab.id/one-api/app_doctor/"; //color Theme // login marketing @@ -255,6 +255,9 @@ class Constant { static Color textWhite = Color(0xffFDFDFD); static Color textGreen = Color(0xff0BAF48); + // background upload file + static Color bgUploadFile = Color(0xffF5F5F5); + //typoGraphy static TextStyle titleH1Login({required BuildContext context}) { return TextStyle( @@ -362,6 +365,13 @@ class Constant { ); } + static TextStyle titleH1Login_SelamatDatang({required BuildContext context}) { + return TextStyle( + fontSize: Constant.getActualYPhone(context: context, y: 32), + fontWeight: FontWeight.w500, + ); + } + static TextStyle titleH1_600({required BuildContext context}) { return TextStyle( fontSize: Constant.getActualYPhone(context: context, y: 36), diff --git a/app_petty_cash/lib/app/route.dart b/app_petty_cash/lib/app/route.dart index 374826e..889aa71 100644 --- a/app_petty_cash/lib/app/route.dart +++ b/app_petty_cash/lib/app/route.dart @@ -1,7 +1,8 @@ -import 'package:app_petty_cash/screen/home/home_screen.dart'; -import 'package:app_petty_cash/screen/transaksi/transaksi_screen.dart'; +import 'package:app_petty_cash/screen/user/user_screen.dart'; import 'package:flutter/material.dart'; +import '../screen/home/home_screen.dart'; +import '../screen/transaksi/transaksi_screen.dart'; import '../screen/login/login_screen.dart'; import '../screen/splash/splash_screen.dart'; import '../screen/test_file_picker/test_file_picker.dart'; @@ -11,6 +12,9 @@ const menuRoute = "/menuRoute"; const splashScreen = "/splashScreen"; const homeRoute = "/homeRoute"; const transaksiRoute = "/transaksiRoute"; +const userRoute = "/userRoute"; + +// test screen const testFilePickerRoute = "/testFilePickerRoute"; class AppRoute { @@ -28,6 +32,19 @@ class AppRoute { }); } + // user screen + if (settings.name == userRoute) { + return MaterialPageRoute(builder: (context) { + return MediaQuery( + data: MediaQuery.of(context).copyWith( + textScaleFactor: 1.0, + padding: EdgeInsets.all(0), + ), + child: UserScreen(), + ); + }); + } + // home screen if (settings.name == homeRoute) { return MaterialPageRoute(builder: (context) { @@ -41,7 +58,7 @@ class AppRoute { }); } - // tansaksi screen + // transaksi screen if (settings.name == transaksiRoute) { return MaterialPageRoute(builder: (context) { return MediaQuery( diff --git a/app_petty_cash/lib/main.dart b/app_petty_cash/lib/main.dart index 6d696b1..c3d8767 100644 --- a/app_petty_cash/lib/main.dart +++ b/app_petty_cash/lib/main.dart @@ -1,12 +1,20 @@ import 'package:flutter/material.dart'; import 'package:flutter/gestures.dart'; +import 'package:flutter/services.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'app/route.dart'; void main() async { WidgetsFlutterBinding.ensureInitialized(); + SystemChrome.setSystemUIOverlayStyle(const SystemUiOverlayStyle( + statusBarIconBrightness: + Brightness.dark, // this will change the brightness of the icons + statusBarColor: Colors.white, // or any color you want + )); runApp( - const ProviderScope(child: MyApp()), + const ProviderScope( + child: MyApp(), + ), ); } @@ -18,7 +26,8 @@ class MyApp extends StatelessWidget { return MaterialApp( title: 'App Petty Cash', theme: ThemeData( - primarySwatch: Colors.red, + // primarySwatch: Colors.red, + primarySwatch: Colors.orange, ), scrollBehavior: MaterialScrollBehavior().copyWith( dragDevices: { @@ -31,8 +40,8 @@ class MyApp extends StatelessWidget { debugShowCheckedModeBanner: false, // initialRoute: loginRoute, // initialRoute: splashScreen, - // initialRoute: transaksiRoute, - initialRoute: testFilePickerRoute, + initialRoute: transaksiRoute, + // initialRoute: testFilePickerRoute, onGenerateRoute: AppRoute.generateRoute, ); } diff --git a/app_petty_cash/lib/screen/home/home_screen.dart b/app_petty_cash/lib/screen/home/home_screen.dart index 3dedaff..cf5fc39 100644 --- a/app_petty_cash/lib/screen/home/home_screen.dart +++ b/app_petty_cash/lib/screen/home/home_screen.dart @@ -1,65 +1,28 @@ -import 'package:app_petty_cash/app/route.dart'; import 'package:flutter/material.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; -class HomeScreen extends StatelessWidget { +import '../../app/constant.dart'; +import '../../widget/custom_drawer.dart'; + +class HomeScreen extends HookConsumerWidget { const HomeScreen({super.key}); @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - title: Text('Home Screen'), + Widget build(BuildContext context, WidgetRef ref) { + return Padding( + padding: EdgeInsets.only( + top: Constant.getActualYPhone(context: context, y: 30), ), - drawer: Drawer( - child: ListView( - padding: EdgeInsets.zero, - children: [ - DrawerHeader( - decoration: BoxDecoration( - color: Colors.blue, - ), - child: Text( - 'Drawer Header', - style: TextStyle( - color: Colors.white, - fontSize: 24, - ), - ), - ), - ListTile( - title: Text('Home'), - onTap: () { - // Handle navigation to Home screen - Navigator.pop(context); - Navigator.pushNamed(context, homeRoute); - }, - ), - ListTile( - title: Text('Transaksi'), - onTap: () { - // Handle navigation to Transaksi screen - Navigator.pop(context); - }, - ), - ListTile( - title: Text('User'), - onTap: () { - // Handle navigation to User screen - Navigator.pop(context); - }, - ), - ListTile( - title: Text('Logout'), - onTap: () { - // Handle logout logic - Navigator.pop(context); - }, - ), - ], + child: Scaffold( + appBar: AppBar( + title: Text('Home Screen'), + ), + drawer: CustomDrawer(), + body: SafeArea( + child: Center( + child: Text('Home Screen Content'), + ), ), - ), - body: Center( - child: Text('Home Screen Content'), ), ); } diff --git a/app_petty_cash/lib/screen/login/block_bodyv2.dart b/app_petty_cash/lib/screen/login/block_bodyv2.dart index 6c35c48..cb9f574 100644 --- a/app_petty_cash/lib/screen/login/block_bodyv2.dart +++ b/app_petty_cash/lib/screen/login/block_bodyv2.dart @@ -97,24 +97,24 @@ class BlockBodyV2 extends HookConsumerWidget { SizedBox( height: Constant.getActualYPhone(context: context, y: 30), ), - Padding( - padding: EdgeInsets.only( - left: Constant.getActualXPhone(context: context, x: 40), - right: Constant.getActualXPhone(context: context, x: 40), - ), - child: Container( - width: Constant.getActualXPhone(context: context, x: 283), - height: Constant.getActualYPhone(context: context, y: 100), - decoration: BoxDecoration( - // color: Colors.green, - image: DecorationImage( - fit: BoxFit.fitWidth, - // image: AssetImage('images/logo_pramita.png'), - image: AssetImage('images/logo_gabung_bg_png.png'), - ), - ), - ), - ), + // Padding( + // padding: EdgeInsets.only( + // left: Constant.getActualXPhone(context: context, x: 40), + // right: Constant.getActualXPhone(context: context, x: 40), + // ), + // child: Container( + // width: Constant.getActualXPhone(context: context, x: 283), + // height: Constant.getActualYPhone(context: context, y: 100), + // decoration: BoxDecoration( + // // color: Colors.green, + // image: DecorationImage( + // fit: BoxFit.fitWidth, + // // image: AssetImage('images/logo_pramita.png'), + // image: AssetImage('images/logo_gabung_bg_png.png'), + // ), + // ), + // ), + // ), SizedBox( height: Constant.getActualYPhone(context: context, y: 60), ), @@ -135,7 +135,7 @@ class BlockBodyV2 extends HookConsumerWidget { .copyWith(color: Constant.subTitleBlack), ), Text( - " DOKTER", + " PETTYCASH", style: Constant.titleH3_700V2(context: context).copyWith( color: Color(0xffd70302), ), diff --git a/app_petty_cash/lib/screen/login/login_form.dart b/app_petty_cash/lib/screen/login/login_form.dart new file mode 100644 index 0000000..6690a96 --- /dev/null +++ b/app_petty_cash/lib/screen/login/login_form.dart @@ -0,0 +1,371 @@ +// ignore_for_file: prefer_const_constructors, use_full_hex_values_for_flutter_colors + +import 'dart:async'; + +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; + +import '../../app/constant.dart'; +import '../../app/route.dart'; +import '../../provider/current_menu_provider.dart'; +import '../../provider/current_user_provider.dart'; +import 'custom_text_field.dart'; +import 'login_provider.dart'; + +class LoginFormScreen extends HookConsumerWidget { + const LoginFormScreen({ + Key? key, + }) : super(key: key); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final isPasswordObscured = useState(true); + final ctrlEmail = useTextEditingController(text: ""); + final ctrlDokterId = useTextEditingController(text: ""); + final ctrlPassword = useTextEditingController(text: ""); + final isLoading = useState(false); + final errorMessage = useState(""); + final isSuccess = useState(false); + final focusNodeDokterID = useFocusNode(); + final focusNodeDokterUsername = useFocusNode(); + final focusNodeDokterPassword = useFocusNode(); + + final dokterIDhasFocus = useState(false); + final usernamehasFocus = useState(false); + final passwordhasFocus = useState(false); + + focusNodeDokterID.addListener(() { + if (focusNodeDokterID.hasPrimaryFocus) { + dokterIDhasFocus.value = true; + usernamehasFocus.value = false; + passwordhasFocus.value = false; + } else { + dokterIDhasFocus.value = false; + } + }); + + focusNodeDokterUsername.addListener(() { + if (focusNodeDokterUsername.hasFocus) { + dokterIDhasFocus.value = false; + usernamehasFocus.value = true; + passwordhasFocus.value = false; + } else { + usernamehasFocus.value = false; + } + }); + + focusNodeDokterPassword.addListener(() { + if (focusNodeDokterPassword.hasFocus) { + dokterIDhasFocus.value = false; + usernamehasFocus.value = false; + passwordhasFocus.value = true; + } else { + passwordhasFocus.value = false; + } + }); + + ref.listen(loginProvider, (prev, next) { + if (next is LoginStateLoading) { + isLoading.value = true; + } else if (next is LoginStateError) { + isLoading.value = false; + errorMessage.value = next.message; + Timer(const Duration(seconds: 3), () { + errorMessage.value = ""; + }); + } else if (next is LoginStateDone) { + isLoading.value = false; + isSuccess.value = true; + ref.read(currentPageProvider.state).update((state) => 0); + ref.read(currentUserProvider.notifier).state = next.model; + + // print(next.model.model.doctorName); + + // Navigator.of(context).pop(); + // Navigator.of(context).pushNamedAndRemoveUntil(menuRoute,(route) => true,); + // Navigator.popAndPushNamed(context,menuRoute); + + Navigator.of(context) + .pushNamedAndRemoveUntil(menuRoute, (route) => false); + } + }); + + return Scaffold( + body: SafeArea( + child: SingleChildScrollView( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Container( + width: Constant.getActualXPhone(context: context, x: 390), + height: Constant.getActualYPhone(context: context, y: 359), + decoration: BoxDecoration(color: Colors.grey), + ), + Container( + width: Constant.getActualXPhone(context: context, x: 390), + height: Constant.getActualYPhone(context: context, y: 485), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Padding( + padding: EdgeInsets.only( + top: Constant.getActualYPhone(context: context, y: 63), + left: Constant.getActualXPhone(context: context, x: 20), + right: + Constant.getActualXPhone(context: context, x: 113), + ), + child: Text( + 'Selamat Datang', + style: Constant.titleH1Login_SelamatDatang( + context: context) + .copyWith( + fontWeight: FontWeight.w600, + color: Constant.textBlack), + ), + ), + Padding( + padding: EdgeInsets.only( + // top: Constant.getActualYPhone(context: context, y: 63), + left: Constant.getActualXPhone(context: context, x: 20), + right: + Constant.getActualXPhone(context: context, x: 48), + ), + child: Text( + 'Silahkan masuk untuk mengakses akun Anda', + style: Constant.body1(context: context).copyWith( + fontWeight: FontWeight.w600, + color: Constant.textBlack), + ), + ), + SizedBox( + height: Constant.getActualYPhone(context: context, y: 39), + ), + + // inputan email + Padding( + padding: EdgeInsets.only( + // top: Constant.getActualYPhone(context: context, y: 63), + left: Constant.getActualXPhone(context: context, x: 20), + right: + Constant.getActualXPhone(context: context, x: 20), + ), + child: Text( + 'Email', + style: Constant.body1_400_dibulan(context: context) + .copyWith( + fontWeight: FontWeight.w600, + color: Constant.textBlack), + ), + ), + SizedBox( + height: Constant.getActualYPhone(context: context, y: 4), + ), + Padding( + padding: EdgeInsets.only( + // top: Constant.getActualYPhone(context: context, y: 63), + left: Constant.getActualXPhone(context: context, x: 20), + right: + Constant.getActualXPhone(context: context, x: 20), + ), + child: TextField( + controller: ctrlEmail, + decoration: InputDecoration( + hintStyle: + Constant.body2_400(context: context).copyWith( + color: Colors.orange, + ), + labelStyle: + Constant.body2_400(context: context).copyWith( + color: Colors.orange, + ), + border: OutlineInputBorder( + borderSide: BorderSide( + color: Colors.orange, + width: 1, + ), + ), + focusedBorder: OutlineInputBorder( + borderSide: BorderSide( + color: Colors.orange, + width: 1, + ), + ), + // labelText: "Nama Pengirim", + // hintText: 'Nama Pengirim', + ), + ), + ), + + SizedBox( + height: Constant.getActualYPhone(context: context, y: 21), + ), + + // password + Padding( + padding: EdgeInsets.only( + // top: Constant.getActualYPhone(context: context, y: 63), + left: Constant.getActualXPhone(context: context, x: 20), + right: + Constant.getActualXPhone(context: context, x: 20), + ), + child: Text( + 'Password', + style: Constant.body1_400_dibulan(context: context) + .copyWith( + fontWeight: FontWeight.w600, + color: Constant.textBlack), + ), + ), + SizedBox( + height: Constant.getActualYPhone(context: context, y: 4), + ), + Padding( + padding: EdgeInsets.only( + // top: Constant.getActualYPhone(context: context, y: 63), + left: Constant.getActualXPhone(context: context, x: 20), + right: + Constant.getActualXPhone(context: context, x: 20), + ), + child: TextField( + controller: ctrlPassword, + decoration: InputDecoration( + hintStyle: + Constant.body2_400(context: context).copyWith( + color: Colors.orange, + ), + labelStyle: + Constant.body2_400(context: context).copyWith( + color: Colors.orange, + ), + border: OutlineInputBorder( + borderSide: BorderSide( + color: Colors.orange, + width: 1, + ), + ), + focusedBorder: OutlineInputBorder( + borderSide: BorderSide( + color: Colors.orange, + width: 1, + ), + ), + // labelText: "Nama Pengirim", + // hintText: 'Nama Pengirim', + ), + ), + ), + + if (isLoading.value) + SizedBox( + width: + Constant.getActualXPhone(context: context, x: 20), + height: + Constant.getActualYPhone(context: context, y: 20), + child: Center(child: CircularProgressIndicator()), + ), + + if (errorMessage.value != "") ...[ + SizedBox( + height: + Constant.getActualYPhone(context: context, y: 10), + ), + Center( + child: Text( + "Peringatan : ${errorMessage.value}", + style: Constant.titleH7_700(context: context) + .copyWith(color: Constant.textRedProblemMaketing), + ), + ), + ], + + SizedBox( + height: Constant.getActualYPhone(context: context, y: 40), + ), + Padding( + padding: EdgeInsets.only( + left: Constant.getActualXPhone(context: context, x: 20), + right: + Constant.getActualXPhone(context: context, x: 20), + ), + child: SizedBox( + width: + Constant.getActualXPhone(context: context, x: 390), + height: + Constant.getActualYPhone(context: context, y: 50), + child: ElevatedButton( + onPressed: () { + Navigator.of(context).pushNamed(homeRoute); + }, + // onPressed: (isSuccess.value == true) + // ? () {} + // : () { + // if (ctrlEmail.text.isEmpty || + // ctrlDokterId.text.isEmpty || + // ctrlPassword.text.isEmpty) { + // isLoading.value = true; + // errorMessage.value = 'Inputan harus diisi'; + // Timer(const Duration(seconds: 3), () { + // isLoading.value = false; + // errorMessage.value = ""; + // }); + // } else { + // ref.read(loginProvider.notifier).login( + // username: ctrlEmail.text, + // dokterId: ctrlDokterId.text, + // password: ctrlPassword.text); + // } + // }, + style: ButtonStyle( + backgroundColor: MaterialStateColor.resolveWith( + (st) => (isSuccess.value == true) + ? Constant.textGrey + : Colors.orange), + shape: MaterialStateProperty.all< + RoundedRectangleBorder>( + RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8), + side: BorderSide(color: Colors.orange), + ), + ), + shadowColor: + MaterialStateProperty.all(Color(0xffff48423d)), + elevation: MaterialStateProperty.all(4.0), + ), + child: Align( + alignment: Alignment.center, + child: Text( + 'Login', + style: Constant.titleH3_700(context: context) + .copyWith(color: Constant.textLoginColor), + ), + ), + ), + ), + ), + + SizedBox( + height: Constant.getActualYPhone(context: context, y: 10), + ), + + Align( + alignment: Alignment.center, + child: Text( + 'Versi ${Constant.version}', + style: Constant.titleH4Login(context: context) + .copyWith(color: Constant.textGrey), + ), + ), + ], + ), + ), + ], + ), + ), + ), + ); + } +} diff --git a/app_petty_cash/lib/screen/login/login_screen.dart b/app_petty_cash/lib/screen/login/login_screen.dart index 478e867..23b1933 100644 --- a/app_petty_cash/lib/screen/login/login_screen.dart +++ b/app_petty_cash/lib/screen/login/login_screen.dart @@ -14,6 +14,7 @@ import '../../provider/current_menu_provider.dart'; import '../../provider/current_user_provider.dart'; import 'block_body.dart'; import 'block_bodyv2.dart'; +import 'login_form.dart'; class LoginScreen extends HookConsumerWidget { const LoginScreen({Key? key}) : super(key: key); @@ -68,8 +69,8 @@ class LoginScreen extends HookConsumerWidget { end: Alignment.centerRight, ), ), - // child: BlockBody(), - child: BlockBodyV2(), + // child: BlockBodyV2(), + child: LoginFormScreen(), ), ), ), diff --git a/app_petty_cash/lib/screen/transaksi/transaksi_screen.dart b/app_petty_cash/lib/screen/transaksi/transaksi_screen.dart index 1be8953..bcb61a3 100644 --- a/app_petty_cash/lib/screen/transaksi/transaksi_screen.dart +++ b/app_petty_cash/lib/screen/transaksi/transaksi_screen.dart @@ -1,9 +1,13 @@ +import 'package:app_petty_cash/app/app_extension.dart'; import 'package:dropdown_button2/dropdown_button2.dart'; import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:intl/intl.dart'; import '../../app/constant.dart'; +import '../../widget/custom_drawer.dart'; import '../login/custom_text_field.dart'; class DummyDropdownTipe { @@ -30,6 +34,18 @@ class TransaksiScreen extends HookConsumerWidget { Widget build(BuildContext context, WidgetRef ref) { final ctrlJumlah = useTextEditingController(text: ""); final ctrlCatatan = useTextEditingController(text: ""); + final ctrlNamaPengirim = useTextEditingController(text: ""); + + String formattedDate = DateFormat('dd-MM-yyyy').format(DateTime.now()); + + // final ctrlTglAwal = useTextEditingController( + // text: DateTime.now().toString().split(' ')[0], + // ); + + final ctrlTglAwal = useTextEditingController(text: formattedDate); + + final tglAwal = useState(DateTime.now()); + final tglAwalTmp = useState(""); final selectedDropdownKategori = useState( DummyDropdownTipe( @@ -58,244 +74,509 @@ class TransaksiScreen extends HookConsumerWidget { selectedDropdownKategori.value = dropdownItemsKategori.value[0]; radioButtonItems.value = [ DummyRadioTipe( - "Debit", + "Income", 1, ), DummyRadioTipe( - "Kredit", + "Expenses", 2, ), ]; selectedRadio.value = radioButtonItems.value[0]; + return () {}; }, []); final isMounted = useIsMounted(); - return Scaffold( - appBar: AppBar( - title: Text('Transaksi'), + var sbHeight = MediaQuery.of(context).padding.top; + + print('Height : ${sbHeight}'); + + return Padding( + padding: EdgeInsets.only( + top: Constant.getActualYPhone(context: context, y: 30), ), - body: SingleChildScrollView( - child: Padding( - padding: EdgeInsets.all(20), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - 'Kategori', - style: Constant.body1(context: context).copyWith( - fontWeight: FontWeight.w600, color: Constant.textBlack), - ), - SizedBox( - height: Constant.getActualYPhone(context: context, y: 10), - ), - // Dropdown kategori - SizedBox( - width: Constant.getActualXPhone(context: context, x: 390), - child: DropdownButtonHideUnderline( - child: DropdownButton2( - isExpanded: true, - hint: Row( - children: [ - Expanded( - child: Text( - 'Select Item', - style: Constant.body1(context: context).copyWith( - fontWeight: FontWeight.w600, - color: Constant.textBlack), - overflow: TextOverflow.ellipsis, - ), - ), - ], - ), - items: dropdownItemsKategori.value - .map((DummyDropdownTipe option) { - return DropdownMenuItem( - value: option, - child: Text( - option.options, - style: Constant.body1(context: context).copyWith( - color: Constant.textBlack, - fontWeight: FontWeight.w600), - ), - ); - }).toList(), - value: selectedDropdownKategori.value, - onChanged: (DummyDropdownTipe? newValue) { - // if (newValue) { - selectedDropdownKategori.value = newValue!; - print(selectedDropdownKategori.value.id); - // } - }, - buttonStyleData: ButtonStyleData( - height: Constant.getActualY(context: context, y: 56), - width: Constant.getActualX(context: context, x: 320), - padding: EdgeInsets.only( - left: Constant.getActualX(context: context, x: 10), - right: Constant.getActualX(context: context, x: 10), - ), - decoration: BoxDecoration( - color: Constant.white, - border: Border.all(color: Constant.textBlack, width: 1), - borderRadius: BorderRadius.circular(8), - ), - elevation: 2, - ), - iconStyleData: IconStyleData( - icon: Icon( - Icons.keyboard_arrow_down_outlined, - ), - iconSize: 24, - iconEnabledColor: Constant.textBlack, - iconDisabledColor: Colors.grey, - ), - dropdownStyleData: DropdownStyleData( - maxHeight: Constant.getActualY(context: context, y: 200), - // width: Constant.getActualX(context: context, x: 320), - padding: EdgeInsets.only( - top: Constant.getActualY(context: context, y: 10), - left: Constant.getActualX(context: context, x: 10), - right: Constant.getActualX(context: context, x: 10), - bottom: Constant.getActualY(context: context, y: 10), - ), - decoration: BoxDecoration( - color: Constant.white, - borderRadius: BorderRadius.circular(8), - boxShadow: [ - BoxShadow( - color: Colors.grey, - blurRadius: 20.0, - spreadRadius: 2.0, - offset: Offset(0.0, 0.0), - ), - ], - ), - elevation: 8, - offset: const Offset(0, -10), - scrollbarTheme: ScrollbarThemeData( - radius: const Radius.circular(40), - thickness: MaterialStateProperty.all(6), - thumbVisibility: MaterialStateProperty.all(true), - ), - ), - menuItemStyleData: MenuItemStyleData( - height: Constant.getActualY(context: context, y: 56), - padding: EdgeInsets.only( - top: Constant.getActualY(context: context, y: 10), - left: Constant.getActualX(context: context, x: 10), - right: Constant.getActualX(context: context, x: 10), - ), - ), + child: Scaffold( + appBar: AppBar( + // centerTitle: true, + title: Text('Transaksi'), + ), + drawer: CustomDrawer(), + body: SafeArea( + child: SingleChildScrollView( + child: Padding( + padding: EdgeInsets.all(20), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'Tanggal Transaksi', + style: Constant.body1(context: context).copyWith( + fontWeight: FontWeight.w600, color: Constant.textBlack), ), - ), - ), - - SizedBox( - height: Constant.getActualYPhone(context: context, y: 20), - ), - - // jenis - Text( - 'Jenis', - style: Constant.body1(context: context).copyWith( - fontWeight: FontWeight.w600, color: Constant.textBlack), - ), - SizedBox( - height: Constant.getActualYPhone(context: context, y: 10), - ), - SizedBox( - width: Constant.getActualXPhone(context: context, x: 340), - height: Constant.getActualYPhone(context: context, y: 36), - child: Row( - mainAxisAlignment: MainAxisAlignment.start, - children: [ - if (radioButtonItems.value.isEmpty) - Text('Radio Button Empty') - else - for (var i = 0; i < radioButtonItems.value.length; i++) - Padding( - padding: const EdgeInsets.only(right: 20), - child: Row( - children: [ - Radio( - activeColor: Constant.confirmed, - value: radioButtonItems.value[i], - groupValue: selectedRadio.value, - onChanged: (DummyRadioTipe? index) { - if (isMounted()) { - selectedRadio.value = index!; - } else { - return; - } - }, + SizedBox( + height: Constant.getActualYPhone(context: context, y: 10), + ), + // Tanggal Transaksi + Row( + children: [ + Expanded( + child: TextField( + controller: ctrlTglAwal, + decoration: InputDecoration( + hintStyle: + Constant.body2_400(context: context).copyWith( + color: Colors.orange, + ), + labelStyle: + Constant.body2_400(context: context).copyWith( + color: Colors.orange, + ), + border: OutlineInputBorder( + borderSide: BorderSide( + color: Colors.orange, + width: 1, ), - Text( - radioButtonItems.value[i].text, - style: - Constant.body1(context: context).copyWith( + ), + focusedBorder: OutlineInputBorder( + borderSide: BorderSide( + color: Colors.orange, + width: 1, + ), + ), + // labelText: "Tanggal Awal", + hintText: 'Tanggal Awal', + // suffixIcon: isLoadingFilterScope.value + // ? SizedBox( + // width: Constant.getActualXPhone( + // context: context, + // x: 4, + // ), + // height: Constant.getActualYPhone( + // context: context, + // y: 4, + // ), + // child: CircularProgressIndicator( + // color: Constant.textRed, + // ), + // ) + // : Icon( + // Icons.calendar_month_sharp, + // color: Constant.colorIconDate, + // ), + ), + onTap: () async { + final selectedDateAwal = await showDatePicker( + // locale: const Locale("en-CA"), + // locale: , + context: context, + initialEntryMode: + DatePickerEntryMode.calendarOnly, + firstDate: DateTime(2000), + lastDate: DateTime(2100), + + initialDate: (ctrlTglAwal.text.isEmpty) + ? DateTime.now() + : tglAwal.value, + ); + + if (selectedDateAwal != null) { + String formattedDate = DateFormat('dd-MM-yyyy') + .format(selectedDateAwal); + // ctrlTglAwal.text = + // selectedDateAwal.toString().split(' ')[0]; + ctrlTglAwal.text = formattedDate; + tglAwal.value = selectedDateAwal; + tglAwalTmp.value = selectedDateAwal.toString(); + } + + if (selectedDateAwal == null) { + print('cancel button'); + return; + } + }, + ), + ), + ], + ), + + SizedBox( + height: Constant.getActualYPhone(context: context, y: 20), + ), + + // Kategori + Text( + 'Kategori', + style: Constant.body1(context: context).copyWith( + fontWeight: FontWeight.w600, color: Constant.textBlack), + ), + SizedBox( + height: Constant.getActualYPhone(context: context, y: 10), + ), + // Dropdown kategori + SizedBox( + width: Constant.getActualXPhone(context: context, x: 390), + child: DropdownButtonHideUnderline( + child: DropdownButton2( + isExpanded: true, + hint: Row( + children: [ + Expanded( + child: Text( + 'Select Item', + style: Constant.body1(context: context) + .copyWith( + fontWeight: FontWeight.w600, + color: Constant.textBlack), + overflow: TextOverflow.ellipsis, + ), + ), + ], + ), + items: dropdownItemsKategori.value + .map((DummyDropdownTipe option) { + return DropdownMenuItem( + value: option, + child: Text( + option.options, + style: Constant.body1(context: context).copyWith( color: Constant.textBlack, - fontWeight: FontWeight.w400, - ), + fontWeight: FontWeight.w600), + ), + ); + }).toList(), + value: selectedDropdownKategori.value, + onChanged: (DummyDropdownTipe? newValue) { + // if (newValue) { + selectedDropdownKategori.value = newValue!; + print(selectedDropdownKategori.value.id); + // } + }, + buttonStyleData: ButtonStyleData( + height: Constant.getActualY(context: context, y: 56), + width: Constant.getActualX(context: context, x: 320), + padding: EdgeInsets.only( + left: Constant.getActualX(context: context, x: 10), + right: Constant.getActualX(context: context, x: 10), + ), + decoration: BoxDecoration( + color: Constant.white, + border: + Border.all(color: Constant.textBlack, width: 1), + borderRadius: BorderRadius.circular(8), + ), + elevation: 2, + ), + iconStyleData: IconStyleData( + icon: Icon( + Icons.keyboard_arrow_down_outlined, + ), + iconSize: 24, + iconEnabledColor: Constant.textBlack, + iconDisabledColor: Colors.grey, + ), + dropdownStyleData: DropdownStyleData( + maxHeight: + Constant.getActualY(context: context, y: 200), + // width: Constant.getActualX(context: context, x: 320), + padding: EdgeInsets.only( + top: Constant.getActualY(context: context, y: 10), + left: Constant.getActualX(context: context, x: 10), + right: Constant.getActualX(context: context, x: 10), + bottom: + Constant.getActualY(context: context, y: 10), + ), + decoration: BoxDecoration( + color: Constant.white, + borderRadius: BorderRadius.circular(8), + boxShadow: [ + BoxShadow( + color: Colors.grey, + blurRadius: 20.0, + spreadRadius: 2.0, + offset: Offset(0.0, 0.0), ), ], ), + elevation: 8, + offset: const Offset(0, -10), + scrollbarTheme: ScrollbarThemeData( + radius: const Radius.circular(40), + thickness: MaterialStateProperty.all(6), + thumbVisibility: + MaterialStateProperty.all(true), + ), ), - ], + menuItemStyleData: MenuItemStyleData( + height: Constant.getActualY(context: context, y: 56), + padding: EdgeInsets.only( + top: Constant.getActualY(context: context, y: 10), + left: Constant.getActualX(context: context, x: 10), + right: Constant.getActualX(context: context, x: 10), + ), + ), + ), + ), + ), + + SizedBox( + height: Constant.getActualYPhone(context: context, y: 20), + ), + Text( + 'Nama Pengirim', + style: Constant.body1(context: context).copyWith( + fontWeight: FontWeight.w600, color: Constant.textBlack), + ), + SizedBox( + height: Constant.getActualYPhone(context: context, y: 10), + ), + TextField( + controller: ctrlNamaPengirim, + decoration: InputDecoration( + hintStyle: Constant.body2_400(context: context).copyWith( + color: Colors.orange, + ), + labelStyle: Constant.body2_400(context: context).copyWith( + color: Colors.orange, + ), + border: OutlineInputBorder( + borderSide: BorderSide( + color: Colors.orange, + width: 1, + ), + ), + focusedBorder: OutlineInputBorder( + borderSide: BorderSide( + color: Colors.orange, + width: 1, + ), + ), + // labelText: "Nama Pengirim", + // hintText: 'Nama Pengirim', + ), + ), + // CustomTextField( + // isNumber: false, + // isReadOnly: false, + // ctrl: ctrlNamaPengirim, + // isPassword: false, + // isMaxLine: false, + // hintText: "Nama Pengirim", + // labelText: "Nama Pengirim", + // // onChange: (String searchResult) {}, + // isPrefix: false, + // ), + SizedBox( + height: Constant.getActualYPhone(context: context, y: 20), + ), + + // jenis + Text( + 'Jenis', + style: Constant.body1(context: context).copyWith( + fontWeight: FontWeight.w600, color: Constant.textBlack), + ), + SizedBox( + height: Constant.getActualYPhone(context: context, y: 10), + ), + SizedBox( + width: Constant.getActualXPhone(context: context, x: 340), + height: Constant.getActualYPhone(context: context, y: 36), + child: Row( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + if (radioButtonItems.value.isEmpty) + Text('Radio Button Empty') + else + for (var i = 0; + i < radioButtonItems.value.length; + i++) + Padding( + padding: const EdgeInsets.only(right: 20), + child: Row( + children: [ + Radio( + activeColor: Constant.confirmed, + value: radioButtonItems.value[i], + groupValue: selectedRadio.value, + onChanged: (DummyRadioTipe? index) { + if (isMounted()) { + selectedRadio.value = index!; + } else { + return; + } + }, + ), + Text( + radioButtonItems.value[i].text, + style: Constant.body1(context: context) + .copyWith( + color: Constant.textBlack, + fontWeight: FontWeight.w400, + ), + ), + ], + ), + ), + ], + ), + ), + + SizedBox( + height: Constant.getActualYPhone(context: context, y: 20), + ), + + // jumlah + Text( + 'Jumlah', + style: Constant.body1(context: context).copyWith( + fontWeight: FontWeight.w600, color: Constant.textBlack), + ), + SizedBox( + height: Constant.getActualYPhone(context: context, y: 20), + ), + TextField( + controller: ctrlJumlah, + keyboardType: TextInputType.number, + decoration: InputDecoration( + hintStyle: Constant.body2_400(context: context).copyWith( + color: Colors.orange, + ), + labelStyle: Constant.body2_400(context: context).copyWith( + color: Colors.orange, + ), + border: OutlineInputBorder( + borderSide: BorderSide( + color: Colors.orange, + width: 1, + ), + ), + focusedBorder: OutlineInputBorder( + borderSide: BorderSide( + color: Colors.orange, + width: 1, + ), + ), + // labelText: "Jumlah", + // hintText: 'Jumlah', + ), + ), + // CustomTextField( + // isNumber: true, + // isReadOnly: false, + // ctrl: ctrlJumlah, + // isPassword: false, + // isMaxLine: false, + // hintText: "Jumlah", + // labelText: "Jumlah", + // // onChange: (String searchResult) {}, + // isPrefix: false, + // ), + + SizedBox( + height: Constant.getActualYPhone(context: context, y: 20), + ), + + // catatan + Text( + 'Catatan', + style: Constant.body1(context: context).copyWith( + fontWeight: FontWeight.w600, color: Constant.textBlack), + ), + SizedBox( + height: Constant.getActualYPhone(context: context, y: 20), + ), + + TextField( + controller: ctrlCatatan, + maxLines: 4, + decoration: InputDecoration( + hintStyle: Constant.body2_400(context: context).copyWith( + color: Colors.orange, + ), + labelStyle: Constant.body2_400(context: context).copyWith( + color: Colors.orange, + ), + border: OutlineInputBorder( + borderSide: BorderSide( + color: Colors.orange, + width: 1, + ), + ), + focusedBorder: OutlineInputBorder( + borderSide: BorderSide( + color: Colors.orange, + width: 1, + ), + ), + // labelText: "Catatan", + // hintText: 'Catatan', + ), + ), + // CustomTextField( + // isNumber: false, + // isReadOnly: false, + // ctrl: ctrlCatatan, + // isPassword: false, + // isMaxLine: true, + // isTextArea: true, + // hintText: "Catatan", + // labelText: "Catatan", + // // onChange: (String searchResult) {}, + // isPrefix: false, + // ), + + SizedBox( + height: Constant.getActualYPhone(context: context, y: 20), + ), + + // Upload File + Container( + width: Constant.getActualXPhone(context: context, x: 336), + height: Constant.getActualYPhone(context: context, y: 83), + decoration: BoxDecoration(color: Constant.bgUploadFile), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Icon( + Icons.upload_outlined, + ), + Text( + 'Upload File', + style: Constant.body1(context: context).copyWith( + fontWeight: FontWeight.w600, + color: Constant.textBlack), + ) + ], + ), + ), + ], + ), + ), + ), + ), + bottomNavigationBar: Padding( + padding: EdgeInsets.only( + right: Constant.getActualXPhone(context: context, x: 27), + left: Constant.getActualXPhone(context: context, x: 27), + bottom: Constant.getActualYPhone(context: context, y: 32), + top: Constant.getActualYPhone(context: context, y: 10), + ), + child: BottomAppBar( + child: Container( + width: Constant.getActualXPhone(context: context, x: 336), + height: Constant.getActualYPhone(context: context, y: 42), + child: ElevatedButton( + child: Text( + 'Simpan', + style: Constant.body1(context: context).copyWith( + fontWeight: FontWeight.w600, color: Constant.textBlack), ), + onPressed: () {}, ), - - SizedBox( - height: Constant.getActualYPhone(context: context, y: 20), - ), - - // jumlah - Text( - 'Jumlah', - style: Constant.body1(context: context).copyWith( - fontWeight: FontWeight.w600, color: Constant.textBlack), - ), - SizedBox( - height: Constant.getActualYPhone(context: context, y: 20), - ), - CustomTextField( - isNumber: true, - isReadOnly: false, - ctrl: ctrlJumlah, - isPassword: false, - isMaxLine: false, - hintText: "Jumlah", - labelText: "Jumlah", - // onChange: (String searchResult) {}, - isPrefix: false, - ), - - SizedBox( - height: Constant.getActualYPhone(context: context, y: 20), - ), - - // catatan - Text( - 'Catatan', - style: Constant.body1(context: context).copyWith( - fontWeight: FontWeight.w600, color: Constant.textBlack), - ), - SizedBox( - height: Constant.getActualYPhone(context: context, y: 20), - ), - CustomTextField( - isNumber: false, - isReadOnly: false, - ctrl: ctrlCatatan, - isPassword: false, - isMaxLine: true, - isTextArea: true, - hintText: "Catatan", - labelText: "Catatan", - // onChange: (String searchResult) {}, - isPrefix: false, - ), - ], + ), ), ), ), diff --git a/app_petty_cash/lib/screen/user/user_screen.dart b/app_petty_cash/lib/screen/user/user_screen.dart new file mode 100644 index 0000000..fc6b3c5 --- /dev/null +++ b/app_petty_cash/lib/screen/user/user_screen.dart @@ -0,0 +1,29 @@ +import 'package:flutter/material.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; + +import '../../app/constant.dart'; +import '../../widget/custom_drawer.dart'; + +class UserScreen extends HookConsumerWidget { + const UserScreen({super.key}); + + @override + Widget build(BuildContext context, WidgetRef ref) { + return Padding( + padding: EdgeInsets.only( + top: Constant.getActualYPhone(context: context, y: 30), + ), + child: Scaffold( + appBar: AppBar( + title: Text('User'), + ), + drawer: CustomDrawer(), + body: SafeArea( + child: Center( + child: Text('Under Construction'), + ), + ), + ), + ); + } +} diff --git a/app_petty_cash/lib/widget/custom_drawer.dart b/app_petty_cash/lib/widget/custom_drawer.dart new file mode 100644 index 0000000..13f29f5 --- /dev/null +++ b/app_petty_cash/lib/widget/custom_drawer.dart @@ -0,0 +1,67 @@ +import 'package:flutter/material.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; + +import '../app/constant.dart'; +import '../app/route.dart'; + +class CustomDrawer extends HookConsumerWidget { + const CustomDrawer({ + super.key, + }); + + @override + Widget build(BuildContext context, WidgetRef ref) { + return Drawer( + child: ListView( + padding: EdgeInsets.only( + top: Constant.getActualYPhone(context: context, y: 10), + ), + children: [ + // DrawerHeader( + // decoration: BoxDecoration( + // color: Colors.blue, + // ), + // child: Text( + // 'Drawer Header', + // style: TextStyle( + // color: Colors.white, + // fontSize: 24, + // ), + // ), + // ), + ListTile( + title: Text('Home'), + onTap: () { + // Handle navigation to Home screen + Navigator.pop(context); + Navigator.pushNamed(context, homeRoute); + }, + ), + ListTile( + title: Text('Transaksi'), + onTap: () { + // Handle navigation to Transaksi screen + Navigator.pop(context); + Navigator.pushNamed(context, transaksiRoute); + }, + ), + ListTile( + title: Text('User'), + onTap: () { + // Handle navigation to User screen + Navigator.pop(context); + Navigator.pushNamed(context, userRoute); + }, + ), + ListTile( + title: Text('Logout'), + onTap: () { + // Handle logout logic + Navigator.pop(context); + }, + ), + ], + ), + ); + } +} diff --git a/app_petty_cash/lib/widget/sankbar_widget.dart b/app_petty_cash/lib/widget/sankbar_widget.dart new file mode 100644 index 0000000..2da9336 --- /dev/null +++ b/app_petty_cash/lib/widget/sankbar_widget.dart @@ -0,0 +1,50 @@ +import 'package:flutter/material.dart'; +import 'package:top_snackbar_flutter/custom_snack_bar.dart'; +import 'package:top_snackbar_flutter/top_snack_bar.dart'; + +enum snackbarType { error, info, success, warning } + +SanckbarWidget(BuildContext context, String msg, snackbarType tipe) { + switch (tipe) { + case snackbarType.error: + return showTopSnackBar( + Overlay.of(context), + CustomSnackBar.error( + message: msg, + ), + ); + break; + case snackbarType.success: + return showTopSnackBar( + Overlay.of(context), + CustomSnackBar.success( + message: msg, + ), + ); + break; + case snackbarType.info: + return showTopSnackBar( + Overlay.of(context), + CustomSnackBar.info( + message: msg, + ), + ); + break; + case snackbarType.warning: + return showTopSnackBar( + Overlay.of(context), + CustomSnackBar.info( + backgroundColor: Colors.orangeAccent, + message: msg, + ), + ); + break; + default: + return showTopSnackBar( + Overlay.of(context), + CustomSnackBar.info( + message: msg, + ), + ); + } +} \ No newline at end of file diff --git a/app_petty_cash/pubspec.lock b/app_petty_cash/pubspec.lock index f4dbc69..674af85 100644 --- a/app_petty_cash/pubspec.lock +++ b/app_petty_cash/pubspec.lock @@ -9,6 +9,22 @@ packages: url: "https://pub.dev" source: hosted version: "2.11.0" + base58check: + dependency: transitive + description: + name: base58check + sha256: "6c300dfc33e598d2fe26319e13f6243fea81eaf8204cb4c6b69ef20a625319a5" + url: "https://pub.dev" + source: hosted + version: "2.0.0" + bech32: + dependency: transitive + description: + name: bech32 + sha256: "156cbace936f7720c79a79d16a03efad343b1ef17106716e04b8b8e39f99f7f7" + url: "https://pub.dev" + source: hosted + version: "0.2.2" boolean_selector: dependency: transitive description: @@ -41,6 +57,22 @@ packages: url: "https://pub.dev" source: hosted version: "1.17.1" + convert: + dependency: transitive + description: + name: convert + sha256: "0f08b14755d163f6e2134cb58222dd25ea2a2ee8a195e53983d57c075324d592" + url: "https://pub.dev" + source: hosted + version: "3.1.1" + crypto: + dependency: transitive + description: + name: crypto + sha256: ff625774173754681d66daaf4a448684fb04b78f902da9cb3d308c19cc5e8bab + url: "https://pub.dev" + source: hosted + version: "3.0.3" cupertino_icons: dependency: "direct main" description: @@ -134,6 +166,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.0.3" + flutter_multi_formatter: + dependency: "direct main" + description: + name: flutter_multi_formatter + sha256: "4798b3ee8a3c00271565e77dc8886f02b52354c3ac0d845e07d1715d159959f6" + url: "https://pub.dev" + source: hosted + version: "2.12.4" flutter_plugin_android_lifecycle: dependency: transitive description: @@ -445,6 +485,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.5.1" + top_snackbar_flutter: + dependency: "direct main" + description: + name: top_snackbar_flutter + sha256: "22d14664a13db6ac714934c3382bd8d4daa57fb888a672f922df71981c5a5cb2" + url: "https://pub.dev" + source: hosted + version: "3.1.0" typed_data: dependency: transitive description: diff --git a/app_petty_cash/pubspec.yaml b/app_petty_cash/pubspec.yaml index 39dc7b2..e694f6e 100644 --- a/app_petty_cash/pubspec.yaml +++ b/app_petty_cash/pubspec.yaml @@ -47,6 +47,8 @@ dependencies: dropdown_button2: ^2.1.3 file_picker: ^6.1.1 open_file: ^3.3.2 + flutter_multi_formatter: ^2.12.4 + top_snackbar_flutter: ^3.1.0 dev_dependencies: flutter_test: