padmanto
3 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