step 16 : fix dropdown sex in edit screen

This commit is contained in:
sindhu
2025-02-18 07:48:09 +07:00
parent 6af18dbe58
commit 34ef739107
7 changed files with 263 additions and 49 deletions

View File

@@ -13,9 +13,7 @@ class ScanRepository extends BaseRepository {
}) async { }) async {
// final service = "${Constant.baseUrl}xauth/login"; // final service = "${Constant.baseUrl}xauth/login";
final service = "http://${host}/one-api/scan-ktp/Scanktp/listRiwayatScan"; final service = "http://${host}/one-api/scan-ktp/Scanktp/listRiwayatScan";
final resp = await post(param: { final resp = await post(param: {"userId": userId}, service: service);
"userId":userId
}, service: service);
final result = List<PersonKtp>.empty(growable: true); final result = List<PersonKtp>.empty(growable: true);
resp['data'].forEach((e) { resp['data'].forEach((e) {
@@ -62,4 +60,36 @@ class ScanRepository extends BaseRepository {
return result; 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'];
}
} }

View File

@@ -1,6 +1,7 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:scanktpflutter/model/sex_model.dart';
import '../../app/app_extension.dart'; import '../../app/app_extension.dart';
import '../../app/route.dart'; import '../../app/route.dart';
@@ -49,6 +50,15 @@ class CardRiwayatScan extends HookConsumerWidget {
// print('id : ${data.personID}'); // print('id : ${data.personID}');
ref.read(selectedPersonIdx.notifier).state = ref.read(selectedPersonIdx.notifier).state =
data.personID; 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( ref.read(selectedEdit.notifier).state = EditPersonModel(
personID: data.personID, personID: data.personID,
personNIK: data.personNIK, personNIK: data.personNIK,

View 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());
}

View File

@@ -1,7 +1,9 @@
import 'package:dropdown_button2/dropdown_button2.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:scanktpflutter/screen/scan/edit_scan_provider.dart';
import '../../model/sex_model.dart'; import '../../model/sex_model.dart';
import '../../screen/scan/sex_provider.dart'; import '../../screen/scan/sex_provider.dart';
import '../../provider/scan_provider.dart'; import '../../provider/scan_provider.dart';
@@ -64,8 +66,27 @@ class EditScanScreen extends HookConsumerWidget {
} else if (next is SexStateDone) { } else if (next is SexStateDone) {
isLoading.value = false; isLoading.value = false;
listSex.value = next.model; listSex.value = next.model;
ref.read(eSexCtr.notifier).state = // ref.read(eSexCtr.notifier).state =
TextEditingController(text: next.model[0].m_sexname); // 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
}
}
} }
}); });
@@ -112,6 +133,12 @@ class EditScanScreen extends HookConsumerWidget {
ref.read(eDobDt.notifier).state = ref.read(eDobDt.notifier).state =
DateTime.parse(listDataEdit.personDob); DateTime.parse(listDataEdit.personDob);
final parsedDate = DateTime.parse(listDataEdit.personDob);
// print("Parsed Date: $parsedDate");
ref.read(eDobDt.notifier).state = parsedDate;
// sex // sex
ref.read(sexProvider.notifier).sex( ref.read(sexProvider.notifier).sex(
host: host, host: host,
@@ -124,11 +151,12 @@ class EditScanScreen extends HookConsumerWidget {
// date picker // date picker
Future<void> _selectDate(BuildContext context, WidgetRef ref) async { Future<void> _selectDate(BuildContext context, WidgetRef ref) async {
DateTime? newSelectedDate = await showDatePicker( DateTime? newSelectedDate = await showDatePicker(
initialEntryMode: DatePickerEntryMode.calendarOnly,
context: context, context: context,
initialDate: (listDataEdit.personDob == "0000-00-00") initialDate: (listDataEdit.personDob != "0000-00-00")
? DateTime.parse(listDataEdit.personDob) ? DateTime.parse(listDataEdit.personDob)
: DateTime.now(), : DateTime.now(),
firstDate: DateTime(2000), firstDate: DateTime(1900),
lastDate: DateTime(2100), 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( return GestureDetector(
onTap: () { onTap: () {
FocusManager.instance.primaryFocus!.unfocus(); FocusManager.instance.primaryFocus!.unfocus();
@@ -204,6 +261,7 @@ class EditScanScreen extends HookConsumerWidget {
), ),
child: TextField( child: TextField(
controller: ref.read(eNikCtr), controller: ref.read(eNikCtr),
keyboardType: TextInputType.number,
decoration: InputDecoration( decoration: InputDecoration(
// hintText: "NIK", // hintText: "NIK",
enabledBorder: const OutlineInputBorder( enabledBorder: const OutlineInputBorder(
@@ -360,42 +418,63 @@ class EditScanScreen extends HookConsumerWidget {
left: Constant.getActualYPhone(context: context, y: 12), left: Constant.getActualYPhone(context: context, y: 12),
right: Constant.getActualYPhone(context: context, y: 12), right: Constant.getActualYPhone(context: context, y: 12),
), ),
child: DropdownMenu<SexModel>( child: DropdownButtonHideUnderline(
initialSelection: child: DropdownButton2<SexModel>(
(listSex.value.isNotEmpty) ? listSex.value[0] : null, isExpanded: true,
controller: ref.read(eSexCtr), value: (listSex.value.isNotEmpty)
width: Constant.getActualXPhone( ? listSex.value.firstWhere(
context: context, x: double.infinity), (sex) =>
// hintText: "Jenis Kelamin", sex.M_SexID ==
requestFocusOnTap: true, ref.read(eSexSelected.notifier).state.M_SexID,
enableFilter: true, orElse: () => listSex.value[0],
// label: const Text('Jenis Kelamin'), )
onSelected: (SexModel? sex) { : null,
if (sex != null) { items: listSex.value.map((SexModel g) {
ref.read(eSexSelected.notifier).state = sex; return DropdownMenuItem<SexModel>(
FocusScope.of(context).unfocus(); value: g,
} child: Text(
}, g.m_sexname,
dropdownMenuEntries: listSex.value style: Constant.title_400(context: context).copyWith(
.map<DropdownMenuEntry<SexModel>>((SexModel sex) { color: Colors.black,
return DropdownMenuEntry<SexModel>( fontWeight: FontWeight.normal,
value: sex, ),
label: sex.m_sexname, ),
); );
}).toList(), }).toList(),
inputDecorationTheme: InputDecorationTheme( onChanged: (SexModel? value) {
enabledBorder: const OutlineInputBorder( if (value != null) {
borderSide: BorderSide( ref.read(eSexSelected.notifier).state = value;
color: Colors.grey, ref.read(eSexCtr.notifier).state = TextEditingController(
width: 1, 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,
), ),
focusedBorder: const OutlineInputBorder( dropdownStyleData: DropdownStyleData(
borderSide: BorderSide( maxHeight: 100,
color: Colors.blue, width: MediaQuery.of(context).size.width - 20,
width: 2, 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,18 +505,25 @@ class EditScanScreen extends HookConsumerWidget {
child: ElevatedButton( child: ElevatedButton(
onPressed: () { onPressed: () {
var param = { var param = {
"Person_ID":selectedPersonId, "userId": userId,
"Person_Name":ref.read(eNamaCtr).text, "Person_ID": selectedPersonId,
"Person_Dob":ref.read(eDobCtr).text, "Person_NIK": ref.read(eNikCtr).text,
"Person_Sex":ref.read(eSexSelected).M_SexID, "Person_Name": ref.read(eNamaCtr).text,
"Person_Dob": ref.read(eDobCtr).text,
"Person_Sex": ref.read(eSexSelected).M_SexID,
}; };
print(param); print(param);
// Navigator.of(context).pushNamedAndRemoveUntil( ref.read(editScanProvider.notifier).editScan(
// homeRoute, host: host,
// (route) => false, 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( style: ElevatedButton.styleFrom(
backgroundColor: Constant.bgButton, backgroundColor: Constant.bgButton,
@@ -465,7 +551,7 @@ class EditScanScreen extends HookConsumerWidget {
SizedBox( SizedBox(
height: Constant.getActualYPhone( height: Constant.getActualYPhone(
context: context, context: context,
y: 20, y: 70,
), ),
), ),
], ],

View File

@@ -129,6 +129,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.1.0" 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: equatable:
dependency: "direct main" dependency: "direct main"
description: description:

View File

@@ -48,6 +48,7 @@ dependencies:
camera: ^0.10.6 camera: ^0.10.6
image: ^4.1.3 image: ^4.1.3
permission_handler: ^11.3.0 permission_handler: ^11.3.0
dropdown_button2: ^2.3.9
dev_dependencies: dev_dependencies:
flutter_test: flutter_test:

View File

@@ -8,7 +8,7 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import '../../main.dart'; import 'package:scanktpflutter/main.dart';
void main() { void main() {
testWidgets('Counter increments smoke test', (WidgetTester tester) async { testWidgets('Counter increments smoke test', (WidgetTester tester) async {