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 {
// 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'];
}
}

View File

@@ -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,

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/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);
// 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
}
}
}
});
@@ -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;
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,
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,
),
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,18 +505,25 @@ class EditScanScreen extends HookConsumerWidget {
child: ElevatedButton(
onPressed: () {
var param = {
"Person_ID":selectedPersonId,
"Person_Name":ref.read(eNamaCtr).text,
"Person_Dob":ref.read(eDobCtr).text,
"Person_Sex":ref.read(eSexSelected).M_SexID,
"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);
// 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,
),
),
],

View File

@@ -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:

View File

@@ -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:

View File

@@ -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 {