step 11 : proses clock in, clock out
This commit is contained in:
BIN
images/presensi_finger_clok_out.png
Normal file
BIN
images/presensi_finger_clok_out.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.9 KiB |
@@ -13,6 +13,9 @@ class Constant {
|
|||||||
static double designHeightPhone = 844;
|
static double designHeightPhone = 844;
|
||||||
static double designWidthPhone = 390;
|
static double designWidthPhone = 390;
|
||||||
|
|
||||||
|
// NOTE VERSI HARUS SAMA DENGAN PUBSPEC.YAML
|
||||||
|
static String version = "1.0.1";
|
||||||
|
|
||||||
// color theme
|
// color theme
|
||||||
static Color textTrueBlack = const Color(0xff000000);
|
static Color textTrueBlack = const Color(0xff000000);
|
||||||
static Color textBlack = const Color(0xff212B36);
|
static Color textBlack = const Color(0xff212B36);
|
||||||
|
|||||||
36
lib/model/check_presensi_jam_model.dart
Normal file
36
lib/model/check_presensi_jam_model.dart
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
class CheckPresensiJamModel {
|
||||||
|
String? status;
|
||||||
|
String? message;
|
||||||
|
String? jamClockIn;
|
||||||
|
String? jamClockOut;
|
||||||
|
String? isAbsenClockIn;
|
||||||
|
String? isAbsenClockOut;
|
||||||
|
|
||||||
|
CheckPresensiJamModel(
|
||||||
|
{this.status,
|
||||||
|
this.message,
|
||||||
|
this.jamClockIn,
|
||||||
|
this.jamClockOut,
|
||||||
|
this.isAbsenClockIn,
|
||||||
|
this.isAbsenClockOut});
|
||||||
|
|
||||||
|
CheckPresensiJamModel.fromJson(Map<String, dynamic> json) {
|
||||||
|
status = json['status'];
|
||||||
|
message = json['message'];
|
||||||
|
jamClockIn = json['jam_clock_in'];
|
||||||
|
jamClockOut = json['jam_clock_out'];
|
||||||
|
isAbsenClockIn = json['is_absen_clock_in'];
|
||||||
|
isAbsenClockOut = json['is_absen_clock_out'];
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
final Map<String, dynamic> data = new Map<String, dynamic>();
|
||||||
|
data['status'] = this.status;
|
||||||
|
data['message'] = this.message;
|
||||||
|
data['jam_clock_in'] = this.jamClockIn;
|
||||||
|
data['jam_clock_out'] = this.jamClockOut;
|
||||||
|
data['is_absen_clock_in'] = this.isAbsenClockIn;
|
||||||
|
data['is_absen_clock_out'] = this.isAbsenClockOut;
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
}
|
||||||
4
lib/provider/current_check_jam_presensi_provider.dart
Normal file
4
lib/provider/current_check_jam_presensi_provider.dart
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
import 'package:absensi_sas_flutter/model/check_presensi_jam_model.dart';
|
||||||
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
|
|
||||||
|
final currentCheckJamPresensiProvider = StateProvider<CheckPresensiJamModel?>((ref) => null);
|
||||||
3
lib/provider/current_menu_provider.dart
Normal file
3
lib/provider/current_menu_provider.dart
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
|
|
||||||
|
final currentPageProvider = StateProvider<int?>((ref) => null);
|
||||||
@@ -5,6 +5,9 @@ import '../app/constant.dart';
|
|||||||
|
|
||||||
final graphqlProvider = Provider.family<GraphQLClient, String>(
|
final graphqlProvider = Provider.family<GraphQLClient, String>(
|
||||||
(_, token) {
|
(_, token) {
|
||||||
|
final policies = Policies(
|
||||||
|
fetch: FetchPolicy.noCache,
|
||||||
|
);
|
||||||
return GraphQLClient(
|
return GraphQLClient(
|
||||||
link: (token != "")
|
link: (token != "")
|
||||||
? HttpLink(
|
? HttpLink(
|
||||||
@@ -17,6 +20,11 @@ final graphqlProvider = Provider.family<GraphQLClient, String>(
|
|||||||
Constant.baseURLGraphQl,
|
Constant.baseURLGraphQl,
|
||||||
),
|
),
|
||||||
cache: GraphQLCache(),
|
cache: GraphQLCache(),
|
||||||
|
defaultPolicies: DefaultPolicies(
|
||||||
|
watchQuery: policies,
|
||||||
|
query: policies,
|
||||||
|
mutate: policies,
|
||||||
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import 'package:absensi_sas_flutter/model/check_distance_model.dart';
|
import 'package:absensi_sas_flutter/model/check_distance_model.dart';
|
||||||
|
import 'package:absensi_sas_flutter/model/check_presensi_jam_model.dart';
|
||||||
import 'base_repository.dart';
|
import 'base_repository.dart';
|
||||||
|
|
||||||
class PresensiRepository extends BaseRepository {
|
class PresensiRepository extends BaseRepository {
|
||||||
@@ -23,7 +24,7 @@ class PresensiRepository extends BaseRepository {
|
|||||||
final resp = await postGraphQlMutation(query, inpVariables);
|
final resp = await postGraphQlMutation(query, inpVariables);
|
||||||
// final loginData = AuthModel.fromJson(resp['userLogin']);
|
// final loginData = AuthModel.fromJson(resp['userLogin']);
|
||||||
|
|
||||||
print(inpVariables);
|
// print(inpVariables);
|
||||||
|
|
||||||
print('obj queryCheckDistance : ${resp["queryCheckDistance"]}');
|
print('obj queryCheckDistance : ${resp["queryCheckDistance"]}');
|
||||||
|
|
||||||
@@ -33,12 +34,145 @@ class PresensiRepository extends BaseRepository {
|
|||||||
// );
|
// );
|
||||||
|
|
||||||
final result = CheckDistanceModel(
|
final result = CheckDistanceModel(
|
||||||
currentDistance: resp['queryCheckDistance']['current_distance'],
|
currentDistance: resp['queryCheckDistance']['current_distance'],
|
||||||
maxDistance: resp['queryCheckDistance']['max_distance'],
|
maxDistance: resp['queryCheckDistance']['max_distance'],
|
||||||
message: resp['queryCheckDistance']['message'],
|
message: resp['queryCheckDistance']['message'],
|
||||||
selfie: resp['queryCheckDistance']['selfie'],
|
selfie: resp['queryCheckDistance']['selfie'],
|
||||||
status: resp['queryCheckDistance']['status'],
|
status: resp['queryCheckDistance']['status'],
|
||||||
unit: resp['queryCheckDistance']['unit']
|
unit: resp['queryCheckDistance']['unit']);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// presensi normal Clock In
|
||||||
|
Future<String> presensiNormalClockIn(
|
||||||
|
String T_TransactionM_StaffID,
|
||||||
|
String T_TransactionM_CompanyID,
|
||||||
|
String T_TransactionCurrentLatitude,
|
||||||
|
String T_TransactionCurrentLongitude,
|
||||||
|
String T_TransactionCurrentDistance,
|
||||||
|
String T_TransactionSelfiePhoto,
|
||||||
|
String token,
|
||||||
|
String isSelfie,
|
||||||
|
Map<String, dynamic> paramInpVariables) async {
|
||||||
|
const String query =
|
||||||
|
r'''mutation($T_TransactionM_StaffID:String!, $T_TransactionM_CompanyID:String!, $T_TransactionCurrentLatitude:String!, $T_TransactionCurrentLongitude:String!, $T_TransactionCurrentDistance:String!, $T_TransactionSelfiePhoto:String, $token:String!, $isSelfie:String!){ mutationClockInAttendance(T_TransactionM_StaffID:$T_TransactionM_StaffID, T_TransactionM_CompanyID:$T_TransactionM_CompanyID, T_TransactionCurrentLatitude:$T_TransactionCurrentLatitude, T_TransactionCurrentLongitude:$T_TransactionCurrentLongitude, T_TransactionCurrentDistance:$T_TransactionCurrentDistance, T_TransactionSelfiePhoto:$T_TransactionSelfiePhoto, token:$token, isSelfie:$isSelfie){ status message } }''';
|
||||||
|
|
||||||
|
Map<String, dynamic> inpVariables = paramInpVariables;
|
||||||
|
print(paramInpVariables);
|
||||||
|
|
||||||
|
final resp = await postGraphQlMutation(query, inpVariables);
|
||||||
|
|
||||||
|
// print(inpVariables);
|
||||||
|
|
||||||
|
print(
|
||||||
|
'obj mutationClockInAttendance : ${resp["mutationClockInAttendance"]}');
|
||||||
|
|
||||||
|
// final result = AuthModel(
|
||||||
|
// token: resp["loginAttendance"]["token"],
|
||||||
|
// model: StaffModel.fromJson(resp["loginAttendance"]),
|
||||||
|
// );
|
||||||
|
|
||||||
|
final result = resp["mutationClockInAttendance"]['status'];
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// presensi normal clock Out
|
||||||
|
Future<String> presensiNormalClockOut(
|
||||||
|
String T_TransactionM_StaffID,
|
||||||
|
String T_TransactionM_CompanyID,
|
||||||
|
String T_TransactionCurrentLatitude,
|
||||||
|
String T_TransactionCurrentLongitude,
|
||||||
|
String T_TransactionCurrentDistance,
|
||||||
|
String T_TransactionSelfiePhoto,
|
||||||
|
String token,
|
||||||
|
String isSelfie,
|
||||||
|
Map<String, dynamic> paramInpVariables) async {
|
||||||
|
const String query =
|
||||||
|
r'''mutation(
|
||||||
|
$T_TransactionM_StaffID:String!,
|
||||||
|
$T_TransactionM_CompanyID:String!,
|
||||||
|
$T_TransactionCurrentLatitude:String!,
|
||||||
|
$T_TransactionCurrentLongitude:String!,
|
||||||
|
$T_TransactionCurrentDistance:String!,
|
||||||
|
$T_TransactionSelfiePhoto:String,
|
||||||
|
$token:String!,
|
||||||
|
$isSelfie:String!
|
||||||
|
){
|
||||||
|
mutationClockOutAttendance(
|
||||||
|
T_TransactionM_StaffID:$T_TransactionM_StaffID,
|
||||||
|
T_TransactionM_CompanyID:$T_TransactionM_CompanyID,
|
||||||
|
T_TransactionCurrentLatitude:$T_TransactionCurrentLatitude,
|
||||||
|
T_TransactionCurrentLongitude:$T_TransactionCurrentLongitude,
|
||||||
|
T_TransactionCurrentDistance:$T_TransactionCurrentDistance,
|
||||||
|
T_TransactionSelfiePhoto:$T_TransactionSelfiePhoto,
|
||||||
|
token:$token, isSelfie:$isSelfie
|
||||||
|
){
|
||||||
|
status
|
||||||
|
message
|
||||||
|
}
|
||||||
|
}''';
|
||||||
|
|
||||||
|
Map<String, dynamic> inpVariables = paramInpVariables;
|
||||||
|
print(paramInpVariables);
|
||||||
|
|
||||||
|
final resp = await postGraphQlMutation(query, inpVariables);
|
||||||
|
|
||||||
|
// print(inpVariables);
|
||||||
|
|
||||||
|
print(
|
||||||
|
'obj mutationClockOutAttendance : ${resp["mutationClockOutAttendance"]}');
|
||||||
|
|
||||||
|
// final result = AuthModel(
|
||||||
|
// token: resp["loginAttendance"]["token"],
|
||||||
|
// model: StaffModel.fromJson(resp["loginAttendance"]),
|
||||||
|
// );
|
||||||
|
|
||||||
|
final result = resp["mutationClockOutAttendance"]['status'];
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check presensi jam
|
||||||
|
Future<CheckPresensiJamModel> checkPresensiJam(
|
||||||
|
String M_StaffID,
|
||||||
|
String M_CompanyID,
|
||||||
|
String token,
|
||||||
|
Map<String, dynamic> paramInpVariables,
|
||||||
|
) async {
|
||||||
|
const String query =
|
||||||
|
r'''query($M_StaffID:String!, $M_CompanyID:String!, $token:String!){
|
||||||
|
queryCheckTimeAttendance(M_StaffID:$M_StaffID, M_CompanyID:$M_CompanyID, token:$token){
|
||||||
|
status
|
||||||
|
message
|
||||||
|
jam_clock_in
|
||||||
|
jam_clock_out
|
||||||
|
is_absen_clock_in
|
||||||
|
is_absen_clock_out
|
||||||
|
}
|
||||||
|
}''';
|
||||||
|
|
||||||
|
// Map<String, dynamic> inpVariables = paramInpVariables;
|
||||||
|
|
||||||
|
// Map<String, dynamic> inpVariables = {
|
||||||
|
// "M_StaffID": M_StaffID,
|
||||||
|
// "M_CompanyID": M_CompanyID,
|
||||||
|
// "token": token,
|
||||||
|
// };
|
||||||
|
|
||||||
|
print(paramInpVariables);
|
||||||
|
|
||||||
|
final resp = await postGraphQlQuery(query, paramInpVariables);
|
||||||
|
|
||||||
|
// print(inpVariables);
|
||||||
|
|
||||||
|
print('obj queryCheckTimeAttendance : ${resp["queryCheckTimeAttendance"]}');
|
||||||
|
|
||||||
|
final result = CheckPresensiJamModel(
|
||||||
|
isAbsenClockIn: resp['queryCheckTimeAttendance']['is_absen_clock_in'],
|
||||||
|
isAbsenClockOut: resp['queryCheckTimeAttendance']['is_absen_clock_out'],
|
||||||
|
jamClockIn: resp['queryCheckTimeAttendance']['jam_clock_in'],
|
||||||
|
jamClockOut: resp['queryCheckTimeAttendance']['jam_clock_out'],
|
||||||
|
message: resp['queryCheckTimeAttendance']['message'],
|
||||||
|
status: resp['queryCheckTimeAttendance']['status'],
|
||||||
);
|
);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -11,6 +11,7 @@ import 'package:shared_preferences/shared_preferences.dart';
|
|||||||
import '../../app/constant.dart';
|
import '../../app/constant.dart';
|
||||||
import '../../app/route.dart';
|
import '../../app/route.dart';
|
||||||
import '../../model/auth_model.dart';
|
import '../../model/auth_model.dart';
|
||||||
|
import '../../provider/current_menu_provider.dart';
|
||||||
import '../../provider/current_user_provider.dart';
|
import '../../provider/current_user_provider.dart';
|
||||||
import '../../provider/google_login_provider.dart';
|
import '../../provider/google_login_provider.dart';
|
||||||
|
|
||||||
@@ -92,6 +93,7 @@ class LoginScreen extends HookConsumerWidget {
|
|||||||
.read(currentUserGoogleProvider.notifier)
|
.read(currentUserGoogleProvider.notifier)
|
||||||
.update((state) => account);
|
.update((state) => account);
|
||||||
ref.read(currentUserProvider.notifier).state = authModel;
|
ref.read(currentUserProvider.notifier).state = authModel;
|
||||||
|
ref.read(currentPageProvider.state).update((state) => 0);
|
||||||
Navigator.of(context).pushNamedAndRemoveUntil(
|
Navigator.of(context).pushNamedAndRemoveUntil(
|
||||||
homeRoute,
|
homeRoute,
|
||||||
(route) => false,
|
(route) => false,
|
||||||
@@ -121,7 +123,7 @@ class LoginScreen extends HookConsumerWidget {
|
|||||||
} else if (next is LoginStateDone) {
|
} else if (next is LoginStateDone) {
|
||||||
isLoading.value = false;
|
isLoading.value = false;
|
||||||
isSuccess.value = true;
|
isSuccess.value = true;
|
||||||
// ref.read(currentPageProvider.state).update((state) => 0);
|
ref.read(currentPageProvider.state).update((state) => 0);
|
||||||
Navigator.of(context)
|
Navigator.of(context)
|
||||||
.pushNamedAndRemoveUntil(homeRoute, (route) => false);
|
.pushNamedAndRemoveUntil(homeRoute, (route) => false);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import 'package:absensi_sas_flutter/provider/current_user_provider.dart';
|
||||||
import 'package:absensi_sas_flutter/repository/presensi_repository.dart';
|
import 'package:absensi_sas_flutter/repository/presensi_repository.dart';
|
||||||
|
|
||||||
import 'package:equatable/equatable.dart';
|
import 'package:equatable/equatable.dart';
|
||||||
@@ -7,6 +8,7 @@ import '../../provider/current_check_distance_provider.dart';
|
|||||||
import '../../provider/dio_provider.dart';
|
import '../../provider/dio_provider.dart';
|
||||||
import '../../provider/graphql_provider.dart';
|
import '../../provider/graphql_provider.dart';
|
||||||
import '../../repository/base_repository.dart';
|
import '../../repository/base_repository.dart';
|
||||||
|
import 'check_presensi_jam_provider.dart';
|
||||||
|
|
||||||
abstract class CheckDistanceState extends Equatable {
|
abstract class CheckDistanceState extends Equatable {
|
||||||
final DateTime date;
|
final DateTime date;
|
||||||
@@ -63,6 +65,21 @@ class CheckDistanceNotifier extends StateNotifier<CheckDistanceState> {
|
|||||||
);
|
);
|
||||||
// set ke global state provider
|
// set ke global state provider
|
||||||
ref.read(currentCheckDistanceProvider.notifier).update((state) => resp);
|
ref.read(currentCheckDistanceProvider.notifier).update((state) => resp);
|
||||||
|
|
||||||
|
// panggil provider cek jam masuk dan pulang (checkPresensiJamProvider)
|
||||||
|
final user = ref.read(currentUserProvider);
|
||||||
|
Map<String, dynamic> inpVariablesCheckPresensiJam = {
|
||||||
|
"M_StaffID": M_StaffID,
|
||||||
|
"M_CompanyID": M_CompanyID,
|
||||||
|
"token": user?.token ?? "",
|
||||||
|
};
|
||||||
|
ref.read(checkPresensiJamProvider.notifier).checkPresensiJam(
|
||||||
|
M_StaffID,
|
||||||
|
M_CompanyID,
|
||||||
|
user?.token ?? "",
|
||||||
|
inpVariablesCheckPresensiJam,
|
||||||
|
);
|
||||||
|
|
||||||
state = CheckDistanceStateDone(model: resp);
|
state = CheckDistanceStateDone(model: resp);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (e is BaseRepositoryException) {
|
if (e is BaseRepositoryException) {
|
||||||
|
|||||||
81
lib/screen/presensi/check_presensi_jam_provider.dart
Normal file
81
lib/screen/presensi/check_presensi_jam_provider.dart
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
import 'package:absensi_sas_flutter/model/check_presensi_jam_model.dart';
|
||||||
|
import 'package:absensi_sas_flutter/repository/presensi_repository.dart';
|
||||||
|
|
||||||
|
import 'package:equatable/equatable.dart';
|
||||||
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
|
import '../../provider/current_check_jam_presensi_provider.dart';
|
||||||
|
import '../../provider/dio_provider.dart';
|
||||||
|
import '../../provider/graphql_provider.dart';
|
||||||
|
import '../../repository/base_repository.dart';
|
||||||
|
|
||||||
|
abstract class CheckPresensiJamState extends Equatable {
|
||||||
|
final DateTime date;
|
||||||
|
const CheckPresensiJamState(this.date);
|
||||||
|
@override
|
||||||
|
List<Object?> get props => [date];
|
||||||
|
}
|
||||||
|
|
||||||
|
class CheckPresensiJamStateInit extends CheckPresensiJamState {
|
||||||
|
CheckPresensiJamStateInit() : super(DateTime.now());
|
||||||
|
}
|
||||||
|
|
||||||
|
class CheckPresensiJamStateLoading extends CheckPresensiJamState {
|
||||||
|
CheckPresensiJamStateLoading() : super(DateTime.now());
|
||||||
|
}
|
||||||
|
|
||||||
|
class CheckPresensiJamStateError extends CheckPresensiJamState {
|
||||||
|
final String message;
|
||||||
|
CheckPresensiJamStateError({
|
||||||
|
required this.message,
|
||||||
|
}) : super(DateTime.now());
|
||||||
|
}
|
||||||
|
|
||||||
|
class CheckPresensiJamStateDone extends CheckPresensiJamState {
|
||||||
|
final CheckPresensiJamModel model;
|
||||||
|
CheckPresensiJamStateDone({
|
||||||
|
required this.model,
|
||||||
|
}) : super(DateTime.now());
|
||||||
|
}
|
||||||
|
|
||||||
|
//notifier
|
||||||
|
class CheckPresensiJamNotifier extends StateNotifier<CheckPresensiJamState> {
|
||||||
|
final Ref ref;
|
||||||
|
CheckPresensiJamNotifier({
|
||||||
|
required this.ref,
|
||||||
|
}) : super(CheckPresensiJamStateInit());
|
||||||
|
|
||||||
|
void checkPresensiJam(
|
||||||
|
String M_StaffID,
|
||||||
|
String M_CompanyID,
|
||||||
|
String token,
|
||||||
|
Map<String, dynamic> paramInpVariables,
|
||||||
|
) async {
|
||||||
|
try {
|
||||||
|
state = CheckPresensiJamStateLoading();
|
||||||
|
final graphql = ref.read(graphqlProvider(''));
|
||||||
|
final dio = ref.read(dioProvider);
|
||||||
|
final resp = await PresensiRepository(graphql: graphql, dio: dio)
|
||||||
|
.checkPresensiJam(
|
||||||
|
M_StaffID,
|
||||||
|
M_CompanyID,
|
||||||
|
token,
|
||||||
|
paramInpVariables,
|
||||||
|
);
|
||||||
|
// set ke global state provider currentCheckJamPresensiProvider
|
||||||
|
ref.read(currentCheckJamPresensiProvider.notifier).update((state) => resp);
|
||||||
|
state = CheckPresensiJamStateDone(model: resp);
|
||||||
|
} catch (e) {
|
||||||
|
if (e is BaseRepositoryException) {
|
||||||
|
state = CheckPresensiJamStateError(message: e.message ?? "");
|
||||||
|
} else {
|
||||||
|
state = CheckPresensiJamStateError(message: e.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// provider
|
||||||
|
final checkPresensiJamProvider =
|
||||||
|
StateNotifierProvider<CheckPresensiJamNotifier, CheckPresensiJamState>(
|
||||||
|
(ref) => CheckPresensiJamNotifier(ref: ref),
|
||||||
|
);
|
||||||
102
lib/screen/presensi/presensi_clock_in_provider.dart
Normal file
102
lib/screen/presensi/presensi_clock_in_provider.dart
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
import 'package:absensi_sas_flutter/repository/presensi_repository.dart';
|
||||||
|
|
||||||
|
import 'package:equatable/equatable.dart';
|
||||||
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
|
import '../../provider/dio_provider.dart';
|
||||||
|
import '../../provider/graphql_provider.dart';
|
||||||
|
import '../../repository/base_repository.dart';
|
||||||
|
import 'check_presensi_jam_provider.dart';
|
||||||
|
|
||||||
|
abstract class PresensiClockInState extends Equatable {
|
||||||
|
final DateTime date;
|
||||||
|
const PresensiClockInState(this.date);
|
||||||
|
@override
|
||||||
|
List<Object?> get props => [date];
|
||||||
|
}
|
||||||
|
|
||||||
|
class PresensiClockInStateInit extends PresensiClockInState {
|
||||||
|
PresensiClockInStateInit() : super(DateTime.now());
|
||||||
|
}
|
||||||
|
|
||||||
|
class PresensiClockInStateLoading extends PresensiClockInState {
|
||||||
|
PresensiClockInStateLoading() : super(DateTime.now());
|
||||||
|
}
|
||||||
|
|
||||||
|
class PresensiClockInStateError extends PresensiClockInState {
|
||||||
|
final String message;
|
||||||
|
PresensiClockInStateError({
|
||||||
|
required this.message,
|
||||||
|
}) : super(DateTime.now());
|
||||||
|
}
|
||||||
|
|
||||||
|
class PresensiClockInStateDone extends PresensiClockInState {
|
||||||
|
final String model;
|
||||||
|
PresensiClockInStateDone({
|
||||||
|
required this.model,
|
||||||
|
}) : super(DateTime.now());
|
||||||
|
}
|
||||||
|
|
||||||
|
//notifier
|
||||||
|
class PresensiClockInNotifier extends StateNotifier<PresensiClockInState> {
|
||||||
|
final Ref ref;
|
||||||
|
PresensiClockInNotifier({
|
||||||
|
required this.ref,
|
||||||
|
}) : super(PresensiClockInStateInit());
|
||||||
|
|
||||||
|
void presensiClockIn(
|
||||||
|
String T_TransactionM_StaffID,
|
||||||
|
String T_TransactionM_CompanyID,
|
||||||
|
String T_TransactionCurrentLatitude,
|
||||||
|
String T_TransactionCurrentLongitude,
|
||||||
|
String T_TransactionCurrentDistance,
|
||||||
|
String T_TransactionSelfiePhoto,
|
||||||
|
String token,
|
||||||
|
String isSelfie,
|
||||||
|
Map<String, dynamic> paramInpVariables,
|
||||||
|
) async {
|
||||||
|
try {
|
||||||
|
state = PresensiClockInStateLoading();
|
||||||
|
final graphql = ref.read(graphqlProvider(''));
|
||||||
|
final dio = ref.read(dioProvider);
|
||||||
|
final resp = await PresensiRepository(graphql: graphql, dio: dio)
|
||||||
|
.presensiNormalClockIn(
|
||||||
|
T_TransactionM_StaffID,
|
||||||
|
T_TransactionM_CompanyID,
|
||||||
|
T_TransactionCurrentLatitude,
|
||||||
|
T_TransactionCurrentLongitude,
|
||||||
|
T_TransactionCurrentDistance,
|
||||||
|
T_TransactionSelfiePhoto,
|
||||||
|
token,
|
||||||
|
isSelfie,
|
||||||
|
paramInpVariables,
|
||||||
|
);
|
||||||
|
|
||||||
|
// panggil provider cek jam masuk dan pulang (checkPresensiJamProvider)
|
||||||
|
Map<String, dynamic> inpVariablesCheckPresensiJam = {
|
||||||
|
"M_StaffID": T_TransactionM_StaffID,
|
||||||
|
"M_CompanyID": T_TransactionM_CompanyID,
|
||||||
|
"token": token,
|
||||||
|
};
|
||||||
|
ref.read(checkPresensiJamProvider.notifier).checkPresensiJam(
|
||||||
|
T_TransactionM_StaffID,
|
||||||
|
T_TransactionM_CompanyID,
|
||||||
|
token,
|
||||||
|
inpVariablesCheckPresensiJam,
|
||||||
|
);
|
||||||
|
print('call check presensi');
|
||||||
|
state = PresensiClockInStateDone(model: resp);
|
||||||
|
} catch (e) {
|
||||||
|
if (e is BaseRepositoryException) {
|
||||||
|
state = PresensiClockInStateError(message: e.message ?? "");
|
||||||
|
} else {
|
||||||
|
state = PresensiClockInStateError(message: e.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// provider
|
||||||
|
final presensiClockInProvider =
|
||||||
|
StateNotifierProvider<PresensiClockInNotifier, PresensiClockInState>(
|
||||||
|
(ref) => PresensiClockInNotifier(ref: ref),
|
||||||
|
);
|
||||||
102
lib/screen/presensi/presensi_clock_out_provider.dart
Normal file
102
lib/screen/presensi/presensi_clock_out_provider.dart
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
import 'package:absensi_sas_flutter/repository/presensi_repository.dart';
|
||||||
|
|
||||||
|
import 'package:equatable/equatable.dart';
|
||||||
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
|
import '../../provider/dio_provider.dart';
|
||||||
|
import '../../provider/graphql_provider.dart';
|
||||||
|
import '../../repository/base_repository.dart';
|
||||||
|
import 'check_presensi_jam_provider.dart';
|
||||||
|
|
||||||
|
abstract class PresensiClockOutState extends Equatable {
|
||||||
|
final DateTime date;
|
||||||
|
const PresensiClockOutState(this.date);
|
||||||
|
@override
|
||||||
|
List<Object?> get props => [date];
|
||||||
|
}
|
||||||
|
|
||||||
|
class PresensiClockOutStateInit extends PresensiClockOutState {
|
||||||
|
PresensiClockOutStateInit() : super(DateTime.now());
|
||||||
|
}
|
||||||
|
|
||||||
|
class PresensiClockOutStateLoading extends PresensiClockOutState {
|
||||||
|
PresensiClockOutStateLoading() : super(DateTime.now());
|
||||||
|
}
|
||||||
|
|
||||||
|
class PresensiClockOutStateError extends PresensiClockOutState {
|
||||||
|
final String message;
|
||||||
|
PresensiClockOutStateError({
|
||||||
|
required this.message,
|
||||||
|
}) : super(DateTime.now());
|
||||||
|
}
|
||||||
|
|
||||||
|
class PresensiClockOutStateDone extends PresensiClockOutState {
|
||||||
|
final String model;
|
||||||
|
PresensiClockOutStateDone({
|
||||||
|
required this.model,
|
||||||
|
}) : super(DateTime.now());
|
||||||
|
}
|
||||||
|
|
||||||
|
//notifier
|
||||||
|
class PresensiClockOutNotifier extends StateNotifier<PresensiClockOutState> {
|
||||||
|
final Ref ref;
|
||||||
|
PresensiClockOutNotifier({
|
||||||
|
required this.ref,
|
||||||
|
}) : super(PresensiClockOutStateInit());
|
||||||
|
|
||||||
|
void presensiClockOut(
|
||||||
|
String T_TransactionM_StaffID,
|
||||||
|
String T_TransactionM_CompanyID,
|
||||||
|
String T_TransactionCurrentLatitude,
|
||||||
|
String T_TransactionCurrentLongitude,
|
||||||
|
String T_TransactionCurrentDistance,
|
||||||
|
String T_TransactionSelfiePhoto,
|
||||||
|
String token,
|
||||||
|
String isSelfie,
|
||||||
|
Map<String, dynamic> paramInpVariables,
|
||||||
|
) async {
|
||||||
|
try {
|
||||||
|
state = PresensiClockOutStateLoading();
|
||||||
|
final graphql = ref.read(graphqlProvider(''));
|
||||||
|
final dio = ref.read(dioProvider);
|
||||||
|
final resp = await PresensiRepository(graphql: graphql, dio: dio)
|
||||||
|
.presensiNormalClockOut(
|
||||||
|
T_TransactionM_StaffID,
|
||||||
|
T_TransactionM_CompanyID,
|
||||||
|
T_TransactionCurrentLatitude,
|
||||||
|
T_TransactionCurrentLongitude,
|
||||||
|
T_TransactionCurrentDistance,
|
||||||
|
T_TransactionSelfiePhoto,
|
||||||
|
token,
|
||||||
|
isSelfie,
|
||||||
|
paramInpVariables,
|
||||||
|
);
|
||||||
|
|
||||||
|
// panggil provider cek jam masuk dan pulang (checkPresensiJamProvider)
|
||||||
|
Map<String, dynamic> inpVariablesCheckPresensiJam = {
|
||||||
|
"M_StaffID": T_TransactionM_StaffID,
|
||||||
|
"M_CompanyID": T_TransactionM_CompanyID,
|
||||||
|
"token": token,
|
||||||
|
};
|
||||||
|
ref.read(checkPresensiJamProvider.notifier).checkPresensiJam(
|
||||||
|
T_TransactionM_StaffID,
|
||||||
|
T_TransactionM_CompanyID,
|
||||||
|
token,
|
||||||
|
inpVariablesCheckPresensiJam,
|
||||||
|
);
|
||||||
|
print('call check presensi clockout');
|
||||||
|
state = PresensiClockOutStateDone(model: resp);
|
||||||
|
} catch (e) {
|
||||||
|
if (e is BaseRepositoryException) {
|
||||||
|
state = PresensiClockOutStateError(message: e.message ?? "");
|
||||||
|
} else {
|
||||||
|
state = PresensiClockOutStateError(message: e.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// provider
|
||||||
|
final presensiClockOutProvider =
|
||||||
|
StateNotifierProvider<PresensiClockOutNotifier, PresensiClockOutState>(
|
||||||
|
(ref) => PresensiClockOutNotifier(ref: ref),
|
||||||
|
);
|
||||||
@@ -1,4 +1,9 @@
|
|||||||
|
import 'dart:convert';
|
||||||
|
|
||||||
|
import 'package:absensi_sas_flutter/provider/current_check_jam_presensi_provider.dart';
|
||||||
import 'package:absensi_sas_flutter/screen/presensi/check_distance_provider.dart';
|
import 'package:absensi_sas_flutter/screen/presensi/check_distance_provider.dart';
|
||||||
|
import 'package:absensi_sas_flutter/screen/presensi/check_presensi_jam_provider.dart';
|
||||||
|
import 'package:absensi_sas_flutter/screen/presensi/presensi_clock_in_provider.dart';
|
||||||
import 'package:absensi_sas_flutter/widget/real_date.dart';
|
import 'package:absensi_sas_flutter/widget/real_date.dart';
|
||||||
import 'package:absensi_sas_flutter/widget/sankbar_widget.dart';
|
import 'package:absensi_sas_flutter/widget/sankbar_widget.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
@@ -12,7 +17,9 @@ import '../../app/constant.dart';
|
|||||||
import '../../app/route.dart';
|
import '../../app/route.dart';
|
||||||
import '../../provider/current_check_distance_provider.dart';
|
import '../../provider/current_check_distance_provider.dart';
|
||||||
import '../../provider/current_user_provider.dart';
|
import '../../provider/current_user_provider.dart';
|
||||||
|
import '../../widget/custom_drawer.dart';
|
||||||
import '../../widget/real_time.dart';
|
import '../../widget/real_time.dart';
|
||||||
|
import 'presensi_clock_out_provider.dart';
|
||||||
|
|
||||||
class PresensiScreen extends HookConsumerWidget {
|
class PresensiScreen extends HookConsumerWidget {
|
||||||
const PresensiScreen({super.key});
|
const PresensiScreen({super.key});
|
||||||
@@ -23,7 +30,9 @@ class PresensiScreen extends HookConsumerWidget {
|
|||||||
final isLoadingAddressUserLocation = useState<bool>(false);
|
final isLoadingAddressUserLocation = useState<bool>(false);
|
||||||
final isLoadingProsesCheckDistance = useState<bool>(false);
|
final isLoadingProsesCheckDistance = useState<bool>(false);
|
||||||
final varCurrentDistanceProvider = ref.watch(currentCheckDistanceProvider);
|
final varCurrentDistanceProvider = ref.watch(currentCheckDistanceProvider);
|
||||||
final selectedUser = ref.read(currentUserProvider);
|
final varCurrentCheckJamProvider =
|
||||||
|
ref.watch(currentCheckJamPresensiProvider);
|
||||||
|
final selectedUser = ref.watch(currentUserProvider);
|
||||||
|
|
||||||
final positionLatitude = useState<String>("");
|
final positionLatitude = useState<String>("");
|
||||||
final positionLongitude = useState<String>("");
|
final positionLongitude = useState<String>("");
|
||||||
@@ -78,6 +87,7 @@ class PresensiScreen extends HookConsumerWidget {
|
|||||||
if (positionLatitude.value.isNotEmpty &&
|
if (positionLatitude.value.isNotEmpty &&
|
||||||
positionLongitude.value.isNotEmpty) {
|
positionLongitude.value.isNotEmpty) {
|
||||||
print('check distance provider');
|
print('check distance provider');
|
||||||
|
|
||||||
// panggil check distance provider
|
// panggil check distance provider
|
||||||
ref.read(checkDistanceProvider.notifier).checkDistance(
|
ref.read(checkDistanceProvider.notifier).checkDistance(
|
||||||
selectedUser?.model.staffId ?? "",
|
selectedUser?.model.staffId ?? "",
|
||||||
@@ -130,6 +140,64 @@ class PresensiScreen extends HookConsumerWidget {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// check jam presensi
|
||||||
|
ref.listen(checkPresensiJamProvider, (prev, next) {
|
||||||
|
if (next is CheckPresensiJamStateLoading) {
|
||||||
|
isLoadingProsesCheckDistance.value = true;
|
||||||
|
} else if (next is CheckPresensiJamStateError) {
|
||||||
|
isLoadingProsesCheckDistance.value = false;
|
||||||
|
SanckbarWidget(
|
||||||
|
context, "Error : " + next.toString(), snackbarType.warning);
|
||||||
|
} else if (next is CheckPresensiJamStateDone) {
|
||||||
|
isLoadingProsesCheckDistance.value = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// proses presensi clock in
|
||||||
|
ref.listen(presensiClockInProvider, (prev, next) {
|
||||||
|
if (next is PresensiClockInStateLoading) {
|
||||||
|
isLoadingProsesCheckDistance.value = true;
|
||||||
|
} else if (next is PresensiClockInStateError) {
|
||||||
|
isLoadingProsesCheckDistance.value = false;
|
||||||
|
SanckbarWidget(
|
||||||
|
context, "Error : " + next.toString(), snackbarType.warning);
|
||||||
|
} else if (next is PresensiClockInStateDone) {
|
||||||
|
isLoadingProsesCheckDistance.value = false;
|
||||||
|
if (next.model == "OK") {
|
||||||
|
SanckbarWidget(context, "Berhasil Absen Masuk", snackbarType.success);
|
||||||
|
requestLocationPermission();
|
||||||
|
}
|
||||||
|
// else{
|
||||||
|
// if(next.model == "WARNING"){
|
||||||
|
// SanckbarWidget(context, "Berhasil Absen Masuk", snackbarType.success);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// proses presensi clock in
|
||||||
|
ref.listen(presensiClockOutProvider, (prev, next) {
|
||||||
|
if (next is PresensiClockOutStateLoading) {
|
||||||
|
isLoadingProsesCheckDistance.value = true;
|
||||||
|
} else if (next is PresensiClockOutStateError) {
|
||||||
|
isLoadingProsesCheckDistance.value = false;
|
||||||
|
SanckbarWidget(
|
||||||
|
context, "Error : " + next.toString(), snackbarType.warning);
|
||||||
|
} else if (next is PresensiClockOutStateDone) {
|
||||||
|
isLoadingProsesCheckDistance.value = false;
|
||||||
|
if (next.model == "OK") {
|
||||||
|
SanckbarWidget(
|
||||||
|
context, "Berhasil Absen Pulang", snackbarType.success);
|
||||||
|
requestLocationPermission();
|
||||||
|
}
|
||||||
|
// else{
|
||||||
|
// if(next.model == "WARNING"){
|
||||||
|
// SanckbarWidget(context, "Berhasil Absen Masuk", snackbarType.success);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
useEffect(() {
|
useEffect(() {
|
||||||
WidgetsBinding.instance.addPostFrameCallback((timeStamp) async {
|
WidgetsBinding.instance.addPostFrameCallback((timeStamp) async {
|
||||||
final staffID = ref.read(currentUserProvider)?.model.staffId ?? "0";
|
final staffID = ref.read(currentUserProvider)?.model.staffId ?? "0";
|
||||||
@@ -150,18 +218,6 @@ class PresensiScreen extends HookConsumerWidget {
|
|||||||
useEffect(() {
|
useEffect(() {
|
||||||
WidgetsBinding.instance.addPostFrameCallback((timeStamp) async {
|
WidgetsBinding.instance.addPostFrameCallback((timeStamp) async {
|
||||||
requestLocationPermission();
|
requestLocationPermission();
|
||||||
|
|
||||||
// // jika sudah dapat latitude dan logitude baru panggil check distance provider
|
|
||||||
// if (positionLatitude.value.isNotEmpty &&
|
|
||||||
// positionLongitude.value.isNotEmpty) {
|
|
||||||
// // panggil check distance provider
|
|
||||||
// ref.read(checkDistanceProvider.notifier).checkDistance(
|
|
||||||
// selectedUser?.model.staffId ?? "",
|
|
||||||
// selectedUser?.model.companyId ?? "",
|
|
||||||
// positionLatitude.value,
|
|
||||||
// positionLongitude.value,
|
|
||||||
// );
|
|
||||||
// }
|
|
||||||
});
|
});
|
||||||
return () {};
|
return () {};
|
||||||
}, []);
|
}, []);
|
||||||
@@ -176,13 +232,14 @@ class PresensiScreen extends HookConsumerWidget {
|
|||||||
String T_TransactionCurrentDistance,
|
String T_TransactionCurrentDistance,
|
||||||
String T_TransactionSelfiePhoto,
|
String T_TransactionSelfiePhoto,
|
||||||
String token,
|
String token,
|
||||||
|
String tipeAbsen,
|
||||||
) async {
|
) async {
|
||||||
return showDialog(
|
return showDialog(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (BuildContext context) {
|
builder: (BuildContext context) {
|
||||||
return AlertDialog(
|
return AlertDialog(
|
||||||
title: Text('Konfirmasi'),
|
title: Text('Konfirmasi'),
|
||||||
content: Text('Apakah anda yakin untuk melakukan Clock In?'),
|
content: Text('Apakah anda yakin untuk melakukan $tipeAbsen?'),
|
||||||
shape: RoundedRectangleBorder(
|
shape: RoundedRectangleBorder(
|
||||||
borderRadius: BorderRadius.circular(8.0),
|
borderRadius: BorderRadius.circular(8.0),
|
||||||
),
|
),
|
||||||
@@ -191,7 +248,7 @@ class PresensiScreen extends HookConsumerWidget {
|
|||||||
onPressed: () {
|
onPressed: () {
|
||||||
T_TransactionSelfiePhoto = "";
|
T_TransactionSelfiePhoto = "";
|
||||||
|
|
||||||
var param = {
|
Map<String, dynamic> param = {
|
||||||
"T_TransactionM_StaffID": T_TransactionM_StaffID,
|
"T_TransactionM_StaffID": T_TransactionM_StaffID,
|
||||||
"T_TransactionM_CompanyID": T_TransactionM_CompanyID,
|
"T_TransactionM_CompanyID": T_TransactionM_CompanyID,
|
||||||
"T_TransactionCurrentLatitude":
|
"T_TransactionCurrentLatitude":
|
||||||
@@ -201,10 +258,42 @@ class PresensiScreen extends HookConsumerWidget {
|
|||||||
"T_TransactionCurrentDistance":
|
"T_TransactionCurrentDistance":
|
||||||
T_TransactionCurrentDistance,
|
T_TransactionCurrentDistance,
|
||||||
"T_TransactionSelfiePhoto": T_TransactionSelfiePhoto,
|
"T_TransactionSelfiePhoto": T_TransactionSelfiePhoto,
|
||||||
"token":token,
|
"token": token,
|
||||||
|
"isSelfie": "FALSE"
|
||||||
};
|
};
|
||||||
print(param);
|
// print(param);
|
||||||
Navigator.of(context).pop();
|
|
||||||
|
if (tipeAbsen == "Clock In") {
|
||||||
|
ref.read(presensiClockInProvider.notifier).presensiClockIn(
|
||||||
|
T_TransactionM_StaffID,
|
||||||
|
T_TransactionM_CompanyID,
|
||||||
|
T_TransactionCurrentLatitude,
|
||||||
|
T_TransactionCurrentLongitude,
|
||||||
|
T_TransactionCurrentDistance,
|
||||||
|
T_TransactionSelfiePhoto,
|
||||||
|
token,
|
||||||
|
"FALSE",
|
||||||
|
param,
|
||||||
|
);
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
} else {
|
||||||
|
if (tipeAbsen == "Clock Out") {
|
||||||
|
ref
|
||||||
|
.read(presensiClockOutProvider.notifier)
|
||||||
|
.presensiClockOut(
|
||||||
|
T_TransactionM_StaffID,
|
||||||
|
T_TransactionM_CompanyID,
|
||||||
|
T_TransactionCurrentLatitude,
|
||||||
|
T_TransactionCurrentLongitude,
|
||||||
|
T_TransactionCurrentDistance,
|
||||||
|
T_TransactionSelfiePhoto,
|
||||||
|
token,
|
||||||
|
"FALSE",
|
||||||
|
param,
|
||||||
|
);
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
child: Text(
|
child: Text(
|
||||||
'Yakin',
|
'Yakin',
|
||||||
@@ -280,6 +369,7 @@ class PresensiScreen extends HookConsumerWidget {
|
|||||||
// elevation: 1.0,
|
// elevation: 1.0,
|
||||||
elevation: 0.5,
|
elevation: 0.5,
|
||||||
),
|
),
|
||||||
|
drawer: CustomDrawer(),
|
||||||
body: SafeArea(
|
body: SafeArea(
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: EdgeInsets.only(
|
padding: EdgeInsets.only(
|
||||||
@@ -415,74 +505,137 @@ class PresensiScreen extends HookConsumerWidget {
|
|||||||
height: Constant.getActualYPhone(context: context, y: 50),
|
height: Constant.getActualYPhone(context: context, y: 50),
|
||||||
),
|
),
|
||||||
|
|
||||||
// gambar icon presensi
|
// tombol aksi absen masuk & pulang
|
||||||
Container(
|
if (varCurrentCheckJamProvider?.isAbsenClockIn == "TRUE" &&
|
||||||
width: Constant.getActualXPhone(context: context, x: 130),
|
varCurrentCheckJamProvider?.isAbsenClockIn == "TRUE") ...[
|
||||||
height: Constant.getActualYPhone(context: context, y: 130),
|
SizedBox.shrink()
|
||||||
child: FittedBox(
|
] else ...[
|
||||||
child: FloatingActionButton(
|
if (varCurrentCheckJamProvider?.isAbsenClockIn == "FALSE" &&
|
||||||
onPressed: () async {
|
varCurrentCheckJamProvider?.jamClockIn == "") ...[
|
||||||
final T_TransactionM_StaffID =
|
// gambar icon presensi clock in
|
||||||
selectedUser?.model.staffId ?? "";
|
(isLoadingAddressUserLocation.value)
|
||||||
final T_TransactionM_CompanyID =
|
? Center(
|
||||||
selectedUser?.model.companyId ?? "";
|
child: CircularProgressIndicator(),
|
||||||
final T_TransactionCurrentLatitude =
|
)
|
||||||
positionLatitude.value;
|
: Container(
|
||||||
final T_TransactionCurrentLongitude =
|
width: Constant.getActualXPhone(
|
||||||
positionLongitude.value;
|
context: context, x: 130),
|
||||||
final T_TransactionCurrentDistance =
|
height: Constant.getActualYPhone(
|
||||||
varCurrentDistanceProvider?.currentDistance ?? "";
|
context: context, y: 130),
|
||||||
final T_TransactionSelfiePhoto = "";
|
child: FittedBox(
|
||||||
final token = selectedUser?.token ?? "";
|
child: FloatingActionButton(
|
||||||
|
onPressed: () async {
|
||||||
|
final T_TransactionM_StaffID =
|
||||||
|
selectedUser?.model.staffId ?? "";
|
||||||
|
final T_TransactionM_CompanyID =
|
||||||
|
selectedUser?.model.companyId ?? "";
|
||||||
|
final T_TransactionCurrentLatitude =
|
||||||
|
positionLatitude.value;
|
||||||
|
final T_TransactionCurrentLongitude =
|
||||||
|
positionLongitude.value;
|
||||||
|
final T_TransactionCurrentDistance =
|
||||||
|
varCurrentDistanceProvider
|
||||||
|
?.currentDistance ??
|
||||||
|
"";
|
||||||
|
final T_TransactionSelfiePhoto = "";
|
||||||
|
final token = selectedUser?.token ?? "";
|
||||||
|
|
||||||
showConfirmationDialog(
|
showConfirmationDialog(
|
||||||
context,
|
context,
|
||||||
T_TransactionM_StaffID,
|
T_TransactionM_StaffID,
|
||||||
T_TransactionM_CompanyID,
|
T_TransactionM_CompanyID,
|
||||||
T_TransactionCurrentLatitude,
|
T_TransactionCurrentLatitude,
|
||||||
T_TransactionCurrentLongitude,
|
T_TransactionCurrentLongitude,
|
||||||
T_TransactionCurrentDistance,
|
T_TransactionCurrentDistance,
|
||||||
T_TransactionSelfiePhoto,
|
T_TransactionSelfiePhoto,
|
||||||
token,
|
token,
|
||||||
);
|
"Clock In");
|
||||||
},
|
},
|
||||||
backgroundColor: Color(0xFFFFFFFF),
|
backgroundColor: Color(0xFFFFFFFF),
|
||||||
shape: CircleBorder(),
|
shape: CircleBorder(),
|
||||||
child: Container(
|
child: Container(
|
||||||
width: Constant.getActualXPhone(
|
width: Constant.getActualXPhone(
|
||||||
context: context, x: 130),
|
context: context, x: 130),
|
||||||
height: Constant.getActualYPhone(
|
height: Constant.getActualYPhone(
|
||||||
context: context, y: 130),
|
context: context, y: 130),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
image: DecorationImage(
|
image: DecorationImage(
|
||||||
// fit: BoxFit.cover,
|
// fit: BoxFit.cover,
|
||||||
image: AssetImage(
|
image: AssetImage(
|
||||||
'images/presensi_finger2.png'), // Ganti dengan path gambar Anda
|
'images/presensi_finger2.png'), // Ganti dengan path gambar Anda
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
] else ...[
|
||||||
),
|
// gambar icon presensi clock out
|
||||||
),
|
if (varCurrentCheckJamProvider?.isAbsenClockIn ==
|
||||||
),
|
"TRUE" &&
|
||||||
),
|
varCurrentCheckJamProvider?.jamClockIn != "") ...[
|
||||||
|
(isLoadingAddressUserLocation.value)
|
||||||
|
? Center(
|
||||||
|
child: CircularProgressIndicator(),
|
||||||
|
)
|
||||||
|
: Container(
|
||||||
|
width: Constant.getActualXPhone(
|
||||||
|
context: context, x: 130),
|
||||||
|
height: Constant.getActualYPhone(
|
||||||
|
context: context, y: 130),
|
||||||
|
child: FittedBox(
|
||||||
|
child: FloatingActionButton(
|
||||||
|
onPressed: () async {
|
||||||
|
final T_TransactionM_StaffID =
|
||||||
|
selectedUser?.model.staffId ?? "";
|
||||||
|
final T_TransactionM_CompanyID =
|
||||||
|
selectedUser?.model.companyId ?? "";
|
||||||
|
final T_TransactionCurrentLatitude =
|
||||||
|
positionLatitude.value;
|
||||||
|
final T_TransactionCurrentLongitude =
|
||||||
|
positionLongitude.value;
|
||||||
|
final T_TransactionCurrentDistance =
|
||||||
|
varCurrentDistanceProvider
|
||||||
|
?.currentDistance ??
|
||||||
|
"";
|
||||||
|
final T_TransactionSelfiePhoto = "";
|
||||||
|
final token = selectedUser?.token ?? "";
|
||||||
|
|
||||||
// Container(
|
showConfirmationDialog(
|
||||||
// width: Constant.getActualXPhone(context: context, x: 100),
|
context,
|
||||||
// height: Constant.getActualYPhone(context: context, y: 200),
|
T_TransactionM_StaffID,
|
||||||
// decoration: BoxDecoration(
|
T_TransactionM_CompanyID,
|
||||||
// image: DecorationImage(
|
T_TransactionCurrentLatitude,
|
||||||
// fit: BoxFit.cover,
|
T_TransactionCurrentLongitude,
|
||||||
// image: AssetImage(
|
T_TransactionCurrentDistance,
|
||||||
// 'images/presensi_finger1.png'), // Ganti dengan path gambar Anda
|
T_TransactionSelfiePhoto,
|
||||||
// ),
|
token,
|
||||||
// ),
|
"Clock Out");
|
||||||
// ),
|
},
|
||||||
|
backgroundColor: Color(0xFFFFFFFF),
|
||||||
|
shape: CircleBorder(),
|
||||||
|
child: Container(
|
||||||
|
width: Constant.getActualXPhone(
|
||||||
|
context: context, x: 130),
|
||||||
|
height: Constant.getActualYPhone(
|
||||||
|
context: context, y: 130),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
image: DecorationImage(
|
||||||
|
// fit: BoxFit.cover,
|
||||||
|
image: AssetImage(
|
||||||
|
'images/presensi_finger_clok_out.png'), // Ganti dengan path gambar Anda
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
]
|
||||||
|
],
|
||||||
|
],
|
||||||
|
|
||||||
Spacer(),
|
Spacer(),
|
||||||
|
|
||||||
// Expanded(
|
|
||||||
// child: SizedBox(),
|
|
||||||
// ),
|
|
||||||
|
|
||||||
// clock in & clock out
|
// clock in & clock out
|
||||||
Padding(
|
Padding(
|
||||||
padding: EdgeInsets.only(
|
padding: EdgeInsets.only(
|
||||||
@@ -510,19 +663,44 @@ class PresensiScreen extends HookConsumerWidget {
|
|||||||
height: Constant.getActualYPhone(
|
height: Constant.getActualYPhone(
|
||||||
context: context, y: 8),
|
context: context, y: 8),
|
||||||
),
|
),
|
||||||
Text(
|
(isLoadingAddressUserLocation.value)
|
||||||
'--:--',
|
? Center(
|
||||||
style: Constant.titlePresensiH2_700(
|
child: CircularProgressIndicator(),
|
||||||
context: context)
|
)
|
||||||
.copyWith(
|
: (varCurrentCheckJamProvider
|
||||||
color: Constant.textTrueBlack,
|
?.isAbsenClockIn ==
|
||||||
),
|
"TRUE" &&
|
||||||
|
varCurrentCheckJamProvider
|
||||||
|
?.jamClockIn !=
|
||||||
|
"")
|
||||||
|
? Text(
|
||||||
|
// '--:--',
|
||||||
|
varCurrentCheckJamProvider
|
||||||
|
?.jamClockIn ??
|
||||||
|
"NULL",
|
||||||
|
style: Constant.titlePresensiH2_700(
|
||||||
|
context: context)
|
||||||
|
.copyWith(
|
||||||
|
color: Constant.textTrueBlack,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
: Text(
|
||||||
|
'--:--',
|
||||||
|
style: Constant.titlePresensiH2_700(
|
||||||
|
context: context)
|
||||||
|
.copyWith(
|
||||||
|
color: Constant.textTrueBlack,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(
|
||||||
|
height: Constant.getActualYPhone(
|
||||||
|
context: context, y: 4),
|
||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
'Clock In',
|
'Clock In',
|
||||||
style: Constant.titleH2_700(context: context)
|
style: Constant.titleH2_700(context: context)
|
||||||
.copyWith(
|
.copyWith(
|
||||||
color: Constant.textTrueBlack,
|
color: Constant.textLightGrey,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@@ -541,19 +719,44 @@ class PresensiScreen extends HookConsumerWidget {
|
|||||||
height: Constant.getActualYPhone(
|
height: Constant.getActualYPhone(
|
||||||
context: context, y: 8),
|
context: context, y: 8),
|
||||||
),
|
),
|
||||||
Text(
|
(isLoadingAddressUserLocation.value)
|
||||||
'--:--',
|
? Center(
|
||||||
style: Constant.titlePresensiH2_700(
|
child: CircularProgressIndicator(),
|
||||||
context: context)
|
)
|
||||||
.copyWith(
|
: (varCurrentCheckJamProvider
|
||||||
color: Constant.textTrueBlack,
|
?.isAbsenClockOut ==
|
||||||
),
|
"TRUE" &&
|
||||||
|
varCurrentCheckJamProvider
|
||||||
|
?.jamClockOut !=
|
||||||
|
"")
|
||||||
|
? Text(
|
||||||
|
// '--:--',
|
||||||
|
varCurrentCheckJamProvider
|
||||||
|
?.jamClockOut ??
|
||||||
|
"NULL",
|
||||||
|
style: Constant.titlePresensiH2_700(
|
||||||
|
context: context)
|
||||||
|
.copyWith(
|
||||||
|
color: Constant.textTrueBlack,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
: Text(
|
||||||
|
'--:--',
|
||||||
|
style: Constant.titlePresensiH2_700(
|
||||||
|
context: context)
|
||||||
|
.copyWith(
|
||||||
|
color: Constant.textTrueBlack,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(
|
||||||
|
height: Constant.getActualYPhone(
|
||||||
|
context: context, y: 4),
|
||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
'Clock Out',
|
'Clock Out',
|
||||||
style: Constant.titleH2_700(context: context)
|
style: Constant.titleH2_700(context: context)
|
||||||
.copyWith(
|
.copyWith(
|
||||||
color: Constant.textTrueBlack,
|
color: Constant.textLightGrey,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@@ -567,81 +770,6 @@ class PresensiScreen extends HookConsumerWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
// bottomNavigationBar: Container(
|
|
||||||
// width: Constant.getActualXPhone(context: context, x: 390),
|
|
||||||
// height: Constant.getActualYPhone(context: context, y: 84),
|
|
||||||
// decoration: BoxDecoration(
|
|
||||||
// color: Color(0xFFFFFFFF),
|
|
||||||
// boxShadow: [
|
|
||||||
// BoxShadow(
|
|
||||||
// offset: Offset(0, -1),
|
|
||||||
// blurRadius: 8,
|
|
||||||
// spreadRadius: -8,
|
|
||||||
// color: Color.fromRGBO(0, 0, 0, 0.10),
|
|
||||||
// ),
|
|
||||||
// ],
|
|
||||||
// ),
|
|
||||||
// child: Row(
|
|
||||||
// children: <Widget>[
|
|
||||||
// Expanded(
|
|
||||||
// child: Container(
|
|
||||||
// child: Column(
|
|
||||||
// children: [
|
|
||||||
// Image.asset(
|
|
||||||
// 'images/clockin_presensi.png', // Path gambar untuk "Clock In"
|
|
||||||
// width: Constant.getActualXPhone(context: context, x: 22),
|
|
||||||
// height: Constant.getActualYPhone(context: context, y: 22),
|
|
||||||
// ),
|
|
||||||
// SizedBox(
|
|
||||||
// height: Constant.getActualYPhone(context: context, y: 8),
|
|
||||||
// ),
|
|
||||||
// Text(
|
|
||||||
// '--:--',
|
|
||||||
// style: Constant.titlePresensiH2_700(context: context)
|
|
||||||
// .copyWith(
|
|
||||||
// color: Constant.textTrueBlack,
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
// Text(
|
|
||||||
// 'Clock In',
|
|
||||||
// style: Constant.titleH2_700(context: context).copyWith(
|
|
||||||
// color: Constant.textTrueBlack,
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
// ],
|
|
||||||
// ),
|
|
||||||
// )),
|
|
||||||
// Expanded(
|
|
||||||
// child: Container(
|
|
||||||
// child: Column(
|
|
||||||
// children: [
|
|
||||||
// Image.asset(
|
|
||||||
// 'images/clockout_presensi.png', // Path gambar untuk "Check In"
|
|
||||||
// width: Constant.getActualXPhone(context: context, x: 22),
|
|
||||||
// height: Constant.getActualYPhone(context: context, y: 22),
|
|
||||||
// ),
|
|
||||||
// SizedBox(
|
|
||||||
// height: Constant.getActualYPhone(context: context, y: 8),
|
|
||||||
// ),
|
|
||||||
// Text(
|
|
||||||
// '--:--',
|
|
||||||
// style: Constant.titlePresensiH2_700(context: context)
|
|
||||||
// .copyWith(
|
|
||||||
// color: Constant.textTrueBlack,
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
// Text(
|
|
||||||
// 'Clock Out',
|
|
||||||
// style: Constant.titleH2_700(context: context).copyWith(
|
|
||||||
// color: Constant.textTrueBlack,
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
// ],
|
|
||||||
// ),
|
|
||||||
// )),
|
|
||||||
// ],
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
183
lib/widget/custom_drawer.dart
Normal file
183
lib/widget/custom_drawer.dart
Normal file
@@ -0,0 +1,183 @@
|
|||||||
|
import 'dart:async';
|
||||||
|
import 'dart:convert';
|
||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||||
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
|
|
||||||
|
import '../app/constant.dart';
|
||||||
|
import '../app/route.dart';
|
||||||
|
import '../provider/current_menu_provider.dart';
|
||||||
|
import '../provider/current_user_provider.dart';
|
||||||
|
import '../screen/login/logout_provider.dart';
|
||||||
|
|
||||||
|
class CustomDrawer extends HookConsumerWidget {
|
||||||
|
// final String userCompany;
|
||||||
|
const CustomDrawer({
|
||||||
|
Key? key,
|
||||||
|
// required this.userCompany,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
|
final selectedUser = ref.read(currentUserProvider);
|
||||||
|
final isLoading = useState(false);
|
||||||
|
final errorMessage = useState("");
|
||||||
|
final successMessage = useState("");
|
||||||
|
final M_CompanyName = useState("-");
|
||||||
|
|
||||||
|
// useEffect(() {
|
||||||
|
// WidgetsBinding.instance.addPostFrameCallback((timeStamp) async {
|
||||||
|
// final staffID = ref.read(currentUserProvider)?.model.staffId ?? "0";
|
||||||
|
// if (staffID == "0") {
|
||||||
|
// //not login
|
||||||
|
// Navigator.of(context)
|
||||||
|
// .pushNamedAndRemoveUntil(loginRoute, (route) => true);
|
||||||
|
|
||||||
|
// // Navigator.popAndPushNamed(context, loginRoute);
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
// return () {};
|
||||||
|
// }, []);
|
||||||
|
|
||||||
|
ref.listen(logoutProvider, (prev, next) async {
|
||||||
|
if (next is LogoutStateLoading) {
|
||||||
|
isLoading.value = true;
|
||||||
|
} else if (next is LogoutStateError) {
|
||||||
|
isLoading.value = false;
|
||||||
|
errorMessage.value = next.message;
|
||||||
|
Timer(const Duration(seconds: 3), () {
|
||||||
|
errorMessage.value = "";
|
||||||
|
});
|
||||||
|
} else if (next is LogoutStateDone) {
|
||||||
|
isLoading.value = false;
|
||||||
|
final shared = await SharedPreferences.getInstance();
|
||||||
|
final bearerString = shared.get(Constant.bearerName).toString();
|
||||||
|
// print(bearerString);
|
||||||
|
if (bearerString.isNotEmpty) {
|
||||||
|
shared.remove(bearerString);
|
||||||
|
shared.clear();
|
||||||
|
// Navigator.popAndPushNamed(context, loginRoute);
|
||||||
|
Navigator.of(context)
|
||||||
|
.pushNamedAndRemoveUntil(loginRoute, (route) => false);
|
||||||
|
}
|
||||||
|
Timer(const Duration(seconds: 3), () async {
|
||||||
|
successMessage.value = "";
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
final currentMenu = ref.read(currentPageProvider);
|
||||||
|
|
||||||
|
return Container(
|
||||||
|
width: Constant.getActualXPhone(context: context, x: 300),
|
||||||
|
height: Constant.getActualYPhone(context: context, y: 844),
|
||||||
|
child: Drawer(
|
||||||
|
elevation: 0,
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.all(Radius.circular(0))),
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: ListView(
|
||||||
|
children: [
|
||||||
|
// Container(
|
||||||
|
// child: Image(
|
||||||
|
// image:
|
||||||
|
// AssetImage('images/logo_sismedika_landscape.png')),
|
||||||
|
// ),
|
||||||
|
|
||||||
|
SizedBox(
|
||||||
|
height: Constant.getActualYPhone(context: context, y: 8),
|
||||||
|
),
|
||||||
|
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsets.only(
|
||||||
|
top: Constant.getActualYPhone(context: context, y: 10),
|
||||||
|
bottom: Constant.getActualYPhone(context: context, y: 10),
|
||||||
|
right: Constant.getActualXPhone(context: context, x: 24),
|
||||||
|
left: Constant.getActualXPhone(context: context, x: 24),
|
||||||
|
),
|
||||||
|
child: Container(
|
||||||
|
width: Constant.getActualXPhone(context: context, x: 300),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Chip(
|
||||||
|
backgroundColor: Constant.textLightGrey.withOpacity(0.16),
|
||||||
|
label: Text(
|
||||||
|
M_CompanyName.value,
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
style: TextStyle(
|
||||||
|
color: Constant.textLightGrey,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
|
ListTile(
|
||||||
|
leading: Icon(
|
||||||
|
Icons.home,
|
||||||
|
color: (currentMenu == 0)
|
||||||
|
? Constant.textOrange
|
||||||
|
: Constant.textLightGrey,
|
||||||
|
),
|
||||||
|
title: Text(
|
||||||
|
'Home',
|
||||||
|
style: TextStyle(
|
||||||
|
color: (currentMenu == 0)
|
||||||
|
? Constant.textOrange
|
||||||
|
: Constant.textLightGrey,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
onTap: () {
|
||||||
|
// Handle navigation to Home screen
|
||||||
|
Navigator.pop(context);
|
||||||
|
ref.read(currentPageProvider.state).update((state) => 0);
|
||||||
|
Navigator.pushNamed(context, homeRoute);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
|
||||||
|
ListTile(
|
||||||
|
leading: Icon(
|
||||||
|
Icons.logout,
|
||||||
|
color: Constant.textLightGrey,
|
||||||
|
),
|
||||||
|
title: Text(
|
||||||
|
'Logout',
|
||||||
|
style: TextStyle(color: Constant.textLightGrey),
|
||||||
|
),
|
||||||
|
onTap: () {
|
||||||
|
// di set ke 0 lagi
|
||||||
|
ref.read(currentPageProvider.state).update((state) => 0);
|
||||||
|
// ref.read(logoutProvider.notifier).logout(
|
||||||
|
// M_UserID: selectedUser?.model.M_UserID ?? "",
|
||||||
|
// M_UserUsername:
|
||||||
|
// selectedUser?.model.M_UserUsername ?? "",
|
||||||
|
// );
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
// Versi Aplikasi
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsets.only(
|
||||||
|
right: Constant.getActualXPhone(context: context, x: 20),
|
||||||
|
bottom: Constant.getActualYPhone(context: context, y: 10),
|
||||||
|
),
|
||||||
|
child: Align(
|
||||||
|
alignment: Alignment.bottomRight,
|
||||||
|
child: Text(
|
||||||
|
'Versi ${Constant.version}',
|
||||||
|
style: Constant.titleH1_700(context: context)
|
||||||
|
.copyWith(color: Constant.textLightGrey),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -16,7 +16,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
|
|||||||
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
|
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
|
||||||
# In Windows, build-name is used as the major, minor, and patch parts
|
# In Windows, build-name is used as the major, minor, and patch parts
|
||||||
# of the product and file versions while build-number is used as the build suffix.
|
# of the product and file versions while build-number is used as the build suffix.
|
||||||
version: 1.0.0+1
|
version: 1.0.1
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
sdk: '>=3.0.6 <4.0.0'
|
sdk: '>=3.0.6 <4.0.0'
|
||||||
|
|||||||
Reference in New Issue
Block a user