Browse Source

Up to Mou Lookup

main
padmanto 3 years ago
parent
commit
cf987b68f8
  1. 10
      helper_func.fish
  2. 1
      lib/app/constants.dart
  3. 48
      lib/model/ac_company_response_model.dart
  4. 45
      lib/model/ac_mou_response_model.dart
  5. 76
      lib/model/mitra_response_model.dart
  6. 20
      lib/repository/base_repository.dart
  7. 56
      lib/repository/mitra_repository.dart
  8. 76
      lib/screen/md_lab_mitra/md_lab_mitra_screen.dart
  9. 70
      lib/screen/md_lab_mitra/mitra_lookup_mou_provider.dart
  10. 70
      lib/screen/md_lab_mitra/mitra_search_provider.dart
  11. 5
      lib/screen/md_lab_mitra/selectedCompanyProvider.dart
  12. 92
      lib/widget/fx_company_lookup.dart
  13. 207
      lib/widget/fx_data_mitra.dart
  14. 20
      lib/widget/fx_debouncer.dart
  15. 20
      lib/widget/fx_error_text.dart
  16. 37
      lib/widget/fx_mitra_add_dialog.dart
  17. 68
      lib/widget/fx_mitra_mou.dart
  18. 86
      lib/widget/loading_page_widget.dart
  19. 12
      php-api/mitra/Md-curl.md
  20. 172
      php-api/mitra/Md.php

10
helper_func.fish

@ -9,3 +9,13 @@ rsync -avzr --progress canvaskit one@$cabang:/home/one/project/one/one-ui-flutte
rsync -avzr --progress icons one@$cabang:/home/one/project/one/one-ui-flutter/md-mitra/
cd ../..
end
function ul_api_to
set cabang $argv[2]
set target (string replace php-api/ "" $argv[1])
echo upload to $cabang
cd php-api
rsync -avzr --progress $target one@devone.aplikasi.web.id:/home/one/project/one/one-api/application/controllers/$target
cd ..
end

1
lib/app/constants.dart

@ -20,6 +20,7 @@ class Constants {
static const fontMediumSize = 16.0;
static const fontSmallSize = 14.0;
static String appVersion = "v0.1";
static String baseUrl = "http://devone.aplikasi.web.id/one-api/mitra/";
static const Color colorNegative = Color(0xff95424E);
}

48
lib/model/ac_company_response_model.dart

@ -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;
}
}

45
lib/model/ac_mou_response_model.dart

@ -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;
}
}

76
lib/model/mitra_response_model.dart

@ -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;
}
}

20
lib/repository/base_repository.dart

@ -1,3 +1,4 @@
import 'dart:convert';
import 'dart:io';
import 'package:dio/dio.dart';
@ -6,7 +7,7 @@ abstract class BaseRepository {
final Dio dio;
BaseRepository({required this.dio});
Future<dynamic> get({
Future<Map<String, dynamic>> get({
required String service,
CancelToken? cancelToken,
}) async {
@ -26,7 +27,11 @@ abstract class BaseRepository {
message: "Invalid Http Response ${response.statusCode}",
);
}
return response.data;
final jData = jsonDecode(response.data);
if (jData["status"] == "ERR") {
throw BaseRepositoryException(message: jData["message"]);
}
return jData;
} on DioError catch (e) {
throw BaseRepositoryException(message: e.message);
} on SocketException catch (e) {
@ -36,7 +41,7 @@ abstract class BaseRepository {
}
}
Future<dynamic> post({
Future<Map<String, dynamic>> post({
required String service,
required Map<String, dynamic> jsonParam,
CancelToken? cancelToken,
@ -55,10 +60,15 @@ abstract class BaseRepository {
);
if (response.statusCode != 200) {
throw BaseRepositoryException(
message: "Invalid Http Response ${response.statusCode}",
message:
"Invalid Http Response ${response.statusCode} |${response.statusMessage}",
);
}
return response.data;
final jData = jsonDecode(response.data);
if (jData["status"] == "ERR") {
throw BaseRepositoryException(message: jData["message"]);
}
return jData;
} on DioError catch (e) {
throw BaseRepositoryException(message: e.message);
} on SocketException catch (e) {

56
lib/repository/mitra_repository.dart

@ -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;
}
}

76
lib/screen/md_lab_mitra/md_lab_mitra_screen.dart

@ -3,6 +3,9 @@ import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import '../../provider/local_auth_provider.dart';
import '../../provider/title_provider.dart';
import '../../widget/fx_data_mitra.dart';
import 'mitra_search_provider.dart';
class MdLabMitraScreen extends HookConsumerWidget {
const MdLabMitraScreen({Key? key}) : super(key: key);
@ -10,78 +13,27 @@ class MdLabMitraScreen extends HookConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final size = MediaQuery.of(context).size;
final errorMessage = useState("");
final oneUser = ref.read(localAuthProvider);
final isInit = useState(true);
if (oneUser == null) {
redirectToHome();
}
if (isInit.value) {
isInit.value = false;
WidgetsBinding.instance.addPostFrameCallback((_) {
ref.read(webTitleProvider.notifier).state = "Master data::Lab Mitra";
ref.read(mitraSearchProvider.notifier).search(query: "");
});
}
return Material(
child: Container(
height: size.height,
width: size.width,
color: Colors.white,
child: Padding(
padding: const EdgeInsets.all(20.0),
child: Row(
children: [
Expanded(
flex: 3,
child: Container(color: Colors.green),
),
const Expanded(
flex: 7,
child: Align(
alignment: Alignment.topLeft,
child: Text("MD Lab Mitra"),
),
),
],
),
),
),
);
}
}
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,
),
child: const Padding(
padding: EdgeInsets.all(20.0),
child: Expanded(child: FxDataMitra()),
),
],
),
);
}

70
lib/screen/md_lab_mitra/mitra_lookup_mou_provider.dart

@ -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,
});
}

70
lib/screen/md_lab_mitra/mitra_search_provider.dart

@ -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,
});
}

5
lib/screen/md_lab_mitra/selectedCompanyProvider.dart

@ -0,0 +1,5 @@
import 'package:flutter_riverpod/flutter_riverpod.dart';
import '../../model/ac_company_response_model.dart';
final selectdAcCompanyProvider = StateProvider<AcCompanyModel?>((ref) => null);

92
lib/widget/fx_company_lookup.dart

@ -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),
],
),
),
));
}),
),
),
);
});
}
}

207
lib/widget/fx_data_mitra.dart

@ -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;
}

20
lib/widget/fx_debouncer.dart

@ -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);
}
}

20
lib/widget/fx_error_text.dart

@ -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,
),
);
}
}

37
lib/widget/fx_mitra_add_dialog.dart

@ -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),
],
),
)),
);
}
}

68
lib/widget/fx_mitra_mou.dart

@ -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);
}),
),
]),
),
),
);
}
}

86
lib/widget/loading_page_widget.dart

@ -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,
),
),
],
),
);
}
}

12
php-api/mitra/Md-curl.md

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

172
php-api/mitra/Md.php

@ -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…
Cancel
Save