step 16 : fix dropdown sex in edit screen
This commit is contained in:
@@ -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'];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
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/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,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
Reference in New Issue
Block a user