padmanto
2 years ago
20 changed files with 1133 additions and 76 deletions
@ -0,0 +1,48 @@ |
|||||||
|
class AcCompanyModel { |
||||||
|
late String mCompanyAddress; |
||||||
|
late String mCompanyAddressLocation; |
||||||
|
late String mCompanyEmail; |
||||||
|
late String mCompanyHp; |
||||||
|
late String mCompanyID; |
||||||
|
late String mCompanyName; |
||||||
|
late String mCompanyNumber; |
||||||
|
late String mCompanyPIC; |
||||||
|
late String mCompanyPhone; |
||||||
|
|
||||||
|
AcCompanyModel({ |
||||||
|
required this.mCompanyAddress, |
||||||
|
required this.mCompanyAddressLocation, |
||||||
|
required this.mCompanyEmail, |
||||||
|
required this.mCompanyHp, |
||||||
|
required this.mCompanyID, |
||||||
|
required this.mCompanyName, |
||||||
|
required this.mCompanyNumber, |
||||||
|
required this.mCompanyPhone, |
||||||
|
}); |
||||||
|
|
||||||
|
AcCompanyModel.fromJson(Map<String, dynamic> json) { |
||||||
|
mCompanyAddress = json['M_CompanyAddress'] ?? ""; |
||||||
|
mCompanyAddressLocation = json['M_CompanyAddressLocation'] ?? ""; |
||||||
|
mCompanyEmail = json['M_CompanyEmail'] ?? ""; |
||||||
|
mCompanyHp = json['M_CompanyHp'] ?? ""; |
||||||
|
mCompanyID = json['M_CompanyID'] ?? ""; |
||||||
|
mCompanyName = json['M_CompanyName'] ?? ""; |
||||||
|
mCompanyNumber = json['M_CompanyNumber'] ?? ""; |
||||||
|
mCompanyPIC = json['M_CompanyPIC'] ?? ""; |
||||||
|
mCompanyPhone = json['M_CompanyPhone'] ?? ""; |
||||||
|
} |
||||||
|
|
||||||
|
Map<String, dynamic> toJson() { |
||||||
|
final Map<String, dynamic> data = <String, dynamic>{}; |
||||||
|
data['M_CompanyAddress'] = mCompanyAddress; |
||||||
|
data['M_CompanyAddressLocation'] = mCompanyAddressLocation; |
||||||
|
data['M_CompanyEmail'] = mCompanyEmail; |
||||||
|
data['M_CompanyHp'] = mCompanyHp; |
||||||
|
data['M_CompanyID'] = mCompanyID; |
||||||
|
data['M_CompanyName'] = mCompanyName; |
||||||
|
data['M_CompanyNumber'] = mCompanyNumber; |
||||||
|
data['M_CompanyPIC'] = mCompanyPIC; |
||||||
|
data['M_CompanyPhone'] = mCompanyPhone; |
||||||
|
return data; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,45 @@ |
|||||||
|
class AcMouResponseModel { |
||||||
|
late String mMouEndDate; |
||||||
|
late String mMouID; |
||||||
|
late String mMouIsActive; |
||||||
|
late String mMouIsMcu; |
||||||
|
late String mMouName; |
||||||
|
late String mMouNote; |
||||||
|
late String mMouNumber; |
||||||
|
late String mMouStartDate; |
||||||
|
|
||||||
|
AcMouResponseModel({ |
||||||
|
required this.mMouEndDate, |
||||||
|
required this.mMouID, |
||||||
|
required this.mMouIsActive, |
||||||
|
required this.mMouIsMcu, |
||||||
|
required this.mMouName, |
||||||
|
required this.mMouNote, |
||||||
|
required this.mMouNumber, |
||||||
|
required this.mMouStartDate, |
||||||
|
}); |
||||||
|
|
||||||
|
AcMouResponseModel.fromJson(Map<String, dynamic> json) { |
||||||
|
mMouEndDate = json['M_MouEndDate'] ?? ""; |
||||||
|
mMouID = json['M_MouID'].toString(); |
||||||
|
mMouIsActive = json['M_MouIsActive'] ?? ""; |
||||||
|
mMouIsMcu = json['M_MouIsMcu'] ?? ""; |
||||||
|
mMouName = json['M_MouName'] ?? ""; |
||||||
|
mMouNote = json['M_MouNote'] ?? ""; |
||||||
|
mMouNumber = json['M_MouNumber'] ?? ""; |
||||||
|
mMouStartDate = json['M_MouStartDate'] ?? ""; |
||||||
|
} |
||||||
|
|
||||||
|
Map<String, dynamic> toJson() { |
||||||
|
final Map<String, dynamic> data = <String, dynamic>{}; |
||||||
|
data['M_MouEndDate'] = mMouEndDate; |
||||||
|
data['M_MouID'] = mMouID; |
||||||
|
data['M_MouIsActive'] = mMouIsActive; |
||||||
|
data['M_MouIsMcu'] = mMouIsMcu; |
||||||
|
data['M_MouName'] = mMouName; |
||||||
|
data['M_MouNote'] = mMouNote; |
||||||
|
data['M_MouNumber'] = mMouNumber; |
||||||
|
data['M_MouStartDate'] = mMouStartDate; |
||||||
|
return data; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,76 @@ |
|||||||
|
class MitraResponseModel { |
||||||
|
late String mCompanyAddress; |
||||||
|
late String mCompanyName; |
||||||
|
late String mitraCommitment; |
||||||
|
late String mitraCreated; |
||||||
|
late String mitraHoldDate; |
||||||
|
late String mitraHoldMUserID; |
||||||
|
late String mitraID; |
||||||
|
late String mitraIDNo; |
||||||
|
late String mitraIsActive; |
||||||
|
late String mitraIsHold; |
||||||
|
late String mitraLastUpdated; |
||||||
|
late String mitraMCompanyID; |
||||||
|
late String mitraMUserID; |
||||||
|
late String mitraPassword; |
||||||
|
late String mitraUsername; |
||||||
|
late String aggrement; |
||||||
|
|
||||||
|
MitraResponseModel({ |
||||||
|
required this.mCompanyAddress, |
||||||
|
required this.mCompanyName, |
||||||
|
required this.mitraCommitment, |
||||||
|
required this.mitraCreated, |
||||||
|
required this.mitraHoldDate, |
||||||
|
required this.mitraHoldMUserID, |
||||||
|
required this.mitraID, |
||||||
|
required this.mitraIDNo, |
||||||
|
required this.mitraIsActive, |
||||||
|
required this.mitraIsHold, |
||||||
|
required this.mitraLastUpdated, |
||||||
|
required this.mitraMCompanyID, |
||||||
|
required this.mitraMUserID, |
||||||
|
required this.mitraPassword, |
||||||
|
required this.mitraUsername, |
||||||
|
required this.aggrement, |
||||||
|
}); |
||||||
|
|
||||||
|
MitraResponseModel.fromJson(Map<String, dynamic> json) { |
||||||
|
mCompanyAddress = json['M_CompanyAddress']; |
||||||
|
mCompanyName = json['M_CompanyName']; |
||||||
|
mitraCommitment = json['MitraCommitment']; |
||||||
|
mitraCreated = json['MitraCreated']; |
||||||
|
mitraHoldDate = json['MitraHoldDate']; |
||||||
|
mitraHoldMUserID = json['MitraHoldM_UserID']?.toString() ?? ""; |
||||||
|
mitraID = json['MitraID'].toString(); |
||||||
|
mitraIDNo = json['MitraIDNo']; |
||||||
|
mitraIsActive = json['MitraIsActive']; |
||||||
|
mitraIsHold = json['MitraIsHold']; |
||||||
|
mitraLastUpdated = json['MitraLastUpdated']; |
||||||
|
mitraMCompanyID = json['MitraM_CompanyID'].toString(); |
||||||
|
mitraMUserID = json['MitraM_UserID']?.toString() ?? ""; |
||||||
|
mitraPassword = json['MitraPassword']; |
||||||
|
mitraUsername = json['MitraUsername']; |
||||||
|
aggrement = json['aggrement']; |
||||||
|
} |
||||||
|
|
||||||
|
Map<String, dynamic> toJson() { |
||||||
|
final Map<String, dynamic> data = new Map<String, dynamic>(); |
||||||
|
data['M_CompanyAddress'] = this.mCompanyAddress; |
||||||
|
data['M_CompanyName'] = this.mCompanyName; |
||||||
|
data['MitraCommitment'] = this.mitraCommitment; |
||||||
|
data['MitraCreated'] = this.mitraCreated; |
||||||
|
data['MitraHoldDate'] = this.mitraHoldDate; |
||||||
|
data['MitraHoldM_UserID'] = this.mitraHoldMUserID; |
||||||
|
data['MitraID'] = this.mitraID; |
||||||
|
data['MitraIDNo'] = this.mitraIDNo; |
||||||
|
data['MitraIsActive'] = this.mitraIsActive; |
||||||
|
data['MitraIsHold'] = this.mitraIsHold; |
||||||
|
data['MitraLastUpdated'] = this.mitraLastUpdated; |
||||||
|
data['MitraM_CompanyID'] = this.mitraMCompanyID; |
||||||
|
data['MitraM_UserID'] = this.mitraMUserID; |
||||||
|
data['MitraPassword'] = this.mitraPassword; |
||||||
|
data['MitraUsername'] = this.mitraUsername; |
||||||
|
return data; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,56 @@ |
|||||||
|
import 'package:dio/dio.dart'; |
||||||
|
|
||||||
|
import '../app/constants.dart'; |
||||||
|
import '../model/ac_company_response_model.dart'; |
||||||
|
import '../model/ac_mou_response_model.dart'; |
||||||
|
import '../model/mitra_response_model.dart'; |
||||||
|
import 'base_repository.dart'; |
||||||
|
|
||||||
|
class MitraRepository extends BaseRepository { |
||||||
|
MitraRepository({required super.dio}); |
||||||
|
Future<List<MitraResponseModel>> search({ |
||||||
|
required String query, |
||||||
|
CancelToken? cancelToken, |
||||||
|
}) async { |
||||||
|
final param = {"query": query}; |
||||||
|
final service = "${Constants.baseUrl}md/search"; |
||||||
|
final resp = await post( |
||||||
|
service: service, jsonParam: param, cancelToken: cancelToken); |
||||||
|
final List<MitraResponseModel> result = List.empty(growable: true); |
||||||
|
for (final el in resp["data"]) { |
||||||
|
final model = MitraResponseModel.fromJson(el); |
||||||
|
result.add(model); |
||||||
|
} |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
Future<List<AcCompanyModel>> lookupCompany({ |
||||||
|
required String query, |
||||||
|
CancelToken? cancelToken, |
||||||
|
}) async { |
||||||
|
final param = {"query": query}; |
||||||
|
final service = "${Constants.baseUrl}md/lookup_company"; |
||||||
|
final resp = await post( |
||||||
|
service: service, jsonParam: param, cancelToken: cancelToken); |
||||||
|
final List<AcCompanyModel> result = List.empty(growable: true); |
||||||
|
for (final el in resp["data"]) { |
||||||
|
final model = AcCompanyModel.fromJson(el); |
||||||
|
result.add(model); |
||||||
|
} |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
Future<List<AcMouResponseModel>> lookupMou({ |
||||||
|
required String companyID, |
||||||
|
CancelToken? cancelToken, |
||||||
|
}) async { |
||||||
|
final service = "${Constants.baseUrl}md/lookup_mou/$companyID"; |
||||||
|
final resp = await get(service: service, cancelToken: cancelToken); |
||||||
|
final List<AcMouResponseModel> result = List.empty(growable: true); |
||||||
|
for (final el in resp["data"]) { |
||||||
|
final model = AcMouResponseModel.fromJson(el); |
||||||
|
result.add(model); |
||||||
|
} |
||||||
|
return result; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,70 @@ |
|||||||
|
import 'package:dio/dio.dart'; |
||||||
|
import 'package:equatable/equatable.dart'; |
||||||
|
import 'package:flutter_riverpod/flutter_riverpod.dart'; |
||||||
|
|
||||||
|
import '../../model/ac_mou_response_model.dart'; |
||||||
|
import '../../provider/dio_provider.dart'; |
||||||
|
import '../../repository/base_repository.dart'; |
||||||
|
import '../../repository/mitra_repository.dart'; |
||||||
|
|
||||||
|
final mitraLookupMouProvider = |
||||||
|
StateNotifierProvider<MitraLookupMouNotifier, MitraLookupMouState>( |
||||||
|
(ref) => MitraLookupMouNotifier(ref: ref), |
||||||
|
); |
||||||
|
|
||||||
|
class MitraLookupMouNotifier extends StateNotifier<MitraLookupMouState> { |
||||||
|
final Ref ref; |
||||||
|
CancelToken? cancelToken; |
||||||
|
MitraLookupMouNotifier({ |
||||||
|
required this.ref, |
||||||
|
}) : super(MitraLookupMouStateInit()); |
||||||
|
|
||||||
|
void lookup({required String companyID}) async { |
||||||
|
if (cancelToken == null) { |
||||||
|
cancelToken = CancelToken(); |
||||||
|
} else { |
||||||
|
cancelToken!.cancel(); |
||||||
|
cancelToken = CancelToken(); |
||||||
|
} |
||||||
|
try { |
||||||
|
state = MitraLookupMouStateLoading(); |
||||||
|
final dio = ref.read(dioProvider); |
||||||
|
final resp = await MitraRepository(dio: dio) |
||||||
|
.lookupMou(companyID: companyID, cancelToken: cancelToken); |
||||||
|
state = MitraLookupMouStateDone(list: resp); |
||||||
|
} catch (e) { |
||||||
|
if (e is BaseRepositoryException) { |
||||||
|
state = MitraLookupMouStateError(message: e.message); |
||||||
|
} else { |
||||||
|
state = MitraLookupMouStateError(message: e.toString()); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
abstract class MitraLookupMouState extends Equatable { |
||||||
|
final DateTime date; |
||||||
|
MitraLookupMouState() : date = DateTime.now(); |
||||||
|
@override |
||||||
|
List<Object?> get props => throw [date]; |
||||||
|
} |
||||||
|
|
||||||
|
class MitraLookupMouStateInit extends MitraLookupMouState {} |
||||||
|
|
||||||
|
class MitraLookupMouStateLoading extends MitraLookupMouState {} |
||||||
|
|
||||||
|
class MitraLookupMouStateError extends MitraLookupMouState { |
||||||
|
final String message; |
||||||
|
|
||||||
|
MitraLookupMouStateError({ |
||||||
|
required this.message, |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
class MitraLookupMouStateDone extends MitraLookupMouState { |
||||||
|
final List<AcMouResponseModel> list; |
||||||
|
|
||||||
|
MitraLookupMouStateDone({ |
||||||
|
required this.list, |
||||||
|
}); |
||||||
|
} |
@ -0,0 +1,70 @@ |
|||||||
|
import 'package:dio/dio.dart'; |
||||||
|
import 'package:equatable/equatable.dart'; |
||||||
|
import 'package:flutter_riverpod/flutter_riverpod.dart'; |
||||||
|
|
||||||
|
import '../../model/mitra_response_model.dart'; |
||||||
|
import '../../provider/dio_provider.dart'; |
||||||
|
import '../../repository/base_repository.dart'; |
||||||
|
import '../../repository/mitra_repository.dart'; |
||||||
|
|
||||||
|
final mitraSearchProvider = |
||||||
|
StateNotifierProvider<MitraSearchNotifier, MitraSearchState>( |
||||||
|
(ref) => MitraSearchNotifier(ref: ref), |
||||||
|
); |
||||||
|
|
||||||
|
class MitraSearchNotifier extends StateNotifier<MitraSearchState> { |
||||||
|
final Ref ref; |
||||||
|
CancelToken? cancelToken; |
||||||
|
MitraSearchNotifier({ |
||||||
|
required this.ref, |
||||||
|
}) : super(MitraSearchStateInit()); |
||||||
|
|
||||||
|
void search({required String query}) async { |
||||||
|
if (cancelToken == null) { |
||||||
|
cancelToken = CancelToken(); |
||||||
|
} else { |
||||||
|
cancelToken!.cancel(); |
||||||
|
cancelToken = CancelToken(); |
||||||
|
} |
||||||
|
try { |
||||||
|
state = MitraSearchStateLoading(); |
||||||
|
final dio = ref.read(dioProvider); |
||||||
|
final resp = await MitraRepository(dio: dio) |
||||||
|
.search(query: query, cancelToken: cancelToken); |
||||||
|
state = MitraSearchStateDone(list: resp); |
||||||
|
} catch (e) { |
||||||
|
if (e is BaseRepositoryException) { |
||||||
|
state = MitraSearchStateError(message: e.message); |
||||||
|
} else { |
||||||
|
state = MitraSearchStateError(message: e.toString()); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
abstract class MitraSearchState extends Equatable { |
||||||
|
final DateTime date; |
||||||
|
MitraSearchState() : date = DateTime.now(); |
||||||
|
@override |
||||||
|
List<Object?> get props => throw [date]; |
||||||
|
} |
||||||
|
|
||||||
|
class MitraSearchStateInit extends MitraSearchState {} |
||||||
|
|
||||||
|
class MitraSearchStateLoading extends MitraSearchState {} |
||||||
|
|
||||||
|
class MitraSearchStateError extends MitraSearchState { |
||||||
|
final String message; |
||||||
|
|
||||||
|
MitraSearchStateError({ |
||||||
|
required this.message, |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
class MitraSearchStateDone extends MitraSearchState { |
||||||
|
final List<MitraResponseModel> list; |
||||||
|
|
||||||
|
MitraSearchStateDone({ |
||||||
|
required this.list, |
||||||
|
}); |
||||||
|
} |
@ -0,0 +1,5 @@ |
|||||||
|
import 'package:flutter_riverpod/flutter_riverpod.dart'; |
||||||
|
|
||||||
|
import '../../model/ac_company_response_model.dart'; |
||||||
|
|
||||||
|
final selectdAcCompanyProvider = StateProvider<AcCompanyModel?>((ref) => null); |
@ -0,0 +1,92 @@ |
|||||||
|
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 '../model/ac_company_response_model.dart'; |
||||||
|
import '../provider/dio_provider.dart'; |
||||||
|
import '../repository/mitra_repository.dart'; |
||||||
|
import '../screen/md_lab_mitra/selectedCompanyProvider.dart'; |
||||||
|
import 'fx_data_mitra.dart'; |
||||||
|
|
||||||
|
// ignore: must_be_immutable |
||||||
|
class FxAcCompany extends HookConsumerWidget { |
||||||
|
FxAcCompany({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 selectedCompany = ref.read(selectdAcCompanyProvider); |
||||||
|
if (selectedCompany != null) { |
||||||
|
ctrl.text = selectedCompany.mCompanyName; |
||||||
|
} |
||||||
|
return RawAutocomplete<AcCompanyModel>( |
||||||
|
textEditingController: ctrl, |
||||||
|
displayStringForOption: (model) => model.mCompanyName, |
||||||
|
focusNode: fc, |
||||||
|
fieldViewBuilder: (context, ctrl, fc, onChange) { |
||||||
|
return TextField( |
||||||
|
controller: ctrl, |
||||||
|
focusNode: fc, |
||||||
|
); |
||||||
|
}, |
||||||
|
optionsBuilder: (tv) async { |
||||||
|
try { |
||||||
|
final dio = ref.read(dioProvider); |
||||||
|
await Future.delayed(const Duration(milliseconds: 300)); |
||||||
|
final resp = await MitraRepository(dio: dio) |
||||||
|
.lookupCompany(query: ctrl.text, cancelToken: cancelToken); |
||||||
|
return resp; |
||||||
|
} catch (e) { |
||||||
|
errorMessage.value = e.toString(); |
||||||
|
} |
||||||
|
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(selectdAcCompanyProvider.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.mCompanyName, |
||||||
|
isBold: true, |
||||||
|
), |
||||||
|
const SizedBox(height: 5), |
||||||
|
FxNormalBlueText( |
||||||
|
title: model.mCompanyAddress), |
||||||
|
], |
||||||
|
), |
||||||
|
), |
||||||
|
)); |
||||||
|
}), |
||||||
|
), |
||||||
|
), |
||||||
|
); |
||||||
|
}); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,207 @@ |
|||||||
|
import 'dart:async'; |
||||||
|
|
||||||
|
import 'package:flutter/material.dart'; |
||||||
|
import 'package:flutter_hooks/flutter_hooks.dart'; |
||||||
|
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'; |
||||||
|
|
||||||
|
class FxDataMitra extends HookConsumerWidget { |
||||||
|
final int rowsPerPage; |
||||||
|
const FxDataMitra({ |
||||||
|
Key? key, |
||||||
|
this.rowsPerPage = 10, |
||||||
|
}) : super(key: key); |
||||||
|
|
||||||
|
@override |
||||||
|
Widget build(BuildContext context, WidgetRef ref) { |
||||||
|
final list = useState<List<MitraResponseModel>>(List.empty()); |
||||||
|
final isLoading = useState(false); |
||||||
|
final errorMessage = useState(""); |
||||||
|
|
||||||
|
ref.listen(mitraSearchProvider, (prev, next) { |
||||||
|
if (next is MitraSearchStateLoading) { |
||||||
|
isLoading.value = true; |
||||||
|
} else if (next is MitraSearchStateError) { |
||||||
|
isLoading.value = false; |
||||||
|
errorMessage.value = next.message; |
||||||
|
Timer(const Duration(seconds: 3), () { |
||||||
|
errorMessage.value = ""; |
||||||
|
}); |
||||||
|
} else if (next is MitraSearchStateDone) { |
||||||
|
isLoading.value = false; |
||||||
|
list.value = next.list; |
||||||
|
} |
||||||
|
}); |
||||||
|
final pageWidth = MediaQuery.of(context).size.width - 200; |
||||||
|
return PaginatedDataTable( |
||||||
|
arrowHeadColor: Colors.red, |
||||||
|
columnSpacing: 10, |
||||||
|
header: Column( |
||||||
|
children: [ |
||||||
|
const FxNormalBlueText(title: "Daftar Lab Mitra"), |
||||||
|
if (isLoading.value) const LinearProgressIndicator(), |
||||||
|
if (errorMessage.value != "") FxErrorText(title: errorMessage.value) |
||||||
|
], |
||||||
|
), |
||||||
|
rowsPerPage: rowsPerPage, |
||||||
|
actions: [ |
||||||
|
SizedBox( |
||||||
|
width: 150, |
||||||
|
child: TextButton( |
||||||
|
child: Row( |
||||||
|
mainAxisSize: MainAxisSize.max, |
||||||
|
children: const [ |
||||||
|
Text("New Lab Mitra"), |
||||||
|
Icon(Icons.add_rounded, size: 24), |
||||||
|
], |
||||||
|
), |
||||||
|
onPressed: () async { |
||||||
|
await showDialog( |
||||||
|
context: context, |
||||||
|
builder: (context) { |
||||||
|
return const FxMitraAddDialog(); |
||||||
|
}); |
||||||
|
}), |
||||||
|
), |
||||||
|
], |
||||||
|
columns: [ |
||||||
|
titleColumn("Company"), |
||||||
|
titleColumn("Login"), |
||||||
|
titleColumn("ID"), |
||||||
|
titleColumn("Aggreement"), |
||||||
|
titleColumn(""), |
||||||
|
], |
||||||
|
source: _MitraDataSource( |
||||||
|
totalRow: list.value.length, |
||||||
|
list: list.value, |
||||||
|
pageWidth: pageWidth, |
||||||
|
), |
||||||
|
); |
||||||
|
} |
||||||
|
|
||||||
|
DataColumn titleColumn(String title) { |
||||||
|
return DataColumn( |
||||||
|
label: FxNormalBlueText(title: title), |
||||||
|
); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
class FxNormalBlueText extends StatelessWidget { |
||||||
|
final String title; |
||||||
|
final bool isBold; |
||||||
|
const FxNormalBlueText({ |
||||||
|
Key? key, |
||||||
|
required this.title, |
||||||
|
this.isBold = false, |
||||||
|
}) : super(key: key); |
||||||
|
|
||||||
|
@override |
||||||
|
Widget build(BuildContext context) { |
||||||
|
return Text( |
||||||
|
title, |
||||||
|
overflow: TextOverflow.ellipsis, |
||||||
|
style: TextStyle( |
||||||
|
fontSize: 16, |
||||||
|
fontWeight: isBold ? FontWeight.w700 : FontWeight.normal, |
||||||
|
color: Colors.blue.shade500, |
||||||
|
), |
||||||
|
); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
class _MitraDataSource extends DataTableSource { |
||||||
|
final List<MitraResponseModel> list; |
||||||
|
final int totalRow; |
||||||
|
final double pageWidth; |
||||||
|
|
||||||
|
_MitraDataSource({ |
||||||
|
required this.list, |
||||||
|
required this.totalRow, |
||||||
|
required this.pageWidth, |
||||||
|
}); |
||||||
|
@override |
||||||
|
DataRow? getRow(int index) { |
||||||
|
final model = list[index]; |
||||||
|
final List<double> width = [ |
||||||
|
pageWidth * 1.5 / 7, |
||||||
|
pageWidth * 0.8 / 7, |
||||||
|
pageWidth * 0.8 / 7, |
||||||
|
pageWidth * 3.9 / 7 |
||||||
|
]; |
||||||
|
final agreement = model.aggrement.replaceAll('^', ', '); |
||||||
|
return DataRow( |
||||||
|
color: (index % 2 == 0) |
||||||
|
? MaterialStateColor.resolveWith( |
||||||
|
(state) => Colors.blue.shade50.withOpacity(0.2)) |
||||||
|
: null, |
||||||
|
cells: [ |
||||||
|
dataCell(model.mCompanyName, width[0]), |
||||||
|
dataCell(model.mitraUsername, width[1]), |
||||||
|
dataCell(model.mitraIDNo, width[2]), |
||||||
|
dataCell(agreement, width[3]), |
||||||
|
DataCell( |
||||||
|
SizedBox( |
||||||
|
width: 60, |
||||||
|
child: Row( |
||||||
|
mainAxisSize: MainAxisSize.max, |
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceAround, |
||||||
|
children: [ |
||||||
|
InkWell( |
||||||
|
onTap: () {}, |
||||||
|
child: Icon( |
||||||
|
Icons.edit_rounded, |
||||||
|
size: 24, |
||||||
|
color: Colors.green.shade700, |
||||||
|
), |
||||||
|
), |
||||||
|
InkWell( |
||||||
|
onTap: () {}, |
||||||
|
child: Icon( |
||||||
|
Icons.delete_rounded, |
||||||
|
size: 24, |
||||||
|
color: Colors.red.shade700, |
||||||
|
), |
||||||
|
), |
||||||
|
], |
||||||
|
), |
||||||
|
), |
||||||
|
), |
||||||
|
], |
||||||
|
); |
||||||
|
} |
||||||
|
|
||||||
|
DataCell dataCell( |
||||||
|
String value, |
||||||
|
double width, |
||||||
|
) { |
||||||
|
return DataCell( |
||||||
|
SizedBox( |
||||||
|
width: width, |
||||||
|
child: Padding( |
||||||
|
padding: const EdgeInsets.all(5.0), |
||||||
|
child: Text( |
||||||
|
value, |
||||||
|
style: TextStyle( |
||||||
|
fontSize: 16, |
||||||
|
color: Colors.blue.shade500, |
||||||
|
), |
||||||
|
), |
||||||
|
), |
||||||
|
), |
||||||
|
); |
||||||
|
} |
||||||
|
|
||||||
|
@override |
||||||
|
bool get isRowCountApproximate => false; |
||||||
|
|
||||||
|
@override |
||||||
|
int get rowCount => list.length; |
||||||
|
|
||||||
|
@override |
||||||
|
int get selectedRowCount => 0; |
||||||
|
} |
@ -0,0 +1,20 @@ |
|||||||
|
import 'dart:async'; |
||||||
|
|
||||||
|
import 'package:flutter/material.dart'; |
||||||
|
|
||||||
|
class FxDebouncer { |
||||||
|
final int milliseconds; |
||||||
|
VoidCallback? action; |
||||||
|
Timer? _timer; |
||||||
|
|
||||||
|
FxDebouncer({ |
||||||
|
required this.milliseconds, |
||||||
|
this.action, |
||||||
|
}); |
||||||
|
run(VoidCallback action) { |
||||||
|
if (_timer != null) { |
||||||
|
_timer!.cancel(); |
||||||
|
} |
||||||
|
_timer = Timer(Duration(milliseconds: milliseconds), action); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,20 @@ |
|||||||
|
import 'package:flutter/material.dart'; |
||||||
|
|
||||||
|
class FxErrorText extends StatelessWidget { |
||||||
|
final String title; |
||||||
|
const FxErrorText({ |
||||||
|
required this.title, |
||||||
|
Key? key, |
||||||
|
}) : super(key: key); |
||||||
|
|
||||||
|
@override |
||||||
|
Widget build(BuildContext context) { |
||||||
|
return Text( |
||||||
|
"Error $title", |
||||||
|
style: const TextStyle( |
||||||
|
fontSize: 16, |
||||||
|
color: Colors.red, |
||||||
|
), |
||||||
|
); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,37 @@ |
|||||||
|
import 'package:flutter/material.dart'; |
||||||
|
import 'package:hooks_riverpod/hooks_riverpod.dart'; |
||||||
|
|
||||||
|
import 'fx_company_lookup.dart'; |
||||||
|
import 'fx_mitra_mou.dart'; |
||||||
|
|
||||||
|
class FxMitraAddDialog extends HookConsumerWidget { |
||||||
|
const FxMitraAddDialog({Key? key}) : super(key: key); |
||||||
|
|
||||||
|
@override |
||||||
|
Widget build(BuildContext context, WidgetRef ref) { |
||||||
|
return Dialog( |
||||||
|
shape: RoundedRectangleBorder( |
||||||
|
side: const BorderSide(), |
||||||
|
borderRadius: BorderRadius.circular(10), |
||||||
|
), |
||||||
|
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), |
||||||
|
], |
||||||
|
), |
||||||
|
)), |
||||||
|
); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,68 @@ |
|||||||
|
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'; |
||||||
|
|
||||||
|
class FxMitraMou extends HookConsumerWidget { |
||||||
|
final double? width; |
||||||
|
const FxMitraMou({ |
||||||
|
Key? key, |
||||||
|
this.width, |
||||||
|
}) : super(key: key); |
||||||
|
|
||||||
|
@override |
||||||
|
Widget build(BuildContext context, WidgetRef ref) { |
||||||
|
final listMou = useState<List<AcMouResponseModel>>(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); |
||||||
|
}); |
||||||
|
} |
||||||
|
ref.listen(mitraLookupMouProvider, (prev, next) { |
||||||
|
if (next is MitraLookupMouStateDone) { |
||||||
|
listMou.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(minHeight: 50, maxHeight: 200), |
||||||
|
child: Padding( |
||||||
|
padding: const EdgeInsets.all(8.0), |
||||||
|
child: Column( |
||||||
|
mainAxisSize: MainAxisSize.min, |
||||||
|
crossAxisAlignment: CrossAxisAlignment.start, |
||||||
|
children: [ |
||||||
|
Text( |
||||||
|
"Agreement " + companyName, |
||||||
|
), |
||||||
|
SizedBox(height: 10), |
||||||
|
if (listMou.value.length > 0) |
||||||
|
Expanded( |
||||||
|
child: ListView.builder( |
||||||
|
itemCount: listMou.value.length, |
||||||
|
itemBuilder: (context, idx) { |
||||||
|
final model = listMou.value[idx]; |
||||||
|
return Text(model.mMouName); |
||||||
|
}), |
||||||
|
), |
||||||
|
]), |
||||||
|
), |
||||||
|
), |
||||||
|
); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,86 @@ |
|||||||
|
import 'package:flutter/material.dart'; |
||||||
|
|
||||||
|
class LoadingPageWidget extends StatelessWidget { |
||||||
|
final String title; |
||||||
|
final Color color; |
||||||
|
final Size size; |
||||||
|
final double fontSize; |
||||||
|
final double circleSize; |
||||||
|
const LoadingPageWidget({ |
||||||
|
Key? key, |
||||||
|
required this.size, |
||||||
|
required this.title, |
||||||
|
this.color = Colors.blue, |
||||||
|
required this.circleSize, |
||||||
|
required this.fontSize, |
||||||
|
}) : super(key: key); |
||||||
|
|
||||||
|
@override |
||||||
|
Widget build(BuildContext context) { |
||||||
|
return Material( |
||||||
|
child: Container( |
||||||
|
height: size.height, |
||||||
|
width: size.width, |
||||||
|
color: Colors.white, |
||||||
|
child: Align( |
||||||
|
alignment: Alignment.center, |
||||||
|
child: Column(children: [ |
||||||
|
SizedBox( |
||||||
|
width: 32, |
||||||
|
height: 32, |
||||||
|
child: CircularProgressIndicator(color: color), |
||||||
|
), |
||||||
|
const SizedBox(height: 10), |
||||||
|
Text( |
||||||
|
title, |
||||||
|
style: TextStyle(fontSize: fontSize, color: color), |
||||||
|
), |
||||||
|
]), |
||||||
|
), |
||||||
|
), |
||||||
|
); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
class FxLoadingWidget extends StatelessWidget { |
||||||
|
final String title; |
||||||
|
final Color color; |
||||||
|
final double size; |
||||||
|
final double fontSize; |
||||||
|
const FxLoadingWidget({ |
||||||
|
Key? key, |
||||||
|
required this.title, |
||||||
|
this.color = Colors.blue, |
||||||
|
this.fontSize = 16.0, |
||||||
|
this.size = 48.0, |
||||||
|
}) : super(key: key); |
||||||
|
|
||||||
|
@override |
||||||
|
Widget build(BuildContext context) { |
||||||
|
return Material( |
||||||
|
child: Column( |
||||||
|
mainAxisAlignment: MainAxisAlignment.center, |
||||||
|
mainAxisSize: MainAxisSize.max, |
||||||
|
children: [ |
||||||
|
SizedBox( |
||||||
|
width: size, |
||||||
|
height: size, |
||||||
|
child: CircularProgressIndicator( |
||||||
|
color: color, |
||||||
|
), |
||||||
|
), |
||||||
|
const SizedBox( |
||||||
|
height: 10, |
||||||
|
), |
||||||
|
Text( |
||||||
|
title, |
||||||
|
style: TextStyle( |
||||||
|
fontSize: fontSize, |
||||||
|
color: color, |
||||||
|
), |
||||||
|
), |
||||||
|
], |
||||||
|
), |
||||||
|
); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,12 @@ |
|||||||
|
-- Add mitra |
||||||
|
|
||||||
|
```bash |
||||||
|
curl http://devone.aplikasi.web.id/one-api/mitra/md/add \ |
||||||
|
-d '{"mitraUsername":"lababc","mitraPassword":"d41d8cd98f00b204e9800998ecf8427e",\ |
||||||
|
"mitraM_CompanyID":4640,"mitraCommitment":"-- commitment --",\ |
||||||
|
"mou": [M_MouID:654,M_MouName:""]}' |
||||||
|
|
||||||
|
``` |
||||||
|
|
||||||
|
-- edit mitra |
||||||
|
-- disable mitra |
@ -0,0 +1,172 @@ |
|||||||
|
<?php |
||||||
|
ini_set("display_errors", 1); |
||||||
|
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 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 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 |
||||||
|
join m_company |
||||||
|
on MitraM_CompanyID = M_CompanyID |
||||||
|
and MitraIsActive = 'Y' |
||||||
|
and ( |
||||||
|
MitraUsername like ? |
||||||
|
or M_CompanyName like ?) |
||||||
|
join mitra_mou |
||||||
|
on MitraID = MitraMouMitraID |
||||||
|
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()]); |
||||||
|
} |
||||||
|
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()]); |
||||||
|
} |
||||||
|
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()]); |
||||||
|
} |
||||||
|
} |
||||||
|
/* |
||||||
|
drop table if exists mitra; |
||||||
|
create table mitra( |
||||||
|
MitraID int not null auto_increment primary key, |
||||||
|
MitraIDNo varchar(6), |
||||||
|
MitraUsername varchar(20), |
||||||
|
MitraPassword varchar(32), |
||||||
|
MitraM_CompanyID int, |
||||||
|
MitraIsActive varchar(1) default 'Y', |
||||||
|
MitraCommitment text, |
||||||
|
MitraCreated datetime default current_timestamp(), |
||||||
|
MitraLastUpdated datetime default current_timestamp() on update current_timestamp(), |
||||||
|
MitraM_UserID int, |
||||||
|
MitraIsHold varchar(1) default 'N', |
||||||
|
MitraHoldDate datetime default current_timestamp(), |
||||||
|
MitraHoldM_UserID int, |
||||||
|
unique(MitraIDNo,MitraUsername), |
||||||
|
key(MitraIsActive), |
||||||
|
key(MitraIsHold), |
||||||
|
key(MitraM_CompanyID) |
||||||
|
); |
||||||
|
create table mitra_mou( |
||||||
|
MitraMouID int not null auto_increment primary key, |
||||||
|
MitraMouMitraID int, |
||||||
|
MitraMouM_MouID int, |
||||||
|
MitraMouIsActive varchar(1) default 'Y', |
||||||
|
MitraMouCreated datetime default current_timestamp(), |
||||||
|
MitraMouLastUpdated datetime default current_timestamp() on update current_timestamp(), |
||||||
|
MitraMouM_UserID int, |
||||||
|
key (MitraMouM_MouID), |
||||||
|
key (MitraMouIsActive) |
||||||
|
); |
||||||
|
delimiter ;; |
||||||
|
drop function if exists fn_generate_mitra_id;; |
||||||
|
create function fn_generate_mitra_id ( |
||||||
|
) returns varchar(6) |
||||||
|
reads sql data |
||||||
|
begin |
||||||
|
set @branchCode = null; |
||||||
|
select M_BranchCode into @branchCode |
||||||
|
from m_branch |
||||||
|
where M_BranchIsDefault = 'Y' and M_BranchIsActive = 'Y'; |
||||||
|
if @branchCode is null then |
||||||
|
return "ERR.BR"; |
||||||
|
end if; |
||||||
|
set @counter =0; |
||||||
|
check_id: loop |
||||||
|
set @sec_key = null; |
||||||
|
select concat(@branchCode,substring('ACDEFGHJKLMNPQRSTUVWXYZ235679', rand()*29+1, 1), |
||||||
|
substring('ACDEFGHJKLMNPQRSTUVWXYZ235679', rand()*29+1, 1), |
||||||
|
substring('ACDEFGHJKLMNPQRSTUVWXYZ235679', rand()*29+1, 1), |
||||||
|
substring('ACDEFGHJKLMNPQRSTUVWXYZ235679', rand()*29+1, 1) |
||||||
|
) into @sec_key; |
||||||
|
return @sec_key; |
||||||
|
set @tot_sec = null; |
||||||
|
select count(*) into @tot_sec |
||||||
|
from mitra where MitraIDNo = @sec_key; |
||||||
|
if @tot_sec = 0 and length(@sec_key) <> 6 then |
||||||
|
return @sec_key; |
||||||
|
end if; |
||||||
|
if @counter > 10 then |
||||||
|
return "ERR.DUP"; |
||||||
|
end if; |
||||||
|
set @counter = @counter+1; |
||||||
|
end loop; |
||||||
|
end;; |
||||||
|
*/ |
Loading…
Reference in new issue