From f915ed2c10088230c80657d9587794b16a08906f Mon Sep 17 00:00:00 2001 From: sindhu Date: Tue, 16 Jan 2024 22:06:42 +0700 Subject: [PATCH] step 20 : delete transaksi, bug icon svg from server, date convert tgl trans --- .../lib/repository/transaksi_repository.dart | 30 ++ .../transaksi/delete_transaksi_provider.dart | 84 ++++ .../transaksi/history_transaksi_screen.dart | 471 ++++++++++++------ .../lib/widget/history_row_atas_widget.dart | 30 +- 4 files changed, 451 insertions(+), 164 deletions(-) create mode 100644 app_petty_cash/lib/screen/transaksi/delete_transaksi_provider.dart diff --git a/app_petty_cash/lib/repository/transaksi_repository.dart b/app_petty_cash/lib/repository/transaksi_repository.dart index 77e0674..90f5166 100644 --- a/app_petty_cash/lib/repository/transaksi_repository.dart +++ b/app_petty_cash/lib/repository/transaksi_repository.dart @@ -121,4 +121,34 @@ class TransaksiRepository extends BaseRepository { }); return result; } + + // delete transaksi + Future deleteTransaksi( + String id, + String userid, + ) async { + + final service = + "${Constant.baseUrlDevone}transaction/deletetransaction/?id=$id&userid=$userid"; + final resp = await get( + // param: { + // "": "", + // }, + service: service, + ); + + print("url delete transaksi : $service"); + + // final result = List.empty(growable: true); + // resp['data'].forEach((e) { + // final model = ListCategory.fromJson(e); + // result.add(model); + // }); + + if(resp['status'] != "OK"){ + return resp['message']; + } + + return resp['status']; + } } diff --git a/app_petty_cash/lib/screen/transaksi/delete_transaksi_provider.dart b/app_petty_cash/lib/screen/transaksi/delete_transaksi_provider.dart new file mode 100644 index 0000000..c15e477 --- /dev/null +++ b/app_petty_cash/lib/screen/transaksi/delete_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'; +import 'search_history_transaksi_provider.dart'; + +abstract class DeleteTransaksiState extends Equatable { + final DateTime date; + const DeleteTransaksiState(this.date); + @override + List get props => [date]; +} + +class DeleteTransaksiStateInit extends DeleteTransaksiState { + DeleteTransaksiStateInit() : super(DateTime.now()); +} + +class DeleteTransaksiStateLoading extends DeleteTransaksiState { + DeleteTransaksiStateLoading() : super(DateTime.now()); +} + +class DeleteTransaksiStateError extends DeleteTransaksiState { + final String message; + DeleteTransaksiStateError({ + required this.message, + }) : super(DateTime.now()); +} + +class DeleteTransaksiStateDone extends DeleteTransaksiState { + // final List model; + final String resp; + DeleteTransaksiStateDone({ + required this.resp, + }) : super(DateTime.now()); +} + +//notifier +class DeleteTransaksiNotifier extends StateNotifier { + final Ref ref; + DeleteTransaksiNotifier({ + required this.ref, + }) : super(DeleteTransaksiStateInit()); + + void deleteTransaksi( + String id, + String userid, + String companyid, + String tglAwal, + String tglAkhir, + String categoryid, + ) async { + try { + state = DeleteTransaksiStateLoading(); + final dio = ref.read(dioProvider); + final resp = await TransaksiRepository(dio: dio).deleteTransaksi( + id, + userid, + ); + state = DeleteTransaksiStateDone(resp: resp); + + // search lagi buat get data + ref.read(searchHistoryTransaksiProvider.notifier).searchHistoryTransaksi( + companyid, + tglAwal, + tglAkhir, + categoryid, + ); + } catch (e) { + if (e is BaseRepositoryException) { + state = DeleteTransaksiStateError(message: e.message.toString()); + } else { + state = DeleteTransaksiStateError(message: e.toString()); + } + } + } +} + +//provider +final deleteTransaksiProvider = + StateNotifierProvider( + (ref) => DeleteTransaksiNotifier(ref: ref), +); diff --git a/app_petty_cash/lib/screen/transaksi/history_transaksi_screen.dart b/app_petty_cash/lib/screen/transaksi/history_transaksi_screen.dart index 5418189..328181a 100644 --- a/app_petty_cash/lib/screen/transaksi/history_transaksi_screen.dart +++ b/app_petty_cash/lib/screen/transaksi/history_transaksi_screen.dart @@ -1,5 +1,6 @@ import 'dart:convert'; +import 'package:app_petty_cash/screen/transaksi/delete_transaksi_provider.dart'; import 'package:app_petty_cash/screen/transaksi/search_history_transaksi_provider.dart'; import 'package:dropdown_button2/dropdown_button2.dart'; import 'package:flutter/material.dart'; @@ -41,7 +42,8 @@ class HistoryTransaksiScreen extends HookConsumerWidget { ), ); - String M_CompanyID = "0"; + // String M_CompanyID = "0"; + final M_CompanyID = useState("0"); String formattedDate = DateFormat('dd-MM-yyyy').format(DateTime.now()); final ctrlTglAwal = useTextEditingController(text: formattedDate); @@ -138,6 +140,27 @@ class HistoryTransaksiScreen extends HookConsumerWidget { }, ); + // delete transaksi + ref.listen( + deleteTransaksiProvider, + (previous, next) { + if (next is DeleteTransaksiStateLoading) { + searchHistoryIsLoading.value = true; + } else if (next is DeleteTransaksiStateError) { + // print(next.message); + searchHistoryIsLoading.value = false; + SanckbarWidget(context, next.message, snackbarType.error); + } else if (next is DeleteTransaksiStateDone) { + // print(jsonEncode(next.model)); + // print(next.model.length); + // listSearchHistory.value = next.model; + SanckbarWidget( + context, 'Data Berhasil Dihapus', snackbarType.success); + searchHistoryIsLoading.value = false; + } + }, + ); + Future getCompanyID() async { final shared = await SharedPreferences.getInstance(); String M_CompanyID = "0"; @@ -180,7 +203,7 @@ class HistoryTransaksiScreen extends HookConsumerWidget { // list category provider ref.read(listCategoryProvider.notifier).getListCategory(); - M_CompanyID = await getCompanyID(); + M_CompanyID.value = await getCompanyID(); DateTime parsedDate = DateFormat('dd-MM-yyyy').parse( ctrlTglAwal.value.text.toString(), @@ -199,11 +222,100 @@ class HistoryTransaksiScreen extends HookConsumerWidget { ref .read(searchHistoryTransaksiProvider.notifier) .searchHistoryTransaksi( - M_CompanyID, formattedDateAwal, formattedDateAkhir, categoryid); + M_CompanyID.value, + formattedDateAwal, + formattedDateAkhir, + categoryid, + ); }); return () {}; }, []); + // delete alert + Future showDeleteConfirmationDialog( + BuildContext context, + String id, + String userid, + String companyid, + String tglAwal, + String tglAkhir, + String categoryid, + ) async { + return showDialog( + context: context, + builder: (BuildContext context) { + return AlertDialog( + title: Text('Konfirmasi Hapus'), + content: Text('Apakah anda yakin menghapus data ini?'), + actions: [ + TextButton( + onPressed: () { + Navigator.of(context).pop(); // Tutup dialog + }, + child: Text('Batal'), + ), + ElevatedButton( + onPressed: () { + print('Deleted id $id , userid $userid'); + DateTime parsedDate = DateFormat('dd-MM-yyyy').parse( + ctrlTglAwal.value.text.toString(), + ); + String formattedDateAwal = + DateFormat('yyyy-MM-dd').format(parsedDate); + + DateTime parsedDateAkhir = DateFormat('dd-MM-yyyy').parse( + ctrlTglAkhir.value.text.toString(), + ); + String formattedDateAkhir = + DateFormat('yyyy-MM-dd').format(parsedDateAkhir); + ref.read(deleteTransaksiProvider.notifier).deleteTransaksi( + id, + userid, + companyid, + formattedDateAwal, + formattedDateAkhir, + categoryid, + ); + Navigator.of(context).pop(); + }, + child: Text( + 'Hapus Data', + style: Constant.body1_600(context: context).copyWith( + fontWeight: FontWeight.w600, + color: Constant.textWhite, + ), + ), + style: ButtonStyle( + backgroundColor: + MaterialStateColor.resolveWith((st) => Constant.textRed), + shape: MaterialStateProperty.all( + RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8), + side: BorderSide( + color: Constant.textRed, + ), + ), + ), + shadowColor: MaterialStateProperty.all(Color(0xffff48423d)), + elevation: MaterialStateProperty.all(4.0), + ), + ), + ], + ); + }, + ); + } + + void _closeKeyboard() { + FocusManager.instance.primaryFocus?.unfocus(); + } + + final FocusNode focusNodetglAwal = useFocusNode(); + final tglAwalHasFocus = useState(false); + + final FocusNode focusNodetglAkhir = useFocusNode(); + final tglAkhirHasFocus = useState(false); + return Padding( padding: EdgeInsets.only( top: Constant.getActualYPhone(context: context, y: 30), @@ -238,80 +350,91 @@ class HistoryTransaksiScreen extends HookConsumerWidget { children: [ // Tanggal Awal Expanded( - child: TextField( - controller: ctrlTglAwal, - decoration: InputDecoration( - hintStyle: - Constant.body2_400(context: context).copyWith( - color: Constant.textGreyv2, - ), - labelStyle: - Constant.body2_400(context: context).copyWith( - color: Constant.textGreyv2, - ), - border: OutlineInputBorder( - borderSide: BorderSide( - color: Colors.orange, - width: 1, - ), - ), - focusedBorder: OutlineInputBorder( - borderSide: BorderSide( - color: Constant.textGreyv2, - 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; - } + child: GestureDetector( + onTap: () { + focusNodetglAwal.unfocus(); + // _closeKeyboard(); }, + child: TextField( + enableInteractiveSelection: false, + showCursor: (tglAwalHasFocus.value) ? true : false, + controller: ctrlTglAwal, + decoration: InputDecoration( + hintStyle: + Constant.body2_400(context: context).copyWith( + color: Constant.textGreyv2, + ), + labelStyle: + Constant.body2_400(context: context).copyWith( + color: Constant.textGreyv2, + ), + border: OutlineInputBorder( + borderSide: BorderSide( + color: Colors.orange, + width: 1, + ), + ), + focusedBorder: OutlineInputBorder( + borderSide: BorderSide( + color: Constant.textGreyv2, + 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; + } + + // focusNodetglAwal.unfocus(); + // _closeKeyboard(); + }, + ), ), ), @@ -321,80 +444,89 @@ class HistoryTransaksiScreen extends HookConsumerWidget { ), // Tanggal Akhir Expanded( - child: TextField( - controller: ctrlTglAkhir, - decoration: InputDecoration( - hintStyle: - Constant.body2_400(context: context).copyWith( - color: Constant.textGreyv2, - ), - labelStyle: - Constant.body2_400(context: context).copyWith( - color: Constant.textGreyv2, - ), - border: OutlineInputBorder( - borderSide: BorderSide( - color: Colors.orange, - width: 1, - ), - ), - focusedBorder: OutlineInputBorder( - borderSide: BorderSide( - color: Constant.textGreyv2, - width: 1, - ), - ), - labelText: "Tanggal Akhir", - hintText: 'Tanggal Akhir', - // 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 selectedDateAkhir = await showDatePicker( - // locale: const Locale("en-CA"), - // locale: , - context: context, - initialEntryMode: - DatePickerEntryMode.calendarOnly, - firstDate: DateTime(2000), - lastDate: DateTime(2100), - - initialDate: (ctrlTglAkhir.text.isEmpty) - ? DateTime.now() - : tglAkhir.value, - ); - - if (selectedDateAkhir != null) { - String formattedDate = DateFormat('dd-MM-yyyy') - .format(selectedDateAkhir); - // ctrlTglAkhir.text = - // selectedDateAkhir.toString().split(' ')[0]; - ctrlTglAkhir.text = formattedDate; - tglAkhir.value = selectedDateAkhir; - tglAkhirTmp.value = selectedDateAkhir.toString(); - } - - if (selectedDateAkhir == null) { - print('cancel button'); - return; - } + child: GestureDetector( + onTap: () { + focusNodetglAkhir.unfocus(); + // _closeKeyboard(); }, + child: TextField( + enableInteractiveSelection: false, + showCursor: (tglAwalHasFocus.value) ? true : false, + controller: ctrlTglAkhir, + decoration: InputDecoration( + hintStyle: + Constant.body2_400(context: context).copyWith( + color: Constant.textGreyv2, + ), + labelStyle: + Constant.body2_400(context: context).copyWith( + color: Constant.textGreyv2, + ), + border: OutlineInputBorder( + borderSide: BorderSide( + color: Colors.orange, + width: 1, + ), + ), + focusedBorder: OutlineInputBorder( + borderSide: BorderSide( + color: Constant.textGreyv2, + width: 1, + ), + ), + labelText: "Tanggal Akhir", + hintText: 'Tanggal Akhir', + // 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 selectedDateAkhir = await showDatePicker( + // locale: const Locale("en-CA"), + // locale: , + context: context, + initialEntryMode: + DatePickerEntryMode.calendarOnly, + firstDate: DateTime(2000), + lastDate: DateTime(2100), + + initialDate: (ctrlTglAkhir.text.isEmpty) + ? DateTime.now() + : tglAkhir.value, + ); + + if (selectedDateAkhir != null) { + String formattedDate = DateFormat('dd-MM-yyyy') + .format(selectedDateAkhir); + // ctrlTglAkhir.text = + // selectedDateAkhir.toString().split(' ')[0]; + ctrlTglAkhir.text = formattedDate; + tglAkhir.value = selectedDateAkhir; + tglAkhirTmp.value = + selectedDateAkhir.toString(); + } + + if (selectedDateAkhir == null) { + print('cancel button'); + return; + } + }, + ), ), ), ], @@ -588,11 +720,11 @@ class HistoryTransaksiScreen extends HookConsumerWidget { ], ), onPressed: () async { - M_CompanyID = await getCompanyID(); + M_CompanyID.value = await getCompanyID(); ref .read(searchHistoryTransaksiProvider.notifier) .searchHistoryTransaksi( - M_CompanyID, + M_CompanyID.value, ctrlTglAwal.text, ctrlTglAkhir.text, selectedListCategory.value.categoryid ?? "0", @@ -754,6 +886,7 @@ class HistoryTransaksiScreen extends HookConsumerWidget { tipe: listSearchHistory .value[idx].tipe .toString(), + // searchHistoryIsLoading.value ), // bawah @@ -774,15 +907,15 @@ class HistoryTransaksiScreen extends HookConsumerWidget { ), shape: RoundedRectangleBorder( side: BorderSide( - color: - Constant.bgChipConfirmed), + color: Constant + .bgTextChipConfirmed), borderRadius: BorderRadius.circular( 50, ), ), - backgroundColor: - Constant.bgChipConfirmed, + backgroundColor: Constant + .bgTextChipConfirmed, ), ], ), @@ -799,8 +932,28 @@ class HistoryTransaksiScreen extends HookConsumerWidget { MainAxisAlignment.end, children: [ InkWell( - onTap: () { - print('Deleted'); + onTap: () async { + final userID = ref + .read( + currentUserProvider) + ?.model + .M_UserID ?? + "0"; + // print('Deleted'); + showDeleteConfirmationDialog( + context, + listSearchHistory + .value[idx].id + .toString(), + userID, + M_CompanyID.value, + ctrlTglAwal.text.toString(), + ctrlTglAkhir.text + .toString(), + selectedListCategory + .value.categoryid + .toString(), + ); }, child: Chip( label: Text( @@ -811,8 +964,8 @@ class HistoryTransaksiScreen extends HookConsumerWidget { ), shape: RoundedRectangleBorder( side: BorderSide( - color: - Constant.bgTextChipDelete), + color: Constant + .bgTextChipDelete), borderRadius: BorderRadius.circular( 50, diff --git a/app_petty_cash/lib/widget/history_row_atas_widget.dart b/app_petty_cash/lib/widget/history_row_atas_widget.dart index 0d8572d..291bfbe 100644 --- a/app_petty_cash/lib/widget/history_row_atas_widget.dart +++ b/app_petty_cash/lib/widget/history_row_atas_widget.dart @@ -3,6 +3,7 @@ import 'package:dio/dio.dart'; import 'package:flutter/material.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:intl/intl.dart'; import '../app/constant.dart'; @@ -12,6 +13,7 @@ class HistoryRowAtasWidget extends HookConsumerWidget { final String amount; final String tipe; final String tglTransaksi; + // final ValueNotifier searchHistoryIsLoading; const HistoryRowAtasWidget({ Key? key, @@ -20,11 +22,11 @@ class HistoryRowAtasWidget extends HookConsumerWidget { required this.amount, required this.tipe, required this.tglTransaksi, + // required this.searchHistoryIsLoading, }) : super(key: key); @override Widget build(BuildContext context, WidgetRef ref) { - // check file exist Future checkFileExistence(String fileUrl) async { try { @@ -62,6 +64,24 @@ class HistoryRowAtasWidget extends HookConsumerWidget { } } + // fungsi tanggal + String formatDateString(String inputDate) { + try { + // Parsing tanggal dari string input + DateTime date = DateFormat('dd-MM-yyyy').parse(inputDate); + + // Format tanggal ke '30 Des 2023' + String formattedDate = DateFormat('dd MMM yyyy', 'id').format(date); + + return formattedDate; + } catch (e) { + // Tangkap kesalahan jika format tanggal tidak sesuai + print('Error parsing date: $e'); + // return 'Format Tanggal Salah'; + return inputDate; + } + } + return Row( children: [ // kiri @@ -76,7 +96,8 @@ class HistoryRowAtasWidget extends HookConsumerWidget { ), // child: Text('s'), child: FutureBuilder( - future: checkFileExistence('https://devone.aplikasi.web.id/pettycash-media/icon/icon_$icon_category_id.svg'), + future: checkFileExistence( + 'https://devone.aplikasi.web.id/pettycash-media/icon/icon_$icon_category_id.svg'), builder: (context, snapshot) { if (snapshot.connectionState == ConnectionState.waiting) { return CircularProgressIndicator(); @@ -86,8 +107,7 @@ class HistoryRowAtasWidget extends HookConsumerWidget { color: Colors.red, ); } else { - return snapshot.data ?? - Container(); + return snapshot.data ?? Container(); } }, ), @@ -163,7 +183,7 @@ class HistoryRowAtasWidget extends HookConsumerWidget { ), ), Text( - tglTransaksi, + formatDateString(tglTransaksi), style: Constant.body1_600(context: context).copyWith( fontWeight: FontWeight.w600, color: Constant.textGreyv2), ),