fixed so many issues regarding the qr state and check in checkout added date remember state and optimised code

This commit is contained in:
sathwikcs
2024-10-22 17:01:35 +05:30
parent 527de78877
commit 3f0f10e2c6

View File

@@ -7,17 +7,14 @@ import androidx.lifecycle.viewModelScope
import com.google.firebase.Timestamp import com.google.firebase.Timestamp
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.data.dataStore.EmployeeRepository
import `in`.sminnovations.attendanceapp.screens.home.data.CheckInCheckOutDataStore import `in`.sminnovations.attendanceapp.screens.home.data.CheckInCheckOutDataStore
import `in`.sminnovations.attendanceapp.screens.login.data.LoginDataStore import `in`.sminnovations.attendanceapp.screens.login.data.LoginDataStore
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
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import java.text.Format
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.time.LocalDate import java.time.LocalDate
import java.time.LocalTime
import java.util.Date import java.util.Date
import java.util.Locale import java.util.Locale
import javax.inject.Inject import javax.inject.Inject
@@ -27,7 +24,6 @@ class HomeViewModel @Inject constructor(
private val loginDataStore: LoginDataStore, private val loginDataStore: LoginDataStore,
private val checkInCheckOutDataStore: CheckInCheckOutDataStore, private val checkInCheckOutDataStore: CheckInCheckOutDataStore,
private val firebaseFirestore: FirebaseFirestore, private val firebaseFirestore: FirebaseFirestore,
private val employeeRepository: EmployeeRepository
) : ViewModel() { ) : ViewModel() {
private val _qrCodeValue = MutableStateFlow<String?>(null) private val _qrCodeValue = MutableStateFlow<String?>(null)
@@ -36,20 +32,29 @@ class HomeViewModel @Inject constructor(
private val _isScanning = MutableStateFlow(false) private val _isScanning = MutableStateFlow(false)
val isScanning: StateFlow<Boolean> = _isScanning.asStateFlow() val isScanning: StateFlow<Boolean> = _isScanning.asStateFlow()
private val _checkedIn = MutableStateFlow<String>("") private val _checkedIn = MutableStateFlow("")
val checkedIn : StateFlow<String> = _checkedIn.asStateFlow() val checkedIn: StateFlow<String> = _checkedIn.asStateFlow()
private val _checkedOut = MutableStateFlow<String>("N /A ") private val _checkedOut = MutableStateFlow("N/A")
val checkedOut : StateFlow<String> = _checkedOut.asStateFlow() val checkedOut: StateFlow<String> = _checkedOut.asStateFlow()
private val _isCheckedIn = MutableStateFlow(false)
val isCheckedIn: StateFlow<Boolean> = _isCheckedIn.asStateFlow()
private val _isCheckedIn = MutableStateFlow<Boolean>(false) private val _isCheckedOut = MutableStateFlow(false)
val isCheckedIn : StateFlow<Boolean> = _isCheckedIn.asStateFlow() val isCheckedOut: StateFlow<Boolean> = _isCheckedOut.asStateFlow()
private val _isCheckedOut = MutableStateFlow<Boolean>(false) private val _errorMessage = MutableStateFlow<String?>(null)
val isCheckedOut : StateFlow<Boolean> = _isCheckedOut.asStateFlow() val errorMessage: StateFlow<String?> = _errorMessage.asStateFlow()
private val _isLoading = MutableStateFlow(false)
val isLoading: StateFlow<Boolean> = _isLoading.asStateFlow()
private fun postErrorMessage(message: String) {
viewModelScope.launch {
_errorMessage.emit(message)
}
}
fun startScanning() { fun startScanning() {
_isScanning.value = true _isScanning.value = true
@@ -67,33 +72,43 @@ class HomeViewModel @Inject constructor(
} }
private fun formatTimestamp(timestamp: Timestamp): String { private fun formatTimestamp(timestamp: Timestamp): String {
val sdf = SimpleDateFormat("dd MMMM yyyy hh:mm:ss a", Locale.getDefault()) // Format with AM/PM val sdf =
SimpleDateFormat("dd MMMM yyyy hh:mm:ss a", Locale.getDefault()) // Format with AM/PM
return sdf.format(timestamp.toDate()) return sdf.format(timestamp.toDate())
} }
init { init {
viewModelScope.launch { viewModelScope.launch {
checkInCheckOutDataStore.checkInId.collect { checkIn -> getCheckInChekout()
checkInCheckOutDataStore.checkOutId.collect { checkOut ->
_checkedIn.value= checkIn
_checkedOut.value = checkOut
}
}
} }
} }
private fun getIsCheckInCheckOut(){ private fun getCheckInChekout() {
viewModelScope.launch { viewModelScope.launch {
checkInCheckOutDataStore.isCheckedIn.collect { isCheckIn -> checkInCheckOutDataStore.checkInId.collect { checkIn ->
checkInCheckOutDataStore.isCheckedOut.collect { isCheckOut -> _checkedIn.value = checkIn
_isCheckedIn.value = isCheckIn
_isCheckedOut.value = isCheckOut
}
} }
} }
viewModelScope.launch {
checkInCheckOutDataStore.checkOutId.collect { checkOut ->
_checkedOut.value = checkOut
}
}
viewModelScope.launch {
checkInCheckOutDataStore.checkInDate.collect {date ->
if (date == LocalDate.now().toString()) {
_isCheckedIn.value = true
}
}
}
} }
private fun getFormattedDate(): String { private fun getFormattedDate(): String {
val dateFormat = SimpleDateFormat("dd-MM-yyyy", Locale.getDefault()) val dateFormat = SimpleDateFormat("dd-MM-yyyy", Locale.getDefault())
return dateFormat.format(Date()) return dateFormat.format(Date())
@@ -101,29 +116,37 @@ class HomeViewModel @Inject constructor(
fun loginNow() { fun loginNow() {
viewModelScope.launch { viewModelScope.launch {
_isLoading.value = true
checkInCheckOutDataStore.checkInDate.collect { checkOutDate -> checkInCheckOutDataStore.checkInDate.collect { checkOutDate ->
loginDataStore.loginId.collect { _ -> loginDataStore.loginId.collect { _ ->
firebaseFirestore.collection("qr_key").whereEqualTo("id", getFormattedDate()) firebaseFirestore.collection("qr_key").whereEqualTo("id", getFormattedDate())
.get().addOnSuccessListener { querySnapshot -> .get().addOnSuccessListener { querySnapshot ->
_isLoading.value = false
if (!querySnapshot.isEmpty) { if (!querySnapshot.isEmpty) {
for (document in querySnapshot) { for (document in querySnapshot) {
if (qrCodeValue.value == document.getString("key")) { if (qrCodeValue.value == document.getString("key")) {
viewModelScope.launch { viewModelScope.launch {
if (checkOutDate != LocalDate.now().toString() || checkOutDate =="") { if (checkOutDate != LocalDate.now().toString() || checkOutDate == ""
) {
putCheckInAttendance("") putCheckInAttendance("")
} else { } else {
viewModelScope.launch {
_isCheckedIn.value = true
}
putCheckOutAttendance() putCheckOutAttendance()
} }
} }
} else { } else {
Log.d("loginNow", "Invalid QR code scanned") postErrorMessage("Invalid QR code scanned")
} }
} }
} else { } else {
Log.d("loginNow", "No matching QR key found for today's date") postErrorMessage("No matching QR key found for today's date")
} }
}.addOnFailureListener { exception -> }.addOnFailureListener { exception ->
Log.e("Firestore", "Error fetching QR key: ", exception) _isLoading.value = false
postErrorMessage("Error fetching QR key: ${exception.message}")
} }
} }
} }
@@ -133,101 +156,100 @@ class HomeViewModel @Inject constructor(
private fun putCheckInAttendance(location: String) { private fun putCheckInAttendance(location: String) {
viewModelScope.launch { viewModelScope.launch {
loginDataStore.loginId.collect { id -> _isLoading.value = true
val currentDate = SimpleDateFormat("dd-MM-yyyy", Locale.getDefault()).format(Date())
val attendanceRef = firebaseFirestore.collection("attendance_$id").document(currentDate)
attendanceRef.get().addOnSuccessListener { document ->
if (!document.exists()) {
val checkInData = hashMapOf(
"Status" to false,
"checkIn" to Timestamp.now(),
"location" to location
)
attendanceRef.set(checkInData).addOnSuccessListener {
// Save the check-in data to a local datastore if needed
viewModelScope.launch {
checkInCheckOutDataStore.saveLoginData(
formatTimestamp(Timestamp.now()),
"Not yet Done"
)
checkInCheckOutDataStore.saveLoginDate(LocalDate.now().toString())
checkInCheckOutDataStore.saveIsLogIn(true)
}
Log.d("Firestore", "Check-in successful")
_isCheckedIn.value = true
}.addOnFailureListener { e ->
Log.e("Firestore", "Error adding check-in", e)
}
} else {
// Document exists, check the checkOut field
val checkOut = document.getTimestamp("checkout")
if (checkOut == null) {
Log.d(
"Firestore",
"Check-in already exists for today. Cannot check in again."
)
} else {
Log.d("Firestore", "Attendance already completed for today.")
}
}
}.addOnFailureListener { exception ->
Log.e("Firestore", "Error fetching document: ", exception)
}
}
}
}
fun putCheckOutAttendance() {
viewModelScope.launch {
loginDataStore.loginId.collect { id -> loginDataStore.loginId.collect { id ->
val currentDate = SimpleDateFormat("dd-MM-yyyy", Locale.getDefault()).format(Date()) val currentDate = SimpleDateFormat("dd-MM-yyyy", Locale.getDefault()).format(Date())
val attendanceRef = val attendanceRef =
firebaseFirestore.collection("attendance_$id").document(currentDate) firebaseFirestore.collection("attendance_$id").document(currentDate)
attendanceRef.get().addOnSuccessListener { document -> attendanceRef.get().addOnSuccessListener { document ->
if (document.exists()) { _isLoading.value = false
if (!document.exists()) {
val checkInData = hashMapOf(
"Status" to false,
"checkIn" to formatTimestamp(Timestamp.now()),
"location" to location,
"checkOut" to "NA"
)
val checkIn = document.getTimestamp("checkIn") attendanceRef.set(checkInData).addOnSuccessListener {
val checkOut = document.getTimestamp("checkout") viewModelScope.launch {
checkInCheckOutDataStore.saveLoginDate(
if (checkIn != null && checkOut == null) { checkDate = LocalDate.now().toString(),
checkInTime = formatTimestamp(Timestamp.now())
val checkOutData = hashMapOf( )
"checkout" to Timestamp.now(), "Status" to true
) as Map<String, Any>
attendanceRef.update(checkOutData).addOnSuccessListener {
viewModelScope.launch {
checkInCheckOutDataStore.saveLoginData(checkedIn.value,formatTimestamp(Timestamp.now()))
checkInCheckOutDataStore.saveIsLogIn(false)
}
Log.d("Firestore", "Check-out successful")
}.addOnFailureListener { e ->
Log.e("Firestore", "Error adding check-out", e)
} }
} else if (checkOut != null) { Log.d("Firestore", "Check-in successful")
Log.d("Firestore", "Already checked out for today.") viewModelScope.launch {
} else { _isCheckedIn.value = true
Log.d("Firestore", "Cannot check out without checking in.") }
}.addOnFailureListener { e ->
postErrorMessage("Error adding check-in: ${e.message}")
} }
} else { } else {
Log.d( postErrorMessage("Check-in already exists for today. Cannot check in again.")
"Firestore", "No attendance found for today. Please check in first." viewModelScope.launch {
) _isCheckedIn.value = true
}
} }
}.addOnFailureListener { exception -> }.addOnFailureListener { exception ->
Log.e("Firestore", "Error fetching document: ", exception) _isLoading.value = false
postErrorMessage("Error fetching document: ${exception.message}")
} }
} }
} }
} }
private fun putCheckOutAttendance() {
viewModelScope.launch {
_isLoading.value = true
loginDataStore.loginId.collect { id ->
val currentDate = SimpleDateFormat("dd-MM-yyyy", Locale.getDefault()).format(Date())
val attendanceRef =
firebaseFirestore.collection("attendance_$id").document(currentDate)
attendanceRef.get().addOnSuccessListener { document ->
_isLoading.value = false
if (document.exists()) {
val checkIn = document.getString("checkIn")
val checkOut = document.getString("checkOut")
if (checkIn != null && checkOut == "NA") {
val checkOutData = hashMapOf(
"checkOut" to formatTimestamp(Timestamp.now()), "Status" to true
) as Map<String, Any>
attendanceRef.update(checkOutData).addOnSuccessListener {
viewModelScope.launch {
checkInCheckOutDataStore.saveLoginData(
checkOut = formatTimestamp(
Timestamp.now()
)
)
checkInCheckOutDataStore.saveIsLogIn(false)
}
Log.d("Firestore", "Check-out successful")
}.addOnFailureListener { e ->
postErrorMessage("Error adding check-out: ${e.message}")
}
} else if (checkOut != "NA") {
postErrorMessage("Already checked out for today.")
viewModelScope.launch {
_isCheckedOut.value = true
}
} else {
postErrorMessage("Cannot check out without checking in.")
}
} else {
postErrorMessage("No attendance found for today. Please check in first.")
}
}.addOnFailureListener { exception ->
_isLoading.value = false
postErrorMessage("Error fetching document: ${exception.message}")
}
}
}
}
} }