diff --git a/README.md b/README.md index 7301bf6..33e4576 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@ # onemd -Create web/md_mitra_lab.html +>Create web/md_mitra_lab.html +>(* will be build and ulded to one-ui-flutter/md-mitra/) + ```html @@ -62,10 +64,12 @@ ul_flutter_ui devone.aplikasi.web.id # one-ui from existing vuejs +( one-ui/flutter/one-md-mitralab/ ) >used file : > index.php > store.js -update store.js + +>update store.js ```js import system from "../../apps/modules/system/system.js"; export const store = new Vuex.Store({ @@ -75,7 +79,7 @@ export const store = new Vuex.Store({ }); ``` -update index.php +>update index.php ```php diff --git a/lib/js/initial_route.dart b/lib/js/initial_route.dart index df01629..066e1fc 100644 --- a/lib/js/initial_route.dart +++ b/lib/js/initial_route.dart @@ -5,6 +5,9 @@ import 'dart:html' as html; @JS('fx_initial_route') external String fxInitialRoute(); +@JS('parent_home') +external String parentHome(); + String? getToken() { return html.window.localStorage['token']; } diff --git a/lib/model/ac_doctor_model.dart b/lib/model/ac_doctor_model.dart new file mode 100644 index 0000000..7d83a26 --- /dev/null +++ b/lib/model/ac_doctor_model.dart @@ -0,0 +1,48 @@ +class AcDoctorResponseModel { + late String fullName; + late String mDoctorID; + AcDoctorResponseModel({ + required this.fullName, + required this.mDoctorID, + }); + + AcDoctorResponseModel.fromJson(Map json) { + fullName = json['FullName']; + mDoctorID = json['M_DoctorID']; + } + + Map toJson() { + final Map data = {}; + data['FullName'] = fullName; + data['M_DoctorID'] = mDoctorID; + return data; + } +} + +class AcDoctorAddressResponseModel { + late String mDoctorAddressDescription; + late String mDoctorAddressID; + late bool isCheck; + + AcDoctorAddressResponseModel({ + required this.mDoctorAddressDescription, + required this.mDoctorAddressID, + }); + + void setIsCheck(bool val) { + isCheck = val; + } + + AcDoctorAddressResponseModel.fromJson(Map json) { + mDoctorAddressDescription = json['M_DoctorAddressDescription']; + mDoctorAddressID = json['M_DoctorAddressID']; + } + + Map toJson() { + final Map data = {}; + data['M_DoctorAddressDescription'] = mDoctorAddressDescription; + data['M_DoctorAddressID'] = mDoctorAddressID; + data['isCheck'] = isCheck; + return data; + } +} diff --git a/lib/model/ac_mou_response_model.dart b/lib/model/ac_mou_response_model.dart index 4a71976..89a1b90 100644 --- a/lib/model/ac_mou_response_model.dart +++ b/lib/model/ac_mou_response_model.dart @@ -7,7 +7,7 @@ class AcMouResponseModel { late String mMouNote; late String mMouNumber; late String mMouStartDate; - + late bool isCheck; AcMouResponseModel({ required this.mMouEndDate, required this.mMouID, @@ -17,6 +17,7 @@ class AcMouResponseModel { required this.mMouNote, required this.mMouNumber, required this.mMouStartDate, + this.isCheck = false, }); AcMouResponseModel.fromJson(Map json) { @@ -28,6 +29,10 @@ class AcMouResponseModel { mMouNote = json['M_MouNote'] ?? ""; mMouNumber = json['M_MouNumber'] ?? ""; mMouStartDate = json['M_MouStartDate'] ?? ""; + isCheck = false; + } + void setCheck(bool val) { + isCheck = val; } Map toJson() { diff --git a/lib/provider/local_auth_provider.dart b/lib/provider/local_auth_provider.dart index e821155..9d50e27 100644 --- a/lib/provider/local_auth_provider.dart +++ b/lib/provider/local_auth_provider.dart @@ -4,11 +4,9 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import '../js/initial_route.dart'; import '../model/one_user_model.dart'; -// ignore: avoid_web_libraries_in_flutter -import 'dart:html' as html; void redirectToHome() { - html.window.location.href = "/one-ui/"; + parentHome(); } final localAuthProvider = Provider((ref) { diff --git a/lib/repository/mitra_repository.dart b/lib/repository/mitra_repository.dart index d996d2c..04d30c7 100644 --- a/lib/repository/mitra_repository.dart +++ b/lib/repository/mitra_repository.dart @@ -2,6 +2,7 @@ import 'package:dio/dio.dart'; import '../app/constants.dart'; import '../model/ac_company_response_model.dart'; +import '../model/ac_doctor_model.dart'; import '../model/ac_mou_response_model.dart'; import '../model/mitra_response_model.dart'; import 'base_repository.dart'; @@ -24,6 +25,37 @@ class MitraRepository extends BaseRepository { return result; } + Future> lookupDoctor({ + required String query, + CancelToken? cancelToken, + }) async { + final param = {"query": query}; + final service = "${Constants.baseUrl}md/lookup_doctor"; + final resp = await post( + service: service, jsonParam: param, cancelToken: cancelToken); + final List result = List.empty(growable: true); + for (final el in resp["data"]) { + final model = AcDoctorResponseModel.fromJson(el); + result.add(model); + } + return result; + } + + Future> lookupDoctorAddress({ + required String doctorID, + CancelToken? cancelToken, + }) async { + final service = "${Constants.baseUrl}md/lookup_doctoraddress/$doctorID"; + final resp = await get(service: service, cancelToken: cancelToken); + final List result = + List.empty(growable: true); + for (final el in resp["data"]) { + final model = AcDoctorAddressResponseModel.fromJson(el); + result.add(model); + } + return result; + } + Future> lookupCompany({ required String query, CancelToken? cancelToken, @@ -49,6 +81,7 @@ class MitraRepository extends BaseRepository { final List result = List.empty(growable: true); for (final el in resp["data"]) { final model = AcMouResponseModel.fromJson(el); + model.isCheck = false; result.add(model); } return result; diff --git a/lib/screen/home/new_screen.dart b/lib/screen/home/new_screen.dart new file mode 100644 index 0000000..e69de29 diff --git a/lib/screen/md_lab_mitra/md_lab_mitra_screen.dart b/lib/screen/md_lab_mitra/md_lab_mitra_screen.dart index 9737863..81c8cd3 100644 --- a/lib/screen/md_lab_mitra/md_lab_mitra_screen.dart +++ b/lib/screen/md_lab_mitra/md_lab_mitra_screen.dart @@ -32,7 +32,7 @@ class MdLabMitraScreen extends HookConsumerWidget { color: Colors.white, child: const Padding( padding: EdgeInsets.all(20.0), - child: Expanded(child: FxDataMitra()), + child: FxDataMitra(), ), ), ); diff --git a/lib/screen/md_lab_mitra/mitra_lookup_mou_provider.dart b/lib/screen/md_lab_mitra/mitra_lookup_mou_provider.dart index b23ab41..b8d6b9e 100644 --- a/lib/screen/md_lab_mitra/mitra_lookup_mou_provider.dart +++ b/lib/screen/md_lab_mitra/mitra_lookup_mou_provider.dart @@ -18,6 +18,9 @@ class MitraLookupMouNotifier extends StateNotifier { MitraLookupMouNotifier({ required this.ref, }) : super(MitraLookupMouStateInit()); + void reset() { + state = MitraLookupMouStateInit(); + } void lookup({required String companyID}) async { if (cancelToken == null) { @@ -36,7 +39,7 @@ class MitraLookupMouNotifier extends StateNotifier { if (e is BaseRepositoryException) { state = MitraLookupMouStateError(message: e.message); } else { - state = MitraLookupMouStateError(message: e.toString()); + state = MitraLookupMouStateError(message: "Error lookupMou"); } } } diff --git a/lib/screen/md_lab_mitra/mitra_search_provider.dart b/lib/screen/md_lab_mitra/mitra_search_provider.dart index b45d256..549639c 100644 --- a/lib/screen/md_lab_mitra/mitra_search_provider.dart +++ b/lib/screen/md_lab_mitra/mitra_search_provider.dart @@ -36,7 +36,7 @@ class MitraSearchNotifier extends StateNotifier { if (e is BaseRepositoryException) { state = MitraSearchStateError(message: e.message); } else { - state = MitraSearchStateError(message: e.toString()); + state = MitraSearchStateError(message: "Error Mitra Search"); } } } diff --git a/lib/screen/md_lab_mitra/timer_provider.dart b/lib/screen/md_lab_mitra/timer_provider.dart new file mode 100644 index 0000000..a08f3f5 --- /dev/null +++ b/lib/screen/md_lab_mitra/timer_provider.dart @@ -0,0 +1,32 @@ +// ignore_for_file: must_be_immutable + +import 'dart:async'; + +import 'package:equatable/equatable.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +final timerProvider = + StateNotifierProvider.autoDispose( + (ref) => TimerNotifier()); + +class TimerNotifier extends StateNotifier { + TimerNotifier() : super(TimerStateInit()) { + Timer.periodic(const Duration(seconds: 5), (tmr) { + state = TimerStateTick(); + }); + } +} + +class TimerState extends Equatable { + late DateTime dateTime; + + TimerState() { + dateTime = DateTime.now(); + } + @override + List get props => [dateTime]; +} + +class TimerStateInit extends TimerState {} + +class TimerStateTick extends TimerState {} diff --git a/lib/widget/fx_company_lookup.dart b/lib/widget/fx_company_lookup.dart index 5883be7..a6f0368 100644 --- a/lib/widget/fx_company_lookup.dart +++ b/lib/widget/fx_company_lookup.dart @@ -6,8 +6,10 @@ import 'package:hooks_riverpod/hooks_riverpod.dart'; import '../model/ac_company_response_model.dart'; import '../provider/dio_provider.dart'; import '../repository/mitra_repository.dart'; -import '../screen/md_lab_mitra/selectedCompanyProvider.dart'; +import '../screen/md_lab_mitra/mitra_lookup_mou_provider.dart'; import 'fx_data_mitra.dart'; +import 'fx_text_field.dart'; +import 'provider/selectedCompanyProvider.dart'; // ignore: must_be_immutable class FxAcCompany extends HookConsumerWidget { @@ -25,14 +27,24 @@ class FxAcCompany extends HookConsumerWidget { if (selectedCompany != null) { ctrl.text = selectedCompany.mCompanyName; } + ref.listen(selectdAcCompanyProvider, ((prev, next) { + if (next != null) { + ref + .read(mitraLookupMouProvider.notifier) + .lookup(companyID: next.mCompanyID); + } + })); + return RawAutocomplete( textEditingController: ctrl, displayStringForOption: (model) => model.mCompanyName, focusNode: fc, fieldViewBuilder: (context, ctrl, fc, onChange) { - return TextField( - controller: ctrl, - focusNode: fc, + return FxTextField( + ctrl: ctrl, + fc: fc, + hint: "Company", + label: "Company", ); }, optionsBuilder: (tv) async { @@ -43,7 +55,7 @@ class FxAcCompany extends HookConsumerWidget { .lookupCompany(query: ctrl.text, cancelToken: cancelToken); return resp; } catch (e) { - errorMessage.value = e.toString(); + errorMessage.value = "Lookup Company Error"; } return []; }, diff --git a/lib/widget/fx_data_mitra.dart b/lib/widget/fx_data_mitra.dart index dde8b91..948c4fa 100644 --- a/lib/widget/fx_data_mitra.dart +++ b/lib/widget/fx_data_mitra.dart @@ -6,7 +6,6 @@ import 'package:hooks_riverpod/hooks_riverpod.dart'; import '../model/mitra_response_model.dart'; import '../screen/md_lab_mitra/mitra_search_provider.dart'; -import '../screen/md_lab_mitra/selectedCompanyProvider.dart'; import 'fx_error_text.dart'; import 'fx_mitra_add_dialog.dart'; diff --git a/lib/widget/fx_doctor_address.dart b/lib/widget/fx_doctor_address.dart new file mode 100644 index 0000000..76169bb --- /dev/null +++ b/lib/widget/fx_doctor_address.dart @@ -0,0 +1,90 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:onemd/model/ac_doctor_model.dart'; + +import 'fx_data_mitra.dart'; +import 'provider/doctor_address_lookup_provider.dart'; +import 'provider/doctor_lookup_provider.dart'; +import 'provider/selectedDoctorProvider.dart'; + +class FxDoctorAddress extends HookConsumerWidget { + final double? width; + const FxDoctorAddress({ + Key? key, + this.width, + }) : super(key: key); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final listAddress = + useState>(List.empty()); + + final doctorModel = ref.watch(selectedAcDoctorProvider); + String doctorName = doctorModel?.fullName ?? ""; + ref.listen(doctorAddressLookupProvider, (prev, next) { + if (next is DoctorAddressLookupStateDone) { + for (int idx = 0; idx < next.list.length; idx++) { + next.list[idx].isCheck = false; + } + listAddress.value = next.list; + } + }); + + return Container( + width: double.infinity, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(10), + border: Border.all(color: Colors.blue.shade700), + color: Colors.blue.shade100.withOpacity(0.3), + ), + child: ConstrainedBox( + constraints: BoxConstraints.loose(const Size(double.infinity, 150)), + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + FxNormalBlueText( + title: "Alamat dari $doctorName", + isBold: true, + ), + const SizedBox(height: 10), + if (listAddress.value.isNotEmpty) + ConstrainedBox( + constraints: + BoxConstraints.loose(const Size(double.infinity, 100)), + child: ListView.builder( + shrinkWrap: true, + itemCount: listAddress.value.length, + itemBuilder: (context, idx) { + final model = listAddress.value[idx]; + return Row( + children: [ + Checkbox( + value: model.isCheck, + onChanged: ((val) { + final List list = + List.empty(growable: true); + list.addAll(listAddress.value); + list[idx].isCheck = val ?? false; + listAddress.value = list; + }), + ), + const SizedBox(width: 10), + Expanded( + child: FxNormalBlueText( + title: model.mDoctorAddressDescription), + ), + ], + ); + }, + ), + ), + ], + ), + ), + )); + } +} diff --git a/lib/widget/fx_doctor_lookup.dart b/lib/widget/fx_doctor_lookup.dart new file mode 100644 index 0000000..c4bd9d8 --- /dev/null +++ b/lib/widget/fx_doctor_lookup.dart @@ -0,0 +1,102 @@ +import 'package:dio/dio.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:onemd/widget/provider/selectedDoctorProvider.dart'; + +import '../model/ac_doctor_model.dart'; +import '../provider/dio_provider.dart'; +import '../repository/mitra_repository.dart'; +import 'fx_data_mitra.dart'; +import 'fx_text_field.dart'; +import 'provider/doctor_address_lookup_provider.dart'; + +// ignore: must_be_immutable +class FxAcDoctor extends HookConsumerWidget { + FxAcDoctor({Key? key}) : super(key: key); + CancelToken? cancelToken; + + @override + Widget build(BuildContext context, WidgetRef ref) { + final errorMessage = useState(""); + final ctrl = useTextEditingController(text: ""); + + cancelToken = CancelToken(); + final fc = FocusNode(); + final selectedDoctor = ref.read(selectedAcDoctorProvider); + if (selectedDoctor != null) { + ctrl.text = selectedDoctor.fullName; + } + ref.listen(selectedAcDoctorProvider, ((prev, next) { + if (next != null) { + print("Calling for " + next.fullName); + ref + .read(doctorAddressLookupProvider.notifier) + .lookup(doctorID: next.mDoctorID); + } + })); + + return RawAutocomplete( + textEditingController: ctrl, + displayStringForOption: (model) => model.fullName, + focusNode: fc, + fieldViewBuilder: (context, ctrl, fc, onChange) { + return FxTextField( + label: "Doctor", + hint: "Doctor", + fc: fc, + ctrl: ctrl, + ); + }, + optionsBuilder: (tv) async { + try { + final dio = ref.read(dioProvider); + await Future.delayed(const Duration(milliseconds: 300)); + final resp = await MitraRepository(dio: dio) + .lookupDoctor(query: ctrl.text, cancelToken: cancelToken); + return resp; + } catch (e) { + errorMessage.value = "lookupDoctor Error"; + } + return []; + }, + optionsViewBuilder: (context, onSelect, listModel) { + return Align( + alignment: Alignment.topLeft, + child: SizedBox( + width: 400, + child: Material( + child: ListView.builder( + itemCount: listModel.length, + itemBuilder: (context, idx) { + final model = listModel.elementAt(idx); + return InkWell( + onTap: () { + ref.read(selectedAcDoctorProvider.notifier).state = + model; + onSelect(model); + }, + child: Container( + color: (idx % 2 == 1) + ? Colors.blue.shade100.withOpacity(0.2) + : null, + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + FxNormalBlueText( + title: model.fullName, + isBold: true, + ), + ], + ), + ), + )); + }), + ), + ), + ); + }); + } +} diff --git a/lib/widget/fx_mitra_add_dialog.dart b/lib/widget/fx_mitra_add_dialog.dart index b7980bd..d2a7f5b 100644 --- a/lib/widget/fx_mitra_add_dialog.dart +++ b/lib/widget/fx_mitra_add_dialog.dart @@ -1,14 +1,20 @@ import 'package:flutter/material.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:onemd/widget/fx_doctor_address.dart'; import 'fx_company_lookup.dart'; +import 'fx_doctor_lookup.dart'; import 'fx_mitra_mou.dart'; +import 'fx_text_field.dart'; class FxMitraAddDialog extends HookConsumerWidget { const FxMitraAddDialog({Key? key}) : super(key: key); @override Widget build(BuildContext context, WidgetRef ref) { + final ctrlLogin = useTextEditingController(text: ""); + final fcLogin = FocusNode(); + return Dialog( shape: RoundedRectangleBorder( side: const BorderSide(), @@ -17,21 +23,40 @@ class FxMitraAddDialog extends HookConsumerWidget { child: SizedBox( width: 800, height: 600, - child: Padding( - padding: const EdgeInsets.all(20.0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - FxAcCompany(), - const SizedBox(height: 10), - const FxMitraMou(), - const Text("Login"), - const SizedBox(height: 10), - const Text("ID -- auto generated"), - const SizedBox(height: 10), - ], + child: SingleChildScrollView( + child: Padding( + padding: const EdgeInsets.all(20.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + FxAcCompany(), + const SizedBox(height: 10), + const FxMitraMou(), + const SizedBox(height: 10), + FxAcDoctor(), + const SizedBox(height: 10), + FxDoctorAddress(), + const SizedBox(height: 10), + FxTextField( + ctrl: ctrlLogin, + fc: fcLogin, + hint: "Login", + label: "Login", + ), + const SizedBox(height: 10), + FxTextField( + hint: "ID", + label: "ID", + isReadOnly: true, + isEnabled: false, + suffixText: "Auto Generated"), + const SizedBox(height: 10), + ], + ), ), )), ); } } + +useTextEditingController({required String text}) {} diff --git a/lib/widget/fx_mitra_mou.dart b/lib/widget/fx_mitra_mou.dart index 70472e3..41779dc 100644 --- a/lib/widget/fx_mitra_mou.dart +++ b/lib/widget/fx_mitra_mou.dart @@ -2,10 +2,10 @@ import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; -import '../model/ac_company_response_model.dart'; import '../model/ac_mou_response_model.dart'; import '../screen/md_lab_mitra/mitra_lookup_mou_provider.dart'; -import '../screen/md_lab_mitra/selectedCompanyProvider.dart'; +import 'fx_data_mitra.dart'; +import 'provider/selectedCompanyProvider.dart'; class FxMitraMou extends HookConsumerWidget { final double? width; @@ -19,19 +19,16 @@ class FxMitraMou extends HookConsumerWidget { final listMou = useState>(List.empty()); final companyModel = ref.watch(selectdAcCompanyProvider); - String companyName = companyModel?.mCompanyName ?? " -- null -- "; - if (companyModel != null) { - WidgetsBinding.instance.addPostFrameCallback((_) { - ref - .read(mitraLookupMouProvider.notifier) - .lookup(companyID: companyModel.mCompanyID); - }); - } + String companyName = companyModel?.mCompanyName ?? ""; ref.listen(mitraLookupMouProvider, (prev, next) { if (next is MitraLookupMouStateDone) { + for (int idx = 0; idx < next.list.length; idx++) { + next.list[idx].isCheck = false; + } listMou.value = next.list; } }); + return Container( width: double.infinity, decoration: BoxDecoration( @@ -40,24 +37,45 @@ class FxMitraMou extends HookConsumerWidget { color: Colors.blue.shade100.withOpacity(0.3), ), child: ConstrainedBox( - constraints: BoxConstraints(minHeight: 50, maxHeight: 200), + constraints: BoxConstraints.loose(const Size(double.infinity, 150)), child: Padding( padding: const EdgeInsets.all(8.0), child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text( - "Agreement " + companyName, + FxNormalBlueText( + title: "Agreement $companyName", + isBold: true, ), - SizedBox(height: 10), - if (listMou.value.length > 0) - Expanded( + const SizedBox(height: 10), + if (listMou.value.isNotEmpty) + ConstrainedBox( + constraints: + BoxConstraints.loose(const Size(double.infinity, 100)), child: ListView.builder( + shrinkWrap: true, itemCount: listMou.value.length, itemBuilder: (context, idx) { final model = listMou.value[idx]; - return Text(model.mMouName); + return Row( + children: [ + Checkbox( + value: model.isCheck, + onChanged: ((val) { + final List list = + List.empty(growable: true); + list.addAll(listMou.value); + list[idx].isCheck = val ?? false; + listMou.value = list; + }), + ), + const SizedBox(width: 10), + Expanded( + child: FxNormalBlueText(title: model.mMouName), + ), + ], + ); }), ), ]), diff --git a/lib/widget/fx_text_field.dart b/lib/widget/fx_text_field.dart new file mode 100644 index 0000000..eaf9994 --- /dev/null +++ b/lib/widget/fx_text_field.dart @@ -0,0 +1,46 @@ +import 'package:flutter/material.dart'; + +class FxTextField extends StatelessWidget { + final TextEditingController? ctrl; + final FocusNode? fc; + final String label; + final String hint; + final String? errorMessage; + final bool? isReadOnly; + final bool? isEnabled; + final String? suffixText; + + const FxTextField({ + Key? key, + this.ctrl, + this.fc, + required this.label, + required this.hint, + this.errorMessage, + this.isReadOnly, + this.isEnabled, + this.suffixText, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + return TextField( + decoration: InputDecoration( + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(10), + ), + hintText: hint, + labelText: label, + errorText: errorMessage, + suffixIcon: Padding( + padding: const EdgeInsets.only(right: 10.0, top: 10.0), + child: Text(suffixText ?? ""), + ), + ), + controller: ctrl, + focusNode: fc, + readOnly: isReadOnly ?? false, + enabled: isEnabled ?? true, + ); + } +} diff --git a/lib/widget/provider/doctor_address_lookup_provider.dart b/lib/widget/provider/doctor_address_lookup_provider.dart new file mode 100644 index 0000000..956aca7 --- /dev/null +++ b/lib/widget/provider/doctor_address_lookup_provider.dart @@ -0,0 +1,74 @@ +import 'package:dio/dio.dart'; +import 'package:equatable/equatable.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +import '../../model/ac_doctor_model.dart'; +import '../../provider/dio_provider.dart'; +import '../../repository/base_repository.dart'; +import '../../repository/mitra_repository.dart'; + +final doctorAddressLookupProvider = StateNotifierProvider< + DoctorAddressLookupNotifier, DoctorAddressLookupState>( + (ref) => DoctorAddressLookupNotifier(ref: ref), +); + +class DoctorAddressLookupNotifier + extends StateNotifier { + final Ref ref; + CancelToken? cancelToken; + DoctorAddressLookupNotifier({ + required this.ref, + }) : super(DoctorAddressLookupStateInit()); + void reset() { + state = DoctorAddressLookupStateInit(); + } + + void lookup({required String doctorID}) async { + if (cancelToken == null) { + cancelToken = CancelToken(); + } else { + cancelToken!.cancel(); + cancelToken = CancelToken(); + } + try { + state = DoctorAddressLookupStateLoading(); + final dio = ref.read(dioProvider); + final resp = await MitraRepository(dio: dio) + .lookupDoctorAddress(doctorID: doctorID, cancelToken: cancelToken); + state = DoctorAddressLookupStateDone(list: resp); + } catch (e) { + if (e is BaseRepositoryException) { + state = DoctorAddressLookupStateError(message: e.message); + } else { + state = DoctorAddressLookupStateError(message: "Unknown Error"); + } + } + } +} + +abstract class DoctorAddressLookupState extends Equatable { + final DateTime date; + DoctorAddressLookupState() : date = DateTime.now(); + @override + List get props => throw [date]; +} + +class DoctorAddressLookupStateInit extends DoctorAddressLookupState {} + +class DoctorAddressLookupStateLoading extends DoctorAddressLookupState {} + +class DoctorAddressLookupStateError extends DoctorAddressLookupState { + final String message; + + DoctorAddressLookupStateError({ + required this.message, + }); +} + +class DoctorAddressLookupStateDone extends DoctorAddressLookupState { + final List list; + + DoctorAddressLookupStateDone({ + required this.list, + }); +} diff --git a/lib/widget/provider/doctor_lookup_provider.dart b/lib/widget/provider/doctor_lookup_provider.dart new file mode 100644 index 0000000..309adf8 --- /dev/null +++ b/lib/widget/provider/doctor_lookup_provider.dart @@ -0,0 +1,73 @@ +import 'package:dio/dio.dart'; +import 'package:equatable/equatable.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +import '../../model/ac_doctor_model.dart'; +import '../../provider/dio_provider.dart'; +import '../../repository/base_repository.dart'; +import '../../repository/mitra_repository.dart'; + +final doctorLookupProvider = + StateNotifierProvider( + (ref) => DoctorLookupNotifier(ref: ref), +); + +class DoctorLookupNotifier extends StateNotifier { + final Ref ref; + CancelToken? cancelToken; + DoctorLookupNotifier({ + required this.ref, + }) : super(DoctorLookupStateInit()); + void reset() { + state = DoctorLookupStateInit(); + } + + void lookup({required String query}) async { + if (cancelToken == null) { + cancelToken = CancelToken(); + } else { + cancelToken!.cancel(); + cancelToken = CancelToken(); + } + try { + state = DoctorLookupStateLoading(); + final dio = ref.read(dioProvider); + final resp = await MitraRepository(dio: dio) + .lookupDoctor(query: query, cancelToken: cancelToken); + state = DoctorLookupStateDone(list: resp); + } catch (e) { + if (e is BaseRepositoryException) { + state = DoctorLookupStateError(message: e.message); + } else { + state = DoctorLookupStateError(message: "Unknown Error "); + } + } + } +} + +abstract class DoctorLookupState extends Equatable { + final DateTime date; + DoctorLookupState() : date = DateTime.now(); + @override + List get props => throw [date]; +} + +class DoctorLookupStateInit extends DoctorLookupState {} + +class DoctorLookupStateLoading extends DoctorLookupState {} + +class DoctorLookupStateError extends DoctorLookupState { + final String message; + + DoctorLookupStateError({ + required this.message, + }); +} + +class DoctorLookupStateDone extends DoctorLookupState { + final List list; + + DoctorLookupStateDone({ + required this.list, + }); +} diff --git a/lib/screen/md_lab_mitra/selectedCompanyProvider.dart b/lib/widget/provider/selectedCompanyProvider.dart similarity index 100% rename from lib/screen/md_lab_mitra/selectedCompanyProvider.dart rename to lib/widget/provider/selectedCompanyProvider.dart diff --git a/lib/widget/provider/selectedDoctorProvider.dart b/lib/widget/provider/selectedDoctorProvider.dart new file mode 100644 index 0000000..5c1cfe1 --- /dev/null +++ b/lib/widget/provider/selectedDoctorProvider.dart @@ -0,0 +1,5 @@ +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:onemd/model/ac_doctor_model.dart'; + +final selectedAcDoctorProvider = + StateProvider((ref) => null); diff --git a/php-api/mitra/Md.php b/php-api/mitra/Md.php index 52234c4..0caf7ff 100644 --- a/php-api/mitra/Md.php +++ b/php-api/mitra/Md.php @@ -4,45 +4,45 @@ ini_set("display_startup_errors", 1); error_reporting(E_ALL); class Md extends MY_Controller { - function __construct() - { - parent::__construct(); - } - function index() - { - echo "Mitra:MD:API"; - } - function add() - { - $param = $this->sys_input; - print_r($param); - } + function __construct() + { + parent::__construct(); + } + function index() + { + echo "Mitra:MD:API"; + } + function add() + { + $param = $this->sys_input; + print_r($param); + } - function corss() - { - global $_SERVER; - if (isset($_SERVER["HTTP_ORIGIN"])) { - header("Access-Control-Allow-Origin:" . $_SERVER["HTTP_ORIGIN"]); - } else { - header("Access-Control-Allow-Origin: */*"); - } - header("Access-Control-Allow-Methods: GET, PUT, POST, DELETE, OPTIONS"); - header( - "Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept, Authorization" - ); - if ( - isset($_SERVER["REQUEST_METHOD"]) && - $_SERVER["REQUEST_METHOD"] == "OPTIONS" - ) { - http_response_code(200); - echo json_encode("OK"); - exit(); - } + function corss() + { + global $_SERVER; + if (isset($_SERVER["HTTP_ORIGIN"])) { + header("Access-Control-Allow-Origin:" . $_SERVER["HTTP_ORIGIN"]); + } else { + header("Access-Control-Allow-Origin: */*"); } - function search() - { - $this->corss(); - $sql = "select mitra.*, + header("Access-Control-Allow-Methods: GET, PUT, POST, DELETE, OPTIONS"); + header( + "Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept, Authorization" + ); + if ( + isset($_SERVER["REQUEST_METHOD"]) && + $_SERVER["REQUEST_METHOD"] == "OPTIONS" + ) { + http_response_code(200); + echo json_encode("OK"); + exit(); + } + } + function search() + { + $this->corss(); + $sql = "select mitra.*, M_CompanyName, M_CompanyAddress, group_concat(concat(M_MouName,' [', date_format(M_MouEndDate,'%d/%m/%Y'),'] ') separator '^') aggrement from mitra @@ -57,51 +57,88 @@ class Md extends MY_Controller and MitraMouIsActive ='Y' join m_mou on MitraMouM_MouID = M_MouID group by MitraID "; - $query = "%" . $this->sys_input["query"] . "%"; - $qry = $this->db->query($sql, [$query, $query]); - if (!$qry) { - echo json_encode([ - "status" => "ERR", - "message" => $this->db->error()["message"], - ]); - exit(); - } - echo json_encode(["status" => "OK", "data" => $qry->result_array()]); + $query = "%" . $this->sys_input["query"] . "%"; + $qry = $this->db->query($sql, [$query, $query]); + if (!$qry) { + echo json_encode([ + "status" => "ERR", + "message" => $this->db->error()["message"], + ]); + exit(); + } + echo json_encode(["status" => "OK", "data" => $qry->result_array()]); + } + function lookup_doctor() + { + $param = $this->sys_input; + $sql = "select M_DoctorID, fn_get_doctor_fullname(M_DoctorID) FullName + from m_doctor + where M_DoctorName like ? + and M_DoctorIsActive = 'Y' + limit 0,50"; + $qry = $this->db->query($sql, ["%" . $param["query"] . "%"]); + if (!$qry) { + echo json_encode([ + "status" => "ERR", + "message" => $this->db->error()["message"], + ]); + exit(); + } + echo json_encode(["status" => "OK", "data" => $qry->result_array()]); + } + + function lookup_doctoraddress($doctorID) + { + $param = $this->sys_input; + $sql = "select M_DoctorAddressID,M_DoctorAddressDescription + from m_doctoraddress + where M_DoctorAddressM_DoctorID = ? + and M_DoctorAddressIsActive = 'Y' + limit 0,50"; + $qry = $this->db->query($sql, [$doctorID]); + if (!$qry) { + echo json_encode([ + "status" => "ERR", + "message" => $this->db->error()["message"], + ]); + exit(); } - function lookup_company() - { - $param = $this->sys_input; - $sql = "select * from m_company + echo json_encode(["status" => "OK", "data" => $qry->result_array()]); + } + function lookup_company() + { + $param = $this->sys_input; + $sql = "select * from m_company where M_CompanyName like ? and M_CompanyIsActive = 'Y' limit 0,50"; - $qry = $this->db->query($sql, ["%" . $param["query"] . "%"]); - if (!$qry) { - echo json_encode([ - "status" => "ERR", - "message" => $this->db->error()["message"], - ]); - exit(); - } - echo json_encode(["status" => "OK", "data" => $qry->result_array()]); + $qry = $this->db->query($sql, ["%" . $param["query"] . "%"]); + if (!$qry) { + echo json_encode([ + "status" => "ERR", + "message" => $this->db->error()["message"], + ]); + exit(); } - function lookup_mou($companyID) - { - $sql = "select + echo json_encode(["status" => "OK", "data" => $qry->result_array()]); + } + function lookup_mou($companyID) + { + $sql = "select * from m_mou where M_MouM_CompanyID = ? and M_MouIsReleased = 'Y' and M_MouIsActive ='Y'"; - $qry = $this->db->query($sql, [$companyID]); - if (!$qry) { - echo json_encode([ - "status" => "ERR", - "message" => $this->db->error()["message"], - ]); - exit(); - } - echo json_encode(["status" => "OK", "data" => $qry->result_array()]); + $qry = $this->db->query($sql, [$companyID]); + if (!$qry) { + echo json_encode([ + "status" => "ERR", + "message" => $this->db->error()["message"], + ]); + exit(); } + echo json_encode(["status" => "OK", "data" => $qry->result_array()]); + } } /* drop table if exists mitra; diff --git a/web/index.html b/web/index.html index 5594ba1..85245c4 100644 --- a/web/index.html +++ b/web/index.html @@ -1,7 +1,8 @@ - - - + + + + + + + + + + + + + + - - - + onemd + - - - - - + + + + - - + + + - - - - - - - diff --git a/web/md_mitra_lab.html b/web/md_mitra_lab.html index d372308..e0c0a84 100644 --- a/web/md_mitra_lab.html +++ b/web/md_mitra_lab.html @@ -1,16 +1,22 @@ - - - - Mitra Lab MasterData - - - - - + + + + + Mitra Lab MasterData + + + + + + +