step 16 : fix dropdown sex in edit screen
This commit is contained in:
@@ -13,9 +13,7 @@ class ScanRepository extends BaseRepository {
|
||||
}) async {
|
||||
// final service = "${Constant.baseUrl}xauth/login";
|
||||
final service = "http://${host}/one-api/scan-ktp/Scanktp/listRiwayatScan";
|
||||
final resp = await post(param: {
|
||||
"userId":userId
|
||||
}, service: service);
|
||||
final resp = await post(param: {"userId": userId}, service: service);
|
||||
|
||||
final result = List<PersonKtp>.empty(growable: true);
|
||||
resp['data'].forEach((e) {
|
||||
@@ -62,4 +60,36 @@ class ScanRepository extends BaseRepository {
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// edit
|
||||
Future<String> prosesEdit({
|
||||
required String host,
|
||||
required String userId,
|
||||
required String Person_ID,
|
||||
required String Person_NIK,
|
||||
required String Person_Name,
|
||||
required String Person_Dob,
|
||||
required String Person_Sex,
|
||||
}) async {
|
||||
final service = "http://${host}/one-api/scan-ktp/Scanktp/proses_edit";
|
||||
final resp = await post(
|
||||
param: {
|
||||
"Person_ID": Person_ID,
|
||||
"Person_NIK": Person_NIK,
|
||||
"Person_Name": Person_Name,
|
||||
"Person_Dob": Person_Dob,
|
||||
"Person_Sex": Person_Sex,
|
||||
"userId": userId,
|
||||
},
|
||||
service: service,
|
||||
);
|
||||
|
||||
if (resp['status'] == "OK") {
|
||||
return "Sukses Update Data";
|
||||
} else {
|
||||
resp['message'];
|
||||
}
|
||||
|
||||
return resp['message'];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:scanktpflutter/model/sex_model.dart';
|
||||
import '../../app/app_extension.dart';
|
||||
import '../../app/route.dart';
|
||||
|
||||
@@ -49,6 +50,15 @@ class CardRiwayatScan extends HookConsumerWidget {
|
||||
// print('id : ${data.personID}');
|
||||
ref.read(selectedPersonIdx.notifier).state =
|
||||
data.personID;
|
||||
|
||||
// set SEX
|
||||
ref.read(eSexSelected.notifier).state = SexModel(
|
||||
M_SexID: data.personSex,
|
||||
M_SexCode: "",
|
||||
m_sexname: data.m_sexname,
|
||||
M_SexNameLang: ""
|
||||
);
|
||||
|
||||
ref.read(selectedEdit.notifier).state = EditPersonModel(
|
||||
personID: data.personID,
|
||||
personNIK: data.personNIK,
|
||||
|
||||
79
lib/screen/scan/edit_scan_provider.dart
Normal file
79
lib/screen/scan/edit_scan_provider.dart
Normal file
@@ -0,0 +1,79 @@
|
||||
import 'package:equatable/equatable.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import '../../repository/scan_repository.dart';
|
||||
|
||||
import '../../provider/dio_provider.dart';
|
||||
import '../../repository/base_repository.dart';
|
||||
|
||||
// 3. state provider
|
||||
final editScanProvider = StateNotifierProvider<EditScanNotifier, EditScanState>(
|
||||
(ref) => EditScanNotifier(ref: ref));
|
||||
|
||||
// 2. notifier
|
||||
class EditScanNotifier extends StateNotifier<EditScanState> {
|
||||
final Ref ref;
|
||||
EditScanNotifier({required this.ref}) : super(EditScanStateInit());
|
||||
void editScan({
|
||||
required String host,
|
||||
required String userId,
|
||||
required String Person_ID,
|
||||
required String Person_NIK,
|
||||
required String Person_Name,
|
||||
required String Person_Dob,
|
||||
required String Person_Sex,
|
||||
}) async {
|
||||
try {
|
||||
state = EditScanStateLoading();
|
||||
final resp = await ScanRepository(
|
||||
dio: ref.read(dioProvider),
|
||||
).prosesEdit(
|
||||
host: host,
|
||||
Person_ID: Person_ID,
|
||||
Person_NIK: Person_NIK,
|
||||
Person_Name: Person_Name,
|
||||
Person_Dob: Person_Dob,
|
||||
Person_Sex: Person_Sex,
|
||||
userId: userId,
|
||||
);
|
||||
|
||||
// print(resp);
|
||||
state = EditScanStateDone(pesan: resp);
|
||||
} catch (e) {
|
||||
if (e is BaseRepositoryException) {
|
||||
state = EditScanStateError(message: e.message);
|
||||
} else {
|
||||
state = EditScanStateError(message: e.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 1. state
|
||||
abstract class EditScanState extends Equatable {
|
||||
final DateTime date;
|
||||
const EditScanState(this.date);
|
||||
@override
|
||||
List<Object?> get props => [date];
|
||||
}
|
||||
|
||||
class EditScanStateInit extends EditScanState {
|
||||
EditScanStateInit() : super(DateTime.now());
|
||||
}
|
||||
|
||||
class EditScanStateLoading extends EditScanState {
|
||||
EditScanStateLoading() : super(DateTime.now());
|
||||
}
|
||||
|
||||
class EditScanStateError extends EditScanState {
|
||||
final String message;
|
||||
EditScanStateError({
|
||||
required this.message,
|
||||
}) : super(DateTime.now());
|
||||
}
|
||||
|
||||
class EditScanStateDone extends EditScanState {
|
||||
final String pesan;
|
||||
EditScanStateDone({
|
||||
required this.pesan,
|
||||
}) : super(DateTime.now());
|
||||
}
|
||||
@@ -1,7 +1,9 @@
|
||||
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';
|
||||
@@ -64,8 +66,27 @@ class EditScanScreen extends HookConsumerWidget {
|
||||
} 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: next.model[0].m_sexname);
|
||||
TextEditingController(text: ''); // atau nilai default lain
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -112,6 +133,12 @@ class EditScanScreen extends HookConsumerWidget {
|
||||
|
||||
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,
|
||||
@@ -124,11 +151,12 @@ class EditScanScreen extends HookConsumerWidget {
|
||||
// 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")
|
||||
initialDate: (listDataEdit.personDob != "0000-00-00")
|
||||
? DateTime.parse(listDataEdit.personDob)
|
||||
: DateTime.now(),
|
||||
firstDate: DateTime(2000),
|
||||
firstDate: DateTime(1900),
|
||||
lastDate: DateTime(2100),
|
||||
);
|
||||
|
||||
@@ -139,6 +167,35 @@ class EditScanScreen extends HookConsumerWidget {
|
||||
}
|
||||
}
|
||||
|
||||
// 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();
|
||||
@@ -204,6 +261,7 @@ class EditScanScreen extends HookConsumerWidget {
|
||||
),
|
||||
child: TextField(
|
||||
controller: ref.read(eNikCtr),
|
||||
keyboardType: TextInputType.number,
|
||||
decoration: InputDecoration(
|
||||
// hintText: "NIK",
|
||||
enabledBorder: const OutlineInputBorder(
|
||||
@@ -360,42 +418,63 @@ class EditScanScreen extends HookConsumerWidget {
|
||||
left: Constant.getActualYPhone(context: context, y: 12),
|
||||
right: Constant.getActualYPhone(context: context, y: 12),
|
||||
),
|
||||
child: DropdownMenu<SexModel>(
|
||||
initialSelection:
|
||||
(listSex.value.isNotEmpty) ? listSex.value[0] : null,
|
||||
controller: ref.read(eSexCtr),
|
||||
width: Constant.getActualXPhone(
|
||||
context: context, x: double.infinity),
|
||||
// hintText: "Jenis Kelamin",
|
||||
requestFocusOnTap: true,
|
||||
enableFilter: true,
|
||||
// label: const Text('Jenis Kelamin'),
|
||||
onSelected: (SexModel? sex) {
|
||||
if (sex != null) {
|
||||
ref.read(eSexSelected.notifier).state = sex;
|
||||
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();
|
||||
}
|
||||
},
|
||||
dropdownMenuEntries: listSex.value
|
||||
.map<DropdownMenuEntry<SexModel>>((SexModel sex) {
|
||||
return DropdownMenuEntry<SexModel>(
|
||||
value: sex,
|
||||
label: sex.m_sexname,
|
||||
);
|
||||
}).toList(),
|
||||
inputDecorationTheme: InputDecorationTheme(
|
||||
enabledBorder: const OutlineInputBorder(
|
||||
borderSide: BorderSide(
|
||||
color: Colors.grey,
|
||||
width: 1,
|
||||
buttonStyleData: ButtonStyleData(
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(5),
|
||||
border: Border.all(color: Colors.grey),
|
||||
),
|
||||
padding: EdgeInsets.symmetric(horizontal: 12),
|
||||
width: double.infinity,
|
||||
),
|
||||
focusedBorder: const OutlineInputBorder(
|
||||
borderSide: BorderSide(
|
||||
color: Colors.blue,
|
||||
width: 2,
|
||||
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();
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -426,7 +505,9 @@ class EditScanScreen extends HookConsumerWidget {
|
||||
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,
|
||||
@@ -434,10 +515,15 @@ class EditScanScreen extends HookConsumerWidget {
|
||||
|
||||
print(param);
|
||||
|
||||
// Navigator.of(context).pushNamedAndRemoveUntil(
|
||||
// homeRoute,
|
||||
// (route) => false,
|
||||
// );
|
||||
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,
|
||||
@@ -465,7 +551,7 @@ class EditScanScreen extends HookConsumerWidget {
|
||||
SizedBox(
|
||||
height: Constant.getActualYPhone(
|
||||
context: context,
|
||||
y: 20,
|
||||
y: 70,
|
||||
),
|
||||
),
|
||||
],
|
||||
|
||||
@@ -129,6 +129,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.0"
|
||||
dropdown_button2:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: dropdown_button2
|
||||
sha256: b0fe8d49a030315e9eef6c7ac84ca964250155a6224d491c1365061bc974a9e1
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.3.9"
|
||||
equatable:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
||||
@@ -48,6 +48,7 @@ dependencies:
|
||||
camera: ^0.10.6
|
||||
image: ^4.1.3
|
||||
permission_handler: ^11.3.0
|
||||
dropdown_button2: ^2.3.9
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
import '../../main.dart';
|
||||
import 'package:scanktpflutter/main.dart';
|
||||
|
||||
void main() {
|
||||
testWidgets('Counter increments smoke test', (WidgetTester tester) async {
|
||||
|
||||
Reference in New Issue
Block a user