diff --git a/app_petty_cash/images/logo_splash_screen.png b/app_petty_cash/images/logo_splash_screen.png new file mode 100644 index 0000000..6b056db Binary files /dev/null and b/app_petty_cash/images/logo_splash_screen.png differ diff --git a/app_petty_cash/lib/repository/transaksi_repository.dart b/app_petty_cash/lib/repository/transaksi_repository.dart index b5c2723..af1121c 100644 --- a/app_petty_cash/lib/repository/transaksi_repository.dart +++ b/app_petty_cash/lib/repository/transaksi_repository.dart @@ -46,4 +46,48 @@ class TransaksiRepository extends BaseRepository { }); return result; } + + // insert transaksi + Future insertTransaksi( + String tanggal, + String tipe, + String kategoriid, + String jumlah, + String catatan, + String userid, + String sender, + String url) async { + String paramPostInUrl = ""; + if (tipe == "KREDIT") { + sender = ""; + paramPostInUrl = + "?tanggal=$tanggal&tipe=$tipe&kategoriid=$kategoriid&jumlah=$jumlah&catatan=$catatan&url=$url&userid=$userid&sender=$sender"; + } else { + if (tipe == "DEBIT") { + kategoriid = "0"; + paramPostInUrl = + "?tanggal=$tanggal&tipe=$tipe&kategoriid=$kategoriid&jumlah=$jumlah&catatan=$catatan&url=$url&userid=$userid&sender=$sender"; + } + } + // /?tanggal=2023-12-29&tipe=KREDIT&kategoriid=3&jumlah=5000&catatan=Lakban%20Besar&url=&userid=1&sender= + + final service = + "${Constant.baseUrlDevone}transaction/addtransaction/$paramPostInUrl"; + final resp = await get( + // param: { + // "": "", + // }, + service: service, + ); + + print("url insert transaksi : $service"); + + // final result = List.empty(growable: true); + // resp['data'].forEach((e) { + // final model = ListCategory.fromJson(e); + // result.add(model); + // }); + + return resp['status']; + } } diff --git a/app_petty_cash/lib/screen/transaksi/insert_transaksi_provider.dart b/app_petty_cash/lib/screen/transaksi/insert_transaksi_provider.dart new file mode 100644 index 0000000..c38e916 --- /dev/null +++ b/app_petty_cash/lib/screen/transaksi/insert_transaksi_provider.dart @@ -0,0 +1,84 @@ + +import 'package:equatable/equatable.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +import '../../repository/transaksi_repository.dart'; +import '../../provider/dio_provider.dart'; +import '../../repository/base_repository.dart'; + +abstract class InsertTransaksiState extends Equatable { + final DateTime date; + const InsertTransaksiState(this.date); + @override + List get props => [date]; +} + +class InsertTransaksiStateInit extends InsertTransaksiState { + InsertTransaksiStateInit() : super(DateTime.now()); +} + +class InsertTransaksiStateLoading extends InsertTransaksiState { + InsertTransaksiStateLoading() : super(DateTime.now()); +} + +class InsertTransaksiStateError extends InsertTransaksiState { + final String message; + InsertTransaksiStateError({ + required this.message, + }) : super(DateTime.now()); +} + +class InsertTransaksiStateDone extends InsertTransaksiState { + // final List model; + final String resp; + InsertTransaksiStateDone({ + required this.resp, + }) : super(DateTime.now()); +} + +//notifier +class InsertTransaksiNotifier extends StateNotifier { + final Ref ref; + InsertTransaksiNotifier({ + required this.ref, + }) : super(InsertTransaksiStateInit()); + + void insertTransaksi( + String tanggal, + String tipe, + String kategoriid, + String jumlah, + String catatan, + String userid, + String sender, + String url, + ) async { + try { + state = InsertTransaksiStateLoading(); + final dio = ref.read(dioProvider); + final resp = await TransaksiRepository(dio: dio).insertTransaksi( + tanggal, + tipe, + kategoriid, + jumlah, + catatan, + userid, + sender, + url, + ); + state = InsertTransaksiStateDone(resp: resp); + } catch (e) { + if (e is BaseRepositoryException) { + state = InsertTransaksiStateError(message: e.message.toString()); + } else { + state = InsertTransaksiStateError(message: e.toString()); + } + } + } +} + +//provider +final insertTransaksiProvider = + StateNotifierProvider( + (ref) => InsertTransaksiNotifier(ref: ref), +); diff --git a/app_petty_cash/lib/screen/transaksi/transaksi_screen.dart b/app_petty_cash/lib/screen/transaksi/transaksi_screen.dart index a5b8270..48d5a87 100644 --- a/app_petty_cash/lib/screen/transaksi/transaksi_screen.dart +++ b/app_petty_cash/lib/screen/transaksi/transaksi_screen.dart @@ -1,5 +1,7 @@ import 'package:app_petty_cash/app/app_extension.dart'; +import 'package:app_petty_cash/app/route.dart'; import 'package:app_petty_cash/model/list_type_model.dart'; +import 'package:app_petty_cash/screen/transaksi/insert_transaksi_provider.dart'; import 'package:app_petty_cash/screen/transaksi/list_category_provider.dart'; import 'package:app_petty_cash/screen/transaksi/list_type_provider.dart'; import 'package:dropdown_button2/dropdown_button2.dart'; @@ -66,6 +68,9 @@ class TransaksiScreen extends HookConsumerWidget { ), ); + // transaksi + final transaksiIsLoading = useState(false); + // A. LISTEN PROVIDER ref.listen( listTypeProvider, @@ -73,7 +78,7 @@ class TransaksiScreen extends HookConsumerWidget { if (next is ListTypeStateLoading) { listTypeLoading.value = true; } else if (next is ListTypeStateError) { - print(next.message); + // print(next.message); listTypeLoading.value = false; SanckbarWidget(context, next.message, snackbarType.error); } else if (next is ListTypeStateDone) { @@ -100,7 +105,7 @@ class TransaksiScreen extends HookConsumerWidget { if (next is ListCategoryStateLoading) { listCategoryLoading.value = true; } else if (next is ListCategoryStateError) { - print(next.message); + // print(next.message); listCategoryLoading.value = false; SanckbarWidget(context, next.message, snackbarType.error); } else if (next is ListCategoryStateDone) { @@ -113,6 +118,31 @@ class TransaksiScreen extends HookConsumerWidget { }, ); + // insert transaksi provider + ref.listen( + insertTransaksiProvider, + (previous, next) { + if (next is InsertTransaksiStateLoading) { + transaksiIsLoading.value = true; + } else if (next is InsertTransaksiStateError) { + print(next.message); + transaksiIsLoading.value = false; + SanckbarWidget(context, next.message, snackbarType.error); + } else if (next is InsertTransaksiStateDone) { + // print(jsonEncode(next.model)); + // print(next.model.length); + transaksiIsLoading.value = false; + SanckbarWidget( + context, + 'Data Berhasil Disimpan', + snackbarType.success, + ); + Navigator.of(context).pop(); + Navigator.of(context).pushNamed(homeRoute); + } + }, + ); + useEffect(() { WidgetsBinding.instance.addPostFrameCallback((timeStamp) async { // list Type Provider @@ -254,42 +284,57 @@ class TransaksiScreen extends HookConsumerWidget { SizedBox( width: Constant.getActualXPhone(context: context, x: 340), height: Constant.getActualYPhone(context: context, y: 36), - child: Row( - mainAxisAlignment: MainAxisAlignment.start, - children: [ - if (listTypeData.value.isEmpty) - Text('Radio Button Empty') - else - for (var i = 0; i < listTypeData.value.length; i++) - Padding( - padding: const EdgeInsets.only(right: 20), - child: Row( - children: [ - Radio( - activeColor: Constant.confirmed, - value: listTypeData.value[i], - groupValue: selectedListTypeData.value, - onChanged: (ListType? index) { - if (isMounted()) { - selectedListTypeData.value = index!; - } else { - return; - } - }, - ), - Text( - listTypeData.value[i].typename ?? "", - style: Constant.body1(context: context) - .copyWith( - color: Constant.textBlack, - fontWeight: FontWeight.w400, + child: (listTypeLoading.value) + ? SizedBox( + width: Constant.getActualXPhone( + context: context, x: 24), + height: Constant.getActualYPhone( + context: context, y: 32), + child: Center( + child: CircularProgressIndicator(), + ), + ) + : Row( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + if (listTypeData.value.isEmpty) + Text('Radio Button Empty') + else + for (var i = 0; + i < listTypeData.value.length; + i++) + Padding( + padding: const EdgeInsets.only(right: 20), + child: Row( + children: [ + Radio( + activeColor: Constant.confirmed, + value: listTypeData.value[i], + groupValue: + selectedListTypeData.value, + onChanged: (ListType? index) { + if (isMounted()) { + selectedListTypeData.value = + index!; + } else { + return; + } + }, + ), + Text( + listTypeData.value[i].typename ?? "", + style: + Constant.body1(context: context) + .copyWith( + color: Constant.textBlack, + fontWeight: FontWeight.w400, + ), + ), + ], ), ), - ], - ), - ), - ], - ), + ], + ), ), SizedBox( @@ -297,9 +342,156 @@ class TransaksiScreen extends HookConsumerWidget { ), // Kategori - if (selectedListTypeData.value.typeid != "KREDIT") ...[ + if (selectedListTypeData.value.typeid == "KREDIT") ...[ Text( 'Kategori', + style: Constant.body1(context: context).copyWith( + fontWeight: FontWeight.w600, + color: Constant.textBlack, + ), + ), + SizedBox( + height: Constant.getActualYPhone(context: context, y: 10), + ), + // Dropdown kategori + (listCategoryLoading.value) + ? SizedBox( + width: Constant.getActualXPhone( + context: context, x: 24), + height: Constant.getActualYPhone( + context: context, y: 32), + child: Center( + child: CircularProgressIndicator(), + ), + ) + : 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: listCategoryData.value + .map((ListCategory option) { + return DropdownMenuItem( + value: option, + child: Text( + option.categoryname ?? "", + style: Constant.body1(context: context) + .copyWith( + color: Constant.textBlack, + fontWeight: FontWeight.w600), + ), + ); + }).toList(), + value: selectedListCategory.value, + onChanged: (ListCategory? newValue) { + // if (newValue) { + selectedListCategory.value = newValue!; + print(selectedListCategory.value.categoryid); + // } + }, + 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), + ), + ], + + // Nama Pengirim + if (selectedListTypeData.value.typeid == "DEBIT") ...[ + Text( + 'Nama Pengirim', style: Constant.body1(context: context).copyWith( fontWeight: FontWeight.w600, color: Constant.textBlack), @@ -307,160 +499,34 @@ class TransaksiScreen extends HookConsumerWidget { 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: - listCategoryData.value.map((ListCategory option) { - return DropdownMenuItem( - value: option, - child: Text( - option.categoryname ?? "", - style: Constant.body1(context: context) - .copyWith( - color: Constant.textBlack, - fontWeight: FontWeight.w600), - ), - ); - }).toList(), - value: selectedListCategory.value, - onChanged: (ListCategory? newValue) { - // if (newValue) { - selectedListCategory.value = newValue!; - print(selectedListCategory.value.categoryid); - // } - }, - 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), - ), + 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', ), ), - - 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, @@ -618,12 +684,67 @@ class TransaksiScreen extends HookConsumerWidget { 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), + child: Stack( + children: [ + (transaksiIsLoading.value) + ? SizedBox( + width: Constant.getActualXPhone( + context: context, x: 24), + height: Constant.getActualYPhone( + context: context, y: 32), + child: CircularProgressIndicator( + color: Colors.white, + ), + ) + : Text( + 'Simpan', + style: Constant.body1(context: context).copyWith( + fontWeight: FontWeight.w600, + color: Constant.textBlack), + ), + ], ), - onPressed: () {}, + onPressed: () { + if (selectedListTypeData.value.typeid.toString() == + "KREDIT") { + ctrlNamaPengirim.text = ""; + // validasi form + } else { + if (selectedListTypeData.value.typeid.toString() == + "DEBIT") { + selectedListCategory.value.categoryid = "0"; + // validasi form + } + } + + DateTime parsedDate = DateFormat('dd-MM-yyyy').parse( + ctrlTglAwal.value.text.toString(), + ); + String formattedDateTransaksi = + DateFormat('yyyy-MM-dd').format(parsedDate); + var param = { + "tgltransaksi": formattedDateTransaksi, + "typeid": selectedListTypeData.value.typeid.toString(), + "categoryid": + selectedListCategory.value.categoryid.toString(), + "jumlah": ctrlJumlah.value.text.toString(), + "catatan": ctrlCatatan.value.text.toString(), + "userid": "1", + "namapengirim": ctrlNamaPengirim.value.text.toString(), + "url": "", + }; + print(param); + ref.read(insertTransaksiProvider.notifier).insertTransaksi( + formattedDateTransaksi, + selectedListTypeData.value.typeid.toString(), + selectedListCategory.value.categoryid.toString(), + ctrlJumlah.value.text.toString(), + ctrlCatatan.value.text.toString(), + "1", + ctrlNamaPengirim.value.text.toString(), + "", + ); + }, ), ), ),