From 945f9920fd6e060bb9c87614e0822415bf89d3d9 Mon Sep 17 00:00:00 2001 From: sathwikcs <85106054+sathwikcs@users.noreply.github.com> Date: Tue, 4 Feb 2025 12:00:42 +0530 Subject: [PATCH] homeVM --- .../screens/home/viewModel/homeVM.kt | 176 ++++++++++-------- 1 file changed, 101 insertions(+), 75 deletions(-) diff --git a/app/src/main/java/in/sminnovations/attendanceapp/screens/home/viewModel/homeVM.kt b/app/src/main/java/in/sminnovations/attendanceapp/screens/home/viewModel/homeVM.kt index fc2f388..d5a8a44 100644 --- a/app/src/main/java/in/sminnovations/attendanceapp/screens/home/viewModel/homeVM.kt +++ b/app/src/main/java/in/sminnovations/attendanceapp/screens/home/viewModel/homeVM.kt @@ -9,10 +9,11 @@ import com.google.firebase.Timestamp import com.google.firebase.firestore.DocumentSnapshot import com.google.firebase.firestore.FirebaseFirestore import dagger.hilt.android.lifecycle.HiltViewModel -import `in`.sminnovations.attendanceapp.main.AppUpdater -import `in`.sminnovations.attendanceapp.main.NetworkMonitor -import `in`.sminnovations.attendanceapp.main.UpdateChecker -import `in`.sminnovations.attendanceapp.main.UpdateInfo +import `in`.sminnovations.attendanceapp.utils.AppUpdater +import `in`.sminnovations.attendanceapp.utils.NetworkMonitor +import `in`.sminnovations.attendanceapp.utils.UpdateInfo +import `in`.sminnovations.attendanceapp.screens.home.data.AttendanceUiState +import `in`.sminnovations.attendanceapp.utils.UpdateChecker import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow @@ -27,7 +28,6 @@ import java.time.format.DateTimeFormatter import java.time.temporal.ChronoUnit import java.util.Date import java.util.Locale -import java.util.concurrent.TimeUnit import javax.inject.Inject import kotlin.math.abs @@ -154,19 +154,17 @@ class HomeViewModel @Inject constructor( processQRCode(value) } } - - private fun processQRCode(userId: String) { + private fun processQRCode(userId: String) { if (userId.isBlank()) return viewModelScope.launch { try { setLoading(true) _uiState.update { - it.copy( - errorMessage = null, userName = null // Reset userName before processing - ) + it.copy(errorMessage = null, userName = null) // Reset UI state } + // Fetch Employee Document val employeeDoc = getEmployeeDocument(userId) if (employeeDoc == null) { handleError("Invalid employee ID") @@ -174,7 +172,6 @@ class HomeViewModel @Inject constructor( } if (!employeeDoc.getBoolean("EmployeeStatus")!!) { - // Set userName only for expired ID case _uiState.update { it.copy( userName = employeeDoc.getString("Name"), @@ -186,17 +183,17 @@ class HomeViewModel @Inject constructor( _uiState.update { it.copy(userName = employeeDoc.getString("Name")) } + // Fetch Attendance Document val currentDate = getCurrentFormattedDate() val attendanceDoc = getAttendanceDocument(userId, currentDate) if (attendanceDoc?.exists() == true) { - val checkIn = attendanceDoc.getString("checkIn") - if (isTimeDifferenceGreaterThanMinutes(givenTimeStr = checkIn!!, minutes = 5L)) { - handleExistingAttendance(attendanceDoc) - }else{ + val checkIn = attendanceDoc.getString("checkIn1") // Using first check-in for time validation + if (checkIn != null && !isTimeDifferenceGreaterThanMinutes(givenTimeStr = checkIn, minutes = 0L)) { handleError("Wait 5 minutes before logging off") + return@launch } - + handleExistingAttendance(attendanceDoc) } else { handleNewAttendance(userId, currentDate) } @@ -209,6 +206,7 @@ class HomeViewModel @Inject constructor( } } + private fun handleError(message: String) { viewModelScope.launch { _uiState.update { @@ -221,64 +219,6 @@ class HomeViewModel @Inject constructor( } } - private suspend fun handleExistingAttendance(document: DocumentSnapshot) { - val checkOut = document.getString("checkOut") - - when { - checkOut == "NA" -> processCheckOut(document) - checkOut != null -> { - _uiState.update { - it.copy( - checkedOutTime = checkOut, errorMessage = "Already checked out for today." - ) - } - } - - else -> handleError("Invalid attendance record") - } - - } - - private suspend fun handleNewAttendance(userId: String, currentDate: String) { - try { - val checkInData = hashMapOf( - "DayCompleted" to false, - "checkIn" to formatTimestamp(Timestamp.now()), - "checkOut" to "NA" - ) - - firebaseFirestore.collection("attendance_$userId").document(currentDate) - .set(checkInData).await() - - _uiState.update { - it.copy( - isCheckedIn = true, qrCodeValue = null - ) - } - } catch (e: Exception) { - handleError("Failed to check in: ${e.message}") - } - } - - private suspend fun processCheckOut(document: DocumentSnapshot) { - - try { - val checkOutData = hashMapOf( - "checkOut" to formatTimestamp(Timestamp.now()), "DayCompleted" to true - ) - - document.reference.update(checkOutData as Map).await() - - _uiState.update { - it.copy( - isCheckedOut = true, qrCodeValue = null - ) - } - } catch (e: Exception) { - handleError("Failed to check out: ${e.message}") - } - - } private suspend fun getEmployeeDocument(userId: String): DocumentSnapshot? { return try { @@ -322,8 +262,40 @@ class HomeViewModel @Inject constructor( // println(a) // return true // } +// fun processAttendance(userId: String) { +// if (userId.isBlank()) return +// +// viewModelScope.launch { +// try { +// val currentDate = getCurrentFormattedDate() +// val attendanceDoc = getAttendanceDocument(userId, currentDate) +// +// if (attendanceDoc?.exists() == true) { +// handleExistingAttendance(attendanceDoc) +// } else { +// handleNewAttendance(userId, currentDate) +// } +// } catch (e: Exception) { +// handleError("Error: ${e.message}") +// } +// } +// } - fun isTimeDifferenceGreaterThanMinutes(givenTimeStr: String, currentTimeStr: String = formatTimestamp(Timestamp.now()), minutes: Long): Boolean { + + + private suspend fun handleExistingAttendance(document: DocumentSnapshot) { + val data = document.data ?: return + val checkIns = data.filterKeys { it.startsWith("checkIn") }.size + val checkOuts = data.filterKeys { it.startsWith("checkOut") }.size + + if (checkIns > checkOuts) { + processCheckOut(document, checkIns) + } else { + processCheckIn(document, checkIns + 1) + } + } + + private fun isTimeDifferenceGreaterThanMinutes(givenTimeStr: String, currentTimeStr: String = formatTimestamp(Timestamp.now()), minutes: Long): Boolean { val formatter = DateTimeFormatter.ofPattern("dd MMMM yyyy hh:mm:ss a") val givenTime = LocalDateTime.parse(givenTimeStr, formatter) @@ -334,7 +306,61 @@ class HomeViewModel @Inject constructor( return timeDifference > minutes } + private suspend fun handleNewAttendance(userId: String, currentDate: String) { + try { + val checkInData = hashMapOf( + "DayCompleted" to false, + "checkIn1" to formatTimestamp(Timestamp.now()), + "totalWork" to "00:00:00" + ) + firebaseFirestore.collection("attendance_$userId").document(currentDate) + .set(checkInData).await() + } catch (e: Exception) { + handleError("Failed to check in: ${e.message}") + } + } + + + private suspend fun processCheckIn(document: DocumentSnapshot, checkInCount: Int) { + try { + document.reference.update("checkIn$checkInCount", formatTimestamp(Timestamp.now())).await() + } catch (e: Exception) { + handleError("Failed to check in: ${e.message}") + } + } + + private suspend fun processCheckOut(document: DocumentSnapshot, checkInCount: Int) { + try { + val checkOutTime = formatTimestamp(Timestamp.now()) + document.reference.update("checkOut$checkInCount", checkOutTime).await() + + val updatedDocument = document.reference.get().await() + val totalWork = calculateTotalWork(updatedDocument) + document.reference.update("totalWork", totalWork).await() + + } catch (e: Exception) { + handleError("Failed to check out: ${e.message}") + } + } + + private fun calculateTotalWork(document: DocumentSnapshot): String { + val formatter = DateTimeFormatter.ofPattern("dd MMMM yyyy hh:mm:ss a", Locale.getDefault()) + var totalMinutes = 0L + + for (i in 1..10) { + val checkIn = document.getString("checkIn$i") ?: break + val checkOut = document.getString("checkOut$i") ?: continue + + val checkInTime = LocalDateTime.parse(checkIn, formatter) + val checkOutTime = LocalDateTime.parse(checkOut, formatter) + totalMinutes += ChronoUnit.MINUTES.between(checkInTime, checkOutTime) + } + + val hours = totalMinutes / 60 + val minutes = totalMinutes % 60 + return String.format("%02d:%02d:00", hours, minutes) + } override fun onCleared() {