step 18 : history widget atas cmp
This commit is contained in:
@@ -15,8 +15,7 @@ class Constant {
|
||||
// static String baseUrl = "https://devregonline.pramita.co.id/one-api/xdoc/";
|
||||
|
||||
// tester devbandungraya
|
||||
static String baseUrlDevoneReport =
|
||||
"devone.aplikasi.web.id";
|
||||
static String baseUrlDevoneReport = "devone.aplikasi.web.id";
|
||||
|
||||
static String baseUrlDevone =
|
||||
"http://devone.aplikasi.web.id/one-api-pettycash/pettycash/";
|
||||
|
||||
64
app_petty_cash/lib/model/history_transaksi_model.dart
Normal file
64
app_petty_cash/lib/model/history_transaksi_model.dart
Normal file
@@ -0,0 +1,64 @@
|
||||
class HistoryTransaksiModel {
|
||||
String? id;
|
||||
String? tanggaltransaksi;
|
||||
String? tipe;
|
||||
String? kategoriid;
|
||||
String? kategoriname;
|
||||
String? note;
|
||||
String? amount;
|
||||
String? sender;
|
||||
String? imgurl;
|
||||
String? isconfirm;
|
||||
String? tanggalconfirm;
|
||||
String? usertransaksi;
|
||||
String? userconfirm;
|
||||
|
||||
HistoryTransaksiModel(
|
||||
{this.id,
|
||||
this.tanggaltransaksi,
|
||||
this.tipe,
|
||||
this.kategoriid,
|
||||
this.kategoriname,
|
||||
this.note,
|
||||
this.amount,
|
||||
this.sender,
|
||||
this.imgurl,
|
||||
this.isconfirm,
|
||||
this.tanggalconfirm,
|
||||
this.usertransaksi,
|
||||
this.userconfirm});
|
||||
|
||||
HistoryTransaksiModel.fromJson(Map<String, dynamic> json) {
|
||||
id = json['id'];
|
||||
tanggaltransaksi = json['tanggaltransaksi'];
|
||||
tipe = json['tipe'];
|
||||
kategoriid = json['kategoriid'];
|
||||
kategoriname = json['kategoriname'];
|
||||
note = json['note'];
|
||||
amount = json['amount'];
|
||||
sender = json['sender'];
|
||||
imgurl = json['imgurl'];
|
||||
isconfirm = json['isconfirm'];
|
||||
tanggalconfirm = json['tanggalconfirm'];
|
||||
usertransaksi = json['usertransaksi'];
|
||||
userconfirm = json['userconfirm'];
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final Map<String, dynamic> data = new Map<String, dynamic>();
|
||||
data['id'] = this.id;
|
||||
data['tanggaltransaksi'] = this.tanggaltransaksi;
|
||||
data['tipe'] = this.tipe;
|
||||
data['kategoriid'] = this.kategoriid;
|
||||
data['kategoriname'] = this.kategoriname;
|
||||
data['note'] = this.note;
|
||||
data['amount'] = this.amount;
|
||||
data['sender'] = this.sender;
|
||||
data['imgurl'] = this.imgurl;
|
||||
data['isconfirm'] = this.isconfirm;
|
||||
data['tanggalconfirm'] = this.tanggalconfirm;
|
||||
data['usertransaksi'] = this.usertransaksi;
|
||||
data['userconfirm'] = this.userconfirm;
|
||||
return data;
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
import 'package:app_petty_cash/model/list_type_model.dart';
|
||||
|
||||
import '../app/constant.dart';
|
||||
import '../model/history_transaksi_model.dart';
|
||||
import '../model/list_category_model.dart';
|
||||
import 'base_repository.dart';
|
||||
|
||||
@@ -93,4 +94,31 @@ class TransaksiRepository extends BaseRepository {
|
||||
|
||||
return resp['status'];
|
||||
}
|
||||
|
||||
// list history transaksi
|
||||
Future<List<HistoryTransaksiModel>> getListHistoryTransaksi(
|
||||
String companyid,
|
||||
String tglAwal,
|
||||
String tglAkhir,
|
||||
String categoryid,
|
||||
) async {
|
||||
final service =
|
||||
"${Constant.baseUrlDevone}/homescreen/list_transaction/?companyid=$companyid&startdate=$tglAwal&enddate=$tglAkhir&kategoriid=$categoryid";
|
||||
// https://devone.aplikasi.web.id/one-api-pettycash/pettycash/history/list_transaction/?companyid=1&startdate=2023-12-01&enddate=2023-12-30&kategoriid=0
|
||||
final resp = await get(
|
||||
// param: {
|
||||
// "": "",
|
||||
// },
|
||||
service: service,
|
||||
);
|
||||
|
||||
print("url list history transaksi : $service");
|
||||
|
||||
final result = List<HistoryTransaksiModel>.empty(growable: true);
|
||||
resp['data'].forEach((e) {
|
||||
final model = HistoryTransaksiModel.fromJson(e);
|
||||
result.add(model);
|
||||
});
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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(),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
@@ -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),
|
||||
);
|
||||
@@ -162,44 +162,44 @@ class CustomDrawer extends HookConsumerWidget {
|
||||
Navigator.pushNamed(context, reportRoute);
|
||||
},
|
||||
),
|
||||
ListTile(
|
||||
title: Text(
|
||||
'User',
|
||||
style: TextStyle(
|
||||
color: (currentMenu == 4)
|
||||
? Constant.textWhite
|
||||
: Constant.textBlack,
|
||||
),
|
||||
),
|
||||
tileColor: (currentMenu == 4)
|
||||
? Constant.pcBtnBackgroundColor
|
||||
: Colors.transparent,
|
||||
onTap: () {
|
||||
// Handle navigation to User screen
|
||||
Navigator.pop(context);
|
||||
ref.read(currentPageProvider.state).update((state) => 4);
|
||||
Navigator.pushNamed(context, userRoute);
|
||||
},
|
||||
),
|
||||
ListTile(
|
||||
title: Text(
|
||||
'Change Company',
|
||||
style: TextStyle(
|
||||
color: (currentMenu == 5)
|
||||
? Constant.textWhite
|
||||
: Constant.textBlack,
|
||||
),
|
||||
),
|
||||
tileColor: (currentMenu == 5)
|
||||
? Constant.pcBtnBackgroundColor
|
||||
: Colors.transparent,
|
||||
onTap: () {
|
||||
// Handle navigation to User screen
|
||||
Navigator.pop(context);
|
||||
ref.read(currentPageProvider.state).update((state) => 5);
|
||||
Navigator.pushNamed(context, changeCompanyRoute);
|
||||
},
|
||||
),
|
||||
// ListTile(
|
||||
// title: Text(
|
||||
// 'User',
|
||||
// style: TextStyle(
|
||||
// color: (currentMenu == 4)
|
||||
// ? Constant.textWhite
|
||||
// : Constant.textBlack,
|
||||
// ),
|
||||
// ),
|
||||
// tileColor: (currentMenu == 4)
|
||||
// ? Constant.pcBtnBackgroundColor
|
||||
// : Colors.transparent,
|
||||
// onTap: () {
|
||||
// // Handle navigation to User screen
|
||||
// Navigator.pop(context);
|
||||
// ref.read(currentPageProvider.state).update((state) => 4);
|
||||
// Navigator.pushNamed(context, userRoute);
|
||||
// },
|
||||
// ),
|
||||
// ListTile(
|
||||
// title: Text(
|
||||
// 'Change Company',
|
||||
// style: TextStyle(
|
||||
// color: (currentMenu == 5)
|
||||
// ? Constant.textWhite
|
||||
// : Constant.textBlack,
|
||||
// ),
|
||||
// ),
|
||||
// tileColor: (currentMenu == 5)
|
||||
// ? Constant.pcBtnBackgroundColor
|
||||
// : Colors.transparent,
|
||||
// onTap: () {
|
||||
// // Handle navigation to User screen
|
||||
// Navigator.pop(context);
|
||||
// ref.read(currentPageProvider.state).update((state) => 5);
|
||||
// Navigator.pushNamed(context, changeCompanyRoute);
|
||||
// },
|
||||
// ),
|
||||
ListTile(
|
||||
title: Text(
|
||||
'Logout',
|
||||
|
||||
110
app_petty_cash/lib/widget/history_row_atas_widget.dart
Normal file
110
app_petty_cash/lib/widget/history_row_atas_widget.dart
Normal file
@@ -0,0 +1,110 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
|
||||
import '../app/constant.dart';
|
||||
|
||||
class HistoryRowAtasWidget extends HookConsumerWidget {
|
||||
const HistoryRowAtasWidget({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
return Row(
|
||||
children: [
|
||||
// kiri
|
||||
Container(
|
||||
width: Constant.getActualXPhone(context: context, x: 38),
|
||||
height: Constant.getActualYPhone(context: context, y: 38),
|
||||
decoration: BoxDecoration(
|
||||
color: Color.fromRGBO(241, 90, 41, 0.08),
|
||||
borderRadius: BorderRadius.all(
|
||||
Radius.circular(8.0),
|
||||
),
|
||||
),
|
||||
// child: Text('s'),
|
||||
child: SvgPicture.network(
|
||||
'https://devone.aplikasi.web.id/pettycash-media/icon/icon_12.svg',
|
||||
semanticsLabel: 'Icon pizza',
|
||||
placeholderBuilder: (BuildContext context) => Container(
|
||||
padding: const EdgeInsets.all(30.0),
|
||||
child: const CircularProgressIndicator(),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
// tengah
|
||||
Expanded(
|
||||
child: Padding(
|
||||
padding: EdgeInsets.only(left: 20),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
'Makanan & Minuman',
|
||||
style: Constant.body2_600(context: context).copyWith(
|
||||
fontWeight: FontWeight.w600, color: Constant.textBlack),
|
||||
),
|
||||
SizedBox(
|
||||
height: Constant.getActualYPhone(
|
||||
context: context,
|
||||
y: 8,
|
||||
),
|
||||
),
|
||||
Text(
|
||||
'100000',
|
||||
style: Constant.body1_600(context: context).copyWith(
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Constant.pcBtnBackgroundColor),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
// kanan
|
||||
Expanded(
|
||||
child: Padding(
|
||||
padding: EdgeInsets.only(right: 8),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.end,
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: [
|
||||
Container(
|
||||
// width: Constant.getActualXPhone(context: context, x: 32),
|
||||
height: Constant.getActualYPhone(context: context, y: 19),
|
||||
decoration: BoxDecoration(
|
||||
color: Color.fromRGBO(241, 90, 41, 0.16),
|
||||
borderRadius: BorderRadius.all(
|
||||
Radius.circular(6.0),
|
||||
),
|
||||
),
|
||||
child: Padding(
|
||||
padding: EdgeInsets.all(2.0),
|
||||
child: Text(
|
||||
'Kredit',
|
||||
style: Constant.body1_600(context: context).copyWith(
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Constant.pcBtnBackgroundColor),
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
height: Constant.getActualYPhone(
|
||||
context: context,
|
||||
y: 8,
|
||||
),
|
||||
),
|
||||
Text(
|
||||
'15 Des 2023',
|
||||
style: Constant.body1_600(context: context).copyWith(
|
||||
fontWeight: FontWeight.w600, color: Constant.textGreyv2),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user