homeVM
This commit is contained in:
@@ -9,10 +9,11 @@ import com.google.firebase.Timestamp
|
|||||||
import com.google.firebase.firestore.DocumentSnapshot
|
import com.google.firebase.firestore.DocumentSnapshot
|
||||||
import com.google.firebase.firestore.FirebaseFirestore
|
import com.google.firebase.firestore.FirebaseFirestore
|
||||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||||
import `in`.sminnovations.attendanceapp.main.AppUpdater
|
import `in`.sminnovations.attendanceapp.utils.AppUpdater
|
||||||
import `in`.sminnovations.attendanceapp.main.NetworkMonitor
|
import `in`.sminnovations.attendanceapp.utils.NetworkMonitor
|
||||||
import `in`.sminnovations.attendanceapp.main.UpdateChecker
|
import `in`.sminnovations.attendanceapp.utils.UpdateInfo
|
||||||
import `in`.sminnovations.attendanceapp.main.UpdateInfo
|
import `in`.sminnovations.attendanceapp.screens.home.data.AttendanceUiState
|
||||||
|
import `in`.sminnovations.attendanceapp.utils.UpdateChecker
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
import kotlinx.coroutines.flow.asStateFlow
|
import kotlinx.coroutines.flow.asStateFlow
|
||||||
@@ -27,7 +28,6 @@ import java.time.format.DateTimeFormatter
|
|||||||
import java.time.temporal.ChronoUnit
|
import java.time.temporal.ChronoUnit
|
||||||
import java.util.Date
|
import java.util.Date
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
import java.util.concurrent.TimeUnit
|
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import kotlin.math.abs
|
import kotlin.math.abs
|
||||||
|
|
||||||
@@ -154,7 +154,6 @@ class HomeViewModel @Inject constructor(
|
|||||||
processQRCode(value)
|
processQRCode(value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun processQRCode(userId: String) {
|
private fun processQRCode(userId: String) {
|
||||||
if (userId.isBlank()) return
|
if (userId.isBlank()) return
|
||||||
|
|
||||||
@@ -162,11 +161,10 @@ class HomeViewModel @Inject constructor(
|
|||||||
try {
|
try {
|
||||||
setLoading(true)
|
setLoading(true)
|
||||||
_uiState.update {
|
_uiState.update {
|
||||||
it.copy(
|
it.copy(errorMessage = null, userName = null) // Reset UI state
|
||||||
errorMessage = null, userName = null // Reset userName before processing
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Fetch Employee Document
|
||||||
val employeeDoc = getEmployeeDocument(userId)
|
val employeeDoc = getEmployeeDocument(userId)
|
||||||
if (employeeDoc == null) {
|
if (employeeDoc == null) {
|
||||||
handleError("Invalid employee ID")
|
handleError("Invalid employee ID")
|
||||||
@@ -174,7 +172,6 @@ class HomeViewModel @Inject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!employeeDoc.getBoolean("EmployeeStatus")!!) {
|
if (!employeeDoc.getBoolean("EmployeeStatus")!!) {
|
||||||
// Set userName only for expired ID case
|
|
||||||
_uiState.update {
|
_uiState.update {
|
||||||
it.copy(
|
it.copy(
|
||||||
userName = employeeDoc.getString("Name"),
|
userName = employeeDoc.getString("Name"),
|
||||||
@@ -186,17 +183,17 @@ class HomeViewModel @Inject constructor(
|
|||||||
|
|
||||||
_uiState.update { it.copy(userName = employeeDoc.getString("Name")) }
|
_uiState.update { it.copy(userName = employeeDoc.getString("Name")) }
|
||||||
|
|
||||||
|
// Fetch Attendance Document
|
||||||
val currentDate = getCurrentFormattedDate()
|
val currentDate = getCurrentFormattedDate()
|
||||||
val attendanceDoc = getAttendanceDocument(userId, currentDate)
|
val attendanceDoc = getAttendanceDocument(userId, currentDate)
|
||||||
|
|
||||||
if (attendanceDoc?.exists() == true) {
|
if (attendanceDoc?.exists() == true) {
|
||||||
val checkIn = attendanceDoc.getString("checkIn")
|
val checkIn = attendanceDoc.getString("checkIn1") // Using first check-in for time validation
|
||||||
if (isTimeDifferenceGreaterThanMinutes(givenTimeStr = checkIn!!, minutes = 5L)) {
|
if (checkIn != null && !isTimeDifferenceGreaterThanMinutes(givenTimeStr = checkIn, minutes = 0L)) {
|
||||||
handleExistingAttendance(attendanceDoc)
|
|
||||||
}else{
|
|
||||||
handleError("Wait 5 minutes before logging off")
|
handleError("Wait 5 minutes before logging off")
|
||||||
|
return@launch
|
||||||
}
|
}
|
||||||
|
handleExistingAttendance(attendanceDoc)
|
||||||
} else {
|
} else {
|
||||||
handleNewAttendance(userId, currentDate)
|
handleNewAttendance(userId, currentDate)
|
||||||
}
|
}
|
||||||
@@ -209,6 +206,7 @@ class HomeViewModel @Inject constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private fun handleError(message: String) {
|
private fun handleError(message: String) {
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
_uiState.update {
|
_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<String, Any>).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? {
|
private suspend fun getEmployeeDocument(userId: String): DocumentSnapshot? {
|
||||||
return try {
|
return try {
|
||||||
@@ -322,8 +262,40 @@ class HomeViewModel @Inject constructor(
|
|||||||
// println(a)
|
// println(a)
|
||||||
// return true
|
// 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 formatter = DateTimeFormatter.ofPattern("dd MMMM yyyy hh:mm:ss a")
|
||||||
|
|
||||||
val givenTime = LocalDateTime.parse(givenTimeStr, formatter)
|
val givenTime = LocalDateTime.parse(givenTimeStr, formatter)
|
||||||
@@ -334,7 +306,61 @@ class HomeViewModel @Inject constructor(
|
|||||||
return timeDifference > minutes
|
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() {
|
override fun onCleared() {
|
||||||
|
|||||||
Reference in New Issue
Block a user