Files
scan-ktp/lib/screen/scan/edit_scan_screen.dart
2025-02-18 07:48:09 +07:00

563 lines
19 KiB
Dart

import 'package:dropdown_button2/dropdown_button2.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:scanktpflutter/screen/scan/edit_scan_provider.dart';
import '../../model/sex_model.dart';
import '../../screen/scan/sex_provider.dart';
import '../../provider/scan_provider.dart';
import '../../widget/customsnackbarwidget.dart';
import '../../app/app_extension.dart';
import '../../app/constant.dart';
import '../../app/route.dart';
import '../../provider/current_user_provider.dart';
class EditScanScreen extends HookConsumerWidget {
const EditScanScreen({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays: [
SystemUiOverlay.bottom,
]);
final currentUser = ref.watch(currentUserProvider);
final host = currentUser?.host ?? "";
final userId = currentUser?.model.userId ?? "";
final baseUrl = "https://$host/";
final selectedPersonId = ref.watch(selectedPersonIdx);
final isLoading = useState<bool>(false);
final listDataEdit = ref.watch(selectedEdit);
final listSex = useState<List<SexModel>>(
List.empty(growable: true),
);
useEffect(() {
WidgetsBinding.instance.addPostFrameCallback((timeStamp) async {
final userID = currentUser?.model.userId ?? "0";
if (userID == "0") {
// not logged in
Navigator.of(context)
.pushNamedAndRemoveUntil(loginRoute, (route) => false);
return;
}
});
return () {};
}, [currentUser]);
// sex
ref.listen(sexProvider, (prev, next) {
if (next is SexStateLoading) {
isLoading.value = true;
} else if (next is SexStateError) {
isLoading.value = false;
// errorMessage.value = next.message;
snackbarWidget(
context,
next.message,
snackbarType.error,
Duration(seconds: 3),
);
} else if (next is SexStateDone) {
isLoading.value = false;
listSex.value = next.model;
// ref.read(eSexCtr.notifier).state =
// TextEditingController(text: next.model[0].m_sexname);
final sexSel = ref.read(selectedEdit.notifier).state;
if (next.model.isNotEmpty) {
final matchedItems = next.model
.where((item) => item.M_SexID == sexSel.personSex)
.toList();
if (matchedItems.length == 1) {
ref.read(eSexCtr.notifier).state = TextEditingController(
text: matchedItems[0].m_sexname,
);
} else {
// Jika lebih dari satu atau tidak ada yang cocok
print('Error: Multiple or no matching items found.');
// Bisa juga mengatur default value jika tidak ditemukan
ref.read(eSexCtr.notifier).state =
TextEditingController(text: ''); // atau nilai default lain
}
}
}
});
// isLoading
useEffect(() {
WidgetsBinding.instance.addPostFrameCallback((timestamp) async {
if (isLoading.value == true) {
snackbarWidget(
context,
"Sedang Memuat Data",
snackbarType.warning,
Duration(days: 1),
);
}
});
return () {};
}, [isLoading]);
// check person id
useEffect(() {
WidgetsBinding.instance.addPostFrameCallback((timestamp) async {
final personIDx = selectedPersonId;
if (personIDx == "0") {
snackbarWidget(
context,
'Gagal mendapatkan data',
snackbarType.error,
Duration(seconds: 3),
);
Navigator.of(context)
.pushNamedAndRemoveUntil(homeRoute, (route) => false);
return;
} else {
// listDataEdit
// set ke inputan
ref.read(eNikCtr.notifier).state =
TextEditingController(text: listDataEdit.personNIK);
ref.read(eNamaCtr.notifier).state =
TextEditingController(text: listDataEdit.personName);
ref.read(eDobCtr.notifier).state = TextEditingController(
text: formatDateJiffy(listDataEdit.personDob));
ref.read(eDobDt.notifier).state =
DateTime.parse(listDataEdit.personDob);
final parsedDate = DateTime.parse(listDataEdit.personDob);
// print("Parsed Date: $parsedDate");
ref.read(eDobDt.notifier).state = parsedDate;
// sex
ref.read(sexProvider.notifier).sex(
host: host,
);
}
});
return () {};
}, [selectedPersonId]);
// date picker
Future<void> _selectDate(BuildContext context, WidgetRef ref) async {
DateTime? newSelectedDate = await showDatePicker(
initialEntryMode: DatePickerEntryMode.calendarOnly,
context: context,
initialDate: (listDataEdit.personDob != "0000-00-00")
? DateTime.parse(listDataEdit.personDob)
: DateTime.now(),
firstDate: DateTime(1900),
lastDate: DateTime(2100),
);
if (newSelectedDate != null) {
ref.read(eDobDt.notifier).state = newSelectedDate;
ref.read(eDobCtr.notifier).state.text =
formatDateJiffy(newSelectedDate.toLocal().toString());
}
}
// proses edit
ref.listen(editScanProvider, (prev, next) {
if (next is EditScanStateLoading) {
isLoading.value = true;
} else if (next is EditScanStateError) {
isLoading.value = false;
// errorMessage.value = next.message;
snackbarWidget(
context,
next.message,
snackbarType.error,
Duration(seconds: 3),
);
} else if (next is EditScanStateDone) {
isLoading.value = false;
snackbarWidget(
context,
next.pesan,
snackbarType.success,
Duration(seconds: 3),
);
Navigator.of(context).pushNamedAndRemoveUntil(
homeRoute,
(route) => false,
);
return;
}
});
return GestureDetector(
onTap: () {
FocusManager.instance.primaryFocus!.unfocus();
},
child: Scaffold(
resizeToAvoidBottomInset: true,
backgroundColor: Constant.bgGrey,
body: ListView(
// crossAxisAlignment: CrossAxisAlignment.start,
children: [
// atas
Image.asset(
'images/vektoratas.png',
width: double.infinity,
fit: BoxFit.cover,
),
SizedBox(
height: Constant.getActualYPhone(
context: context,
y: 34,
),
),
// image ktp
Padding(
padding: EdgeInsets.only(
left: Constant.getActualYPhone(context: context, y: 12),
right: Constant.getActualYPhone(context: context, y: 12),
),
child: Image.network(
baseUrl + listDataEdit.personUrl,
fit: BoxFit.fitWidth,
),
),
SizedBox(
height: Constant.getActualYPhone(
context: context,
y: 32,
),
),
// inputan nik
Padding(
padding: EdgeInsets.only(
left: Constant.getActualYPhone(context: context, y: 12),
right: Constant.getActualYPhone(context: context, y: 12),
),
child: Text(
'NIK',
style: Constant.title_400(context: context).copyWith(
color: Constant.inputanGrey,
),
),
),
SizedBox(
height: Constant.getActualYPhone(
context: context,
y: 16,
),
),
Padding(
padding: EdgeInsets.only(
left: Constant.getActualYPhone(context: context, y: 12),
right: Constant.getActualYPhone(context: context, y: 12),
),
child: TextField(
controller: ref.read(eNikCtr),
keyboardType: TextInputType.number,
decoration: InputDecoration(
// hintText: "NIK",
enabledBorder: const OutlineInputBorder(
borderSide: BorderSide(
color: Colors.grey,
width: 1,
),
),
focusedBorder: const OutlineInputBorder(
borderSide: BorderSide(
color: Colors.blue,
width: 2,
),
),
),
),
),
SizedBox(
height: Constant.getActualYPhone(
context: context,
y: 16,
),
),
// inputan nama
Padding(
padding: EdgeInsets.only(
left: Constant.getActualYPhone(context: context, y: 12),
right: Constant.getActualYPhone(context: context, y: 12),
),
child: Text(
'Nama',
style: Constant.title_400(context: context).copyWith(
color: Constant.inputanGrey,
),
),
),
SizedBox(
height: Constant.getActualYPhone(
context: context,
y: 16,
),
),
Padding(
padding: EdgeInsets.only(
left: Constant.getActualYPhone(context: context, y: 12),
right: Constant.getActualYPhone(context: context, y: 12),
),
child: TextField(
controller: ref.read(eNamaCtr),
decoration: InputDecoration(
// hintText: "NIK",
enabledBorder: const OutlineInputBorder(
borderSide: BorderSide(
color: Colors.grey,
width: 1,
),
),
focusedBorder: const OutlineInputBorder(
borderSide: BorderSide(
color: Colors.blue,
width: 2,
),
),
),
),
),
SizedBox(
height: Constant.getActualYPhone(
context: context,
y: 16,
),
),
// inputan dob
Padding(
padding: EdgeInsets.only(
left: Constant.getActualYPhone(context: context, y: 12),
right: Constant.getActualYPhone(context: context, y: 12),
),
child: Text(
'DOB',
style: Constant.title_400(context: context).copyWith(
color: Constant.inputanGrey,
),
),
),
SizedBox(
height: Constant.getActualYPhone(
context: context,
y: 16,
),
),
Padding(
padding: EdgeInsets.only(
left: Constant.getActualYPhone(context: context, y: 12),
right: Constant.getActualYPhone(context: context, y: 12),
),
child: TextField(
readOnly: true,
controller: ref.read(eDobCtr),
onTap: () {
_selectDate(context, ref);
},
decoration: InputDecoration(
// hintText: "NIK",
suffixIcon: IconButton(
icon: Icon(Icons.calendar_today,
color: Constant.textCardGrey),
onPressed: () {
_selectDate(context, ref);
},
),
enabledBorder: const OutlineInputBorder(
borderSide: BorderSide(
color: Colors.grey,
width: 1,
),
),
focusedBorder: const OutlineInputBorder(
borderSide: BorderSide(
color: Colors.blue,
width: 2,
),
),
),
),
),
SizedBox(
height: Constant.getActualYPhone(
context: context,
y: 16,
),
),
// inputan jenis kelamin
Padding(
padding: EdgeInsets.only(
left: Constant.getActualYPhone(context: context, y: 12),
right: Constant.getActualYPhone(context: context, y: 12),
),
child: Text(
'Jenis Kelamin',
style: Constant.title_400(context: context).copyWith(
color: Constant.inputanGrey,
),
),
),
SizedBox(
height: Constant.getActualYPhone(
context: context,
y: 16,
),
),
Padding(
padding: EdgeInsets.only(
left: Constant.getActualYPhone(context: context, y: 12),
right: Constant.getActualYPhone(context: context, y: 12),
),
child: DropdownButtonHideUnderline(
child: DropdownButton2<SexModel>(
isExpanded: true,
value: (listSex.value.isNotEmpty)
? listSex.value.firstWhere(
(sex) =>
sex.M_SexID ==
ref.read(eSexSelected.notifier).state.M_SexID,
orElse: () => listSex.value[0],
)
: null,
items: listSex.value.map((SexModel g) {
return DropdownMenuItem<SexModel>(
value: g,
child: Text(
g.m_sexname,
style: Constant.title_400(context: context).copyWith(
color: Colors.black,
fontWeight: FontWeight.normal,
),
),
);
}).toList(),
onChanged: (SexModel? value) {
if (value != null) {
ref.read(eSexSelected.notifier).state = value;
ref.read(eSexCtr.notifier).state = TextEditingController(
text: value.m_sexname,
);
FocusScope.of(context).unfocus();
}
},
buttonStyleData: ButtonStyleData(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5),
border: Border.all(color: Colors.grey),
),
padding: EdgeInsets.symmetric(horizontal: 12),
width: double.infinity,
),
dropdownStyleData: DropdownStyleData(
maxHeight: 100,
width: MediaQuery.of(context).size.width - 20,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5),
color: Colors.white,
),
offset: Offset(0, 2),
),
menuItemStyleData: MenuItemStyleData(
padding: EdgeInsets.symmetric(horizontal: 12, vertical: 8),
),
onMenuStateChange: (isOpen) {
if (!isOpen) {
ref.read(eSexCtr).clear();
}
},
),
),
),
SizedBox(
height: Constant.getActualYPhone(
context: context,
y: 44,
),
),
// button save
Padding(
padding: EdgeInsets.only(
left: Constant.getActualXPhone(
context: context,
x: 16,
),
right: Constant.getActualXPhone(
context: context,
x: 16,
),
),
child: SizedBox(
width: double.infinity,
height: Constant.getActualYPhone(
context: context,
y: 48,
),
child: ElevatedButton(
onPressed: () {
var param = {
"userId": userId,
"Person_ID": selectedPersonId,
"Person_NIK": ref.read(eNikCtr).text,
"Person_Name": ref.read(eNamaCtr).text,
"Person_Dob": ref.read(eDobCtr).text,
"Person_Sex": ref.read(eSexSelected).M_SexID,
};
print(param);
ref.read(editScanProvider.notifier).editScan(
host: host,
userId: userId,
Person_ID: selectedPersonId,
Person_NIK: ref.read(eNikCtr).text,
Person_Name: ref.read(eNamaCtr).text,
Person_Dob: ref.read(eDobCtr).text,
Person_Sex: ref.read(eSexSelected).M_SexID,
);
},
style: ElevatedButton.styleFrom(
backgroundColor: Constant.bgButton,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
),
elevation: 8,
shadowColor: Constant.bgButton.withOpacity(0.24),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'SAVE',
style:
Constant.titleButton500(context: context).copyWith(
color: Constant.textWhite,
),
),
],
),
),
),
),
SizedBox(
height: Constant.getActualYPhone(
context: context,
y: 70,
),
),
],
),
),
);
}
}