step 18 : history widget atas cmp

This commit is contained in:
sindhu
2024-01-16 18:02:38 +07:00
parent de84b76170
commit 9416c010d7
19 changed files with 1108 additions and 126 deletions

View File

@@ -1,18 +1,162 @@
import 'dart:convert';
import 'package:app_petty_cash/screen/transaksi/search_history_transaksi_provider.dart';
import 'package:dropdown_button2/dropdown_button2.dart';
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:flutter_svg/svg.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:intl/intl.dart';
import 'package:shared_preferences/shared_preferences.dart';
import '../../app/constant.dart';
import '../../app/route.dart';
import '../../model/history_transaksi_model.dart';
import '../../model/list_category_model.dart';
import '../../model/list_type_model.dart';
import '../../provider/current_user_provider.dart';
import '../../widget/custom_drawer.dart';
import '../../widget/field_row_history_transaksi.dart';
import '../../widget/history_row_atas_widget.dart';
import '../../widget/sankbar_widget.dart';
import 'list_category_provider.dart';
import 'list_type_provider.dart';
class HistoryTransaksiScreen extends HookConsumerWidget {
const HistoryTransaksiScreen({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
final listTypeData = useState<List<ListType>>(List.empty(growable: true));
final selectedListTypeData = useState<ListType>(ListType());
final listTypeLoading = useState(false);
// category
final listCategoryLoading = useState(false);
final selectedListCategory = useState<ListCategory>(ListCategory());
final listCategoryData = useState<List<ListCategory>>(
List.empty(
growable: true,
),
);
String M_CompanyID = "0";
String formattedDate = DateFormat('dd-MM-yyyy').format(DateTime.now());
final ctrlTglAwal = useTextEditingController(text: formattedDate);
final tglAwal = useState<DateTime>(DateTime.now());
final tglAwalTmp = useState<String>("");
final ctrlTglAkhir = useTextEditingController(text: formattedDate);
final tglAkhir = useState<DateTime>(DateTime.now());
final tglAkhirTmp = useState<String>("");
final categoryIsLoading = useState<bool>(false);
final searchHistoryIsLoading = useState<bool>(false);
final listSearchHistory = useState<List<HistoryTransaksiModel>>(
List.empty(
growable: true,
),
);
// A. LISTEN PROVIDER
// type
ref.listen(
listTypeProvider,
(previous, next) {
if (next is ListTypeStateLoading) {
listTypeLoading.value = true;
} else if (next is ListTypeStateError) {
// print(next.message);
listTypeLoading.value = false;
SanckbarWidget(context, next.message, snackbarType.error);
} else if (next is ListTypeStateDone) {
// print(jsonEncode(next.model));
// print(next.model.length);
listTypeData.value = next.model;
listTypeLoading.value = false;
var idx = 0;
for (var i = 0; i < listTypeData.value.length; i++) {
if (listTypeData.value[i].typeid == "KREDIT") {
selectedListTypeData.value = listTypeData.value[i];
idx = i;
}
}
selectedListTypeData.value = listTypeData.value[idx];
}
},
);
// category
ref.listen(
listCategoryProvider,
(previous, next) {
if (next is ListCategoryStateLoading) {
listCategoryLoading.value = true;
} else if (next is ListCategoryStateError) {
// print(next.message);
listCategoryLoading.value = false;
SanckbarWidget(context, next.message, snackbarType.error);
} else if (next is ListCategoryStateDone) {
// print(jsonEncode(next.model));
// print(next.model.length);
// listCategoryData.value = next.model;
final xList = List<ListCategory>.empty(growable: true);
xList.add(
ListCategory(
categoryid: "0",
categoryname: "ALL",
),
);
xList.addAll(next.model);
listCategoryData.value = xList;
listCategoryLoading.value = false;
selectedListCategory.value = listCategoryData.value[0];
}
},
);
// search
ref.listen(
searchHistoryTransaksiProvider,
(previous, next) {
if (next is SearchHistoryTransaksiStateLoading) {
searchHistoryIsLoading.value = true;
} else if (next is SearchHistoryTransaksiStateError) {
// print(next.message);
searchHistoryIsLoading.value = false;
SanckbarWidget(context, next.message, snackbarType.error);
} else if (next is SearchHistoryTransaksiStateDone) {
// print(jsonEncode(next.model));
// print(next.model.length);
listSearchHistory.value = next.model;
searchHistoryIsLoading.value = false;
}
},
);
Future<String> getCompanyID() async {
final shared = await SharedPreferences.getInstance();
String M_CompanyID = "0";
if (shared != null) {
final bearerString = shared.get(Constant.bearerName).toString();
final xmodel = jsonDecode(bearerString);
if (xmodel != null) {
M_CompanyID = xmodel["model"]["M_CompanyID"];
}
}
if (M_CompanyID == "0") {
// throw BaseRepositoryException(message: 'Invalid Company ID');
}
return M_CompanyID;
}
useEffect(() {
WidgetsBinding.instance.addPostFrameCallback((timeStamp) async {
final userID = ref.read(currentUserProvider)?.model.M_UserID ?? "0";
@@ -28,6 +172,38 @@ class HistoryTransaksiScreen extends HookConsumerWidget {
return () {};
}, []);
useEffect(() {
WidgetsBinding.instance.addPostFrameCallback((timeStamp) async {
// list Type Provider
ref.read(listTypeProvider.notifier).getListType();
// list category provider
ref.read(listCategoryProvider.notifier).getListCategory();
M_CompanyID = await getCompanyID();
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);
final categoryid = selectedListCategory.value.categoryid ?? "0";
// search
ref
.read(searchHistoryTransaksiProvider.notifier)
.searchHistoryTransaksi(
M_CompanyID, formattedDateAwal, formattedDateAkhir, categoryid);
});
return () {};
}, []);
return Padding(
padding: EdgeInsets.only(
top: Constant.getActualYPhone(context: context, y: 30),
@@ -45,100 +221,517 @@ class HistoryTransaksiScreen extends HookConsumerWidget {
),
drawer: CustomDrawer(),
body: SafeArea(
child: SingleChildScrollView(
child: Padding(
padding: EdgeInsets.only(
top: Constant.getActualYPhone(context: context, y: 10),
left: Constant.getActualXPhone(context: context, x: 8),
right: Constant.getActualXPhone(context: context, x: 8),
),
child: Container(
height: MediaQuery.of(context).size.height - 10,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Card looping transaksi
Card(
margin: EdgeInsets.all(16.0),
child: Padding(
padding: EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
FieldRowHistoryTransaksi(
label: "Tipe",
value: "DEBIT",
child: Padding(
padding: EdgeInsets.only(
top: Constant.getActualYPhone(context: context, y: 15),
left: Constant.getActualXPhone(context: context, x: 10),
right: Constant.getActualXPhone(context: context, x: 10),
bottom: Constant.getActualYPhone(context: context, y: 10),
),
child: Container(
// height: MediaQuery.of(context).size.height - 10,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// filter
Row(
children: [
// Tanggal Awal
Expanded(
child: TextField(
controller: ctrlTglAwal,
decoration: InputDecoration(
hintStyle:
Constant.body2_400(context: context).copyWith(
color: Constant.textGreyv2,
),
SizedBox(height: 8.0),
FieldRowHistoryTransaksi(
label: "Tanggal",
value: "15-12-2023",
labelStyle:
Constant.body2_400(context: context).copyWith(
color: Constant.textGreyv2,
),
SizedBox(height: 8.0),
FieldRowHistoryTransaksi(
label: "Nominal",
value: "100.000",
),
SizedBox(height: 8.0),
FieldRowHistoryTransaksi(
label: "Kategori",
value: "Jumat Sehat",
),
SizedBox(height: 8.0),
Chip(
label: Text(
'Verify',
style: TextStyle(color: Constant.green_600),
border: OutlineInputBorder(
borderSide: BorderSide(
color: Colors.orange,
width: 1,
),
shape: RoundedRectangleBorder(
side: BorderSide(
color: Constant.green_600,
),
borderRadius: BorderRadius.circular(4.0),
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(
color: Constant.textGreyv2,
width: 1,
),
backgroundColor: Colors.white,
),
SizedBox(
height: Constant.getActualYPhone(
context: context, y: 6),
),
Chip(
label: Text(
'Not Verify',
style: TextStyle(color: Constant.textGreyv2),
),
shape: RoundedRectangleBorder(
side: BorderSide(
color: Constant.textGreyv2,
),
borderRadius: BorderRadius.circular(4.0),
),
backgroundColor: Colors.white,
),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
ElevatedButton(
onPressed: () {
// Handle delete button tap
},
child: Text(
'Delete',
style: TextStyle(color: Constant.textWhite),
),
style: ElevatedButton.styleFrom(
backgroundColor: Colors
.red, // Ganti dengan warna delete button yang diinginkan
),
),
],
),
],
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(
width:
Constant.getActualXPhone(context: context, x: 10),
),
// 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;
}
},
),
),
],
),
SizedBox(
height: Constant.getActualYPhone(context: context, y: 20),
),
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<ListCategory>(
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<ListCategory>(
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<double>(6),
thumbVisibility:
MaterialStateProperty.all<bool>(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: 10),
),
Container(
width: Constant.getActualXPhone(context: context, x: 390),
child: Align(
alignment: Alignment.centerRight,
child: ElevatedButton(
style: ButtonStyle(
backgroundColor: MaterialStateColor.resolveWith(
(st) => Constant.pcBtnBackgroundColor),
shape:
MaterialStateProperty.all<RoundedRectangleBorder>(
RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
side: BorderSide(
color: Constant.pcBtnBackgroundColor,
),
),
),
shadowColor:
MaterialStateProperty.all(Color(0xffff48423d)),
elevation: MaterialStateProperty.all(4.0),
),
child: Stack(
children: [
(categoryIsLoading.value)
? SizedBox(
width: Constant.getActualXPhone(
context: context, x: 24),
height: Constant.getActualYPhone(
context: context, y: 32),
child: CircularProgressIndicator(
color: Colors.white,
),
)
: Text(
'Search',
style: Constant.body1(context: context)
.copyWith(
fontWeight: FontWeight.w600,
color: Constant.white),
),
],
),
onPressed: () async {
M_CompanyID = await getCompanyID();
ref
.read(searchHistoryTransaksiProvider.notifier)
.searchHistoryTransaksi(
M_CompanyID,
ctrlTglAwal.text,
ctrlTglAkhir.text,
selectedListCategory.value.categoryid ?? "0",
);
},
),
),
),
SizedBox(
height: Constant.getActualYPhone(context: context, y: 20),
),
// Card looping transaksi
// (searchHistoryIsLoading.value)
// ? Center(
// child: CircularProgressIndicator(),
// )
// : Expanded(
// child: ListView.builder(
// itemCount: listSearchHistory.value.length,
// itemBuilder: (context, idx) {
// return Card(
// child: Padding(
// padding: EdgeInsets.all(16.0),
// child: Column(
// crossAxisAlignment:
// CrossAxisAlignment.start,
// children: [
// FieldRowHistoryTransaksi(
// label: "Tipe",
// value: listSearchHistory
// .value[idx].tipe
// .toString(),
// ),
// SizedBox(height: 8.0),
// FieldRowHistoryTransaksi(
// label: "Tanggal",
// value: listSearchHistory
// .value[idx].tanggaltransaksi
// .toString(),
// ),
// SizedBox(height: 8.0),
// FieldRowHistoryTransaksi(
// label: "Nominal",
// value: listSearchHistory
// .value[idx].amount
// .toString(),
// // value: "nunggu api",
// ),
// SizedBox(height: 8.0),
// FieldRowHistoryTransaksi(
// label: "Kategori",
// value: listSearchHistory
// .value[idx].kategoriname
// .toString(),
// ),
// SizedBox(height: 8.0),
// if (listSearchHistory
// .value[idx].isconfirm ==
// "Y")
// Row(
// mainAxisAlignment:
// MainAxisAlignment.end,
// children: [
// Chip(
// label: Text(
// 'Confirmed',
// style: TextStyle(
// color:
// Constant.green_600),
// ),
// shape: RoundedRectangleBorder(
// side: BorderSide(
// color:
// Constant.green_600),
// borderRadius:
// BorderRadius.circular(
// 4.0),
// ),
// backgroundColor: Colors.white,
// ),
// ],
// ),
// SizedBox(
// height: Constant.getActualYPhone(
// context: context, y: 6),
// ),
// if (listSearchHistory
// .value[idx].isconfirm ==
// "N")
// Row(
// mainAxisAlignment:
// MainAxisAlignment.end,
// children: [
// ElevatedButton(
// onPressed: () {
// // Handle delete button tap
// },
// child: Text(
// 'Delete',
// style: TextStyle(
// color:
// Constant.textWhite),
// ),
// style: ElevatedButton.styleFrom(
// backgroundColor: Colors
// .red, // Ganti dengan warna delete button yang diinginkan
// ),
// ),
// ],
// )
// ],
// ),
// ),
// );
// },
// ),
// ),
Card(
elevation: 2.0,
child: Padding(
padding: const EdgeInsets.all(10),
child: Column(
// crossAxisAlignment: CrossAxisAlignment.start,
// mainAxisAlignment: MainAxisAlignment.start,
children: [
// atas
HistoryRowAtasWidget(),
// bawah
Row(),
],
),
),
),
],
),
),
),

View File

@@ -0,0 +1,76 @@
import 'package:equatable/equatable.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import '../../model/history_transaksi_model.dart';
import '../../repository/transaksi_repository.dart';
import '../../provider/dio_provider.dart';
import '../../repository/base_repository.dart';
abstract class SearchHistoryTransaksiState extends Equatable {
final DateTime date;
const SearchHistoryTransaksiState(this.date);
@override
List<Object?> get props => [date];
}
class SearchHistoryTransaksiStateInit extends SearchHistoryTransaksiState {
SearchHistoryTransaksiStateInit() : super(DateTime.now());
}
class SearchHistoryTransaksiStateLoading extends SearchHistoryTransaksiState {
SearchHistoryTransaksiStateLoading() : super(DateTime.now());
}
class SearchHistoryTransaksiStateError extends SearchHistoryTransaksiState {
final String message;
SearchHistoryTransaksiStateError({
required this.message,
}) : super(DateTime.now());
}
class SearchHistoryTransaksiStateDone extends SearchHistoryTransaksiState {
final List<HistoryTransaksiModel> model;
SearchHistoryTransaksiStateDone({
required this.model,
}) : super(DateTime.now());
}
//notifier
class SearchHistoryTransaksiNotifier
extends StateNotifier<SearchHistoryTransaksiState> {
final Ref ref;
SearchHistoryTransaksiNotifier({
required this.ref,
}) : super(SearchHistoryTransaksiStateInit());
void searchHistoryTransaksi(
String companyid,
String tglAwal,
String tglAkhir,
String categoryid,
) async {
try {
state = SearchHistoryTransaksiStateLoading();
final dio = ref.read(dioProvider);
final resp = await TransaksiRepository(dio: dio).getListHistoryTransaksi(
companyid,
tglAwal,
tglAkhir,
categoryid,
);
state = SearchHistoryTransaksiStateDone(model: resp);
} catch (e) {
if (e is BaseRepositoryException) {
state = SearchHistoryTransaksiStateError(message: e.message.toString());
} else {
state = SearchHistoryTransaksiStateError(message: e.toString());
}
}
}
}
//provider
final searchHistoryTransaksiProvider = StateNotifierProvider<
SearchHistoryTransaksiNotifier, SearchHistoryTransaksiState>(
(ref) => SearchHistoryTransaksiNotifier(ref: ref),
);