step 11 : proses clock in, clock out

This commit is contained in:
sindhu
2024-01-26 15:10:36 +07:00
parent 1af974881a
commit c551ee2cdb
16 changed files with 1590 additions and 712 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

View File

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

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

View 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);

View File

@@ -0,0 +1,3 @@
import 'package:flutter_riverpod/flutter_riverpod.dart';
final currentPageProvider = StateProvider<int?>((ref) => null);

View File

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

View File

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

View File

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

View File

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

View 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),
);

View 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),
);

View 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),
);

View File

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

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

View File

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