package com.example.barokahstore.ui.screens import androidx.compose.foundation.background import androidx.compose.foundation.border import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.* import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.ArrowDropDown import androidx.compose.material3.* import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import com.example.barokahstore.data.Attendance import com.example.barokahstore.data.DatabaseHelper import com.example.barokahstore.data.User import java.text.SimpleDateFormat import java.util.Calendar import java.util.Date import java.util.Locale @OptIn(ExperimentalMaterial3Api::class) @Composable fun AbsensiScreen( dbHelper: DatabaseHelper, currentUser: User ) { val isAdmin = currentUser.role == "admin" var attendanceRecords by remember { mutableStateOf(listOf()) } var allUsers by remember { mutableStateOf(listOf()) } var selectedUserFilter by remember { mutableStateOf(null) } // null means "Semua Staff" var showUserDropdown by remember { mutableStateOf(false) } fun refreshAttendance() { attendanceRecords = dbHelper.getAllAttendanceRecords() allUsers = dbHelper.getAllUsers() } LaunchedEffect(Unit) { refreshAttendance() } // Helper functions for work duration val calculateWorkDuration = { checkInStr: String, checkOutStr: String? -> if (checkOutStr == null) { "Sedang Bekerja" } else { val sdf = SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault()) try { val checkInDate = sdf.parse(checkInStr) val checkOutDate = sdf.parse(checkOutStr) if (checkInDate != null && checkOutDate != null) { val diffMs = checkOutDate.time - checkInDate.time val diffSecs = diffMs / 1000 val hours = diffSecs / 3600 val minutes = (diffSecs % 3600) / 60 if (hours > 0) { "${hours}j ${minutes}m" } else { "${minutes}m" } } else { "-" } } catch (e: Exception) { "-" } } } val calculateWorkDurationHours = { checkInStr: String, checkOutStr: String? -> if (checkOutStr == null) { 0.0 } else { val sdf = SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault()) try { val checkInDate = sdf.parse(checkInStr) val checkOutDate = sdf.parse(checkOutStr) if (checkInDate != null && checkOutDate != null) { val diffMs = checkOutDate.time - checkInDate.time diffMs.toDouble() / (1000 * 3600) } else { 0.0 } } catch (e: Exception) { 0.0 } } } val activeRecapUser = if (isAdmin) selectedUserFilter else currentUser Column( modifier = Modifier .fillMaxSize() .padding(16.dp), verticalArrangement = Arrangement.spacedBy(16.dp) ) { // User Filter Selector (Only for Admin) if (isAdmin) { Box(modifier = Modifier.fillMaxWidth()) { OutlinedButton( onClick = { showUserDropdown = true }, modifier = Modifier.fillMaxWidth(), shape = RoundedCornerShape(12.dp) ) { Row( modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween, verticalAlignment = Alignment.CenterVertically ) { Text( text = "Sortir User: ${activeRecapUser?.name ?: "Semua Staff"}", fontWeight = FontWeight.Bold, color = Color(0xFF1F2937) ) Icon(Icons.Default.ArrowDropDown, contentDescription = null, tint = Color.Gray) } } DropdownMenu( expanded = showUserDropdown, onDismissRequest = { showUserDropdown = false }, modifier = Modifier.fillMaxWidth(0.9f) ) { DropdownMenuItem( text = { Text("Semua Staff", fontWeight = FontWeight.Bold) }, onClick = { selectedUserFilter = null showUserDropdown = false } ) allUsers.forEach { user -> DropdownMenuItem( text = { Text(user.name) }, onClick = { selectedUserFilter = user showUserDropdown = false } ) } } } } // Calculations based on filtered logs val filteredRecords = remember(attendanceRecords, activeRecapUser) { if (activeRecapUser == null) { attendanceRecords } else { attendanceRecords.filter { it.userId == activeRecapUser.id } } } val totalPresent = filteredRecords.count { it.status == "present" || it.status == "late" } val totalLate = filteredRecords.count { it.status == "late" } val totalHours = filteredRecords.sumOf { calculateWorkDurationHours(it.checkIn, it.checkOut) } // Summary Metrics Grid Row( modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.spacedBy(12.dp) ) { // Presence Card Card( modifier = Modifier.weight(1f), shape = RoundedCornerShape(12.dp), colors = CardDefaults.cardColors(containerColor = Color(0xFFE0E7FF)) ) { Column(modifier = Modifier.padding(12.dp), horizontalAlignment = Alignment.CenterHorizontally) { Text("Total Hadir", fontSize = 11.sp, color = Color.Gray, fontWeight = FontWeight.Medium) Text("$totalPresent Hari", fontSize = 16.sp, fontWeight = FontWeight.Bold, color = Color(0xFF4F46E5)) } } // Late Card Card( modifier = Modifier.weight(1f), shape = RoundedCornerShape(12.dp), colors = CardDefaults.cardColors(containerColor = Color(0xFFFEF3C7)) ) { Column(modifier = Modifier.padding(12.dp), horizontalAlignment = Alignment.CenterHorizontally) { Text("Terlambat", fontSize = 11.sp, color = Color.Gray, fontWeight = FontWeight.Medium) Text("$totalLate Kali", fontSize = 16.sp, fontWeight = FontWeight.Bold, color = Color(0xFFD97706)) } } // Hours Worked Card Card( modifier = Modifier.weight(1.2f), shape = RoundedCornerShape(12.dp), colors = CardDefaults.cardColors(containerColor = Color(0xFFD1FAE5)) ) { Column(modifier = Modifier.padding(12.dp), horizontalAlignment = Alignment.CenterHorizontally) { Text("Jam Kerja", fontSize = 11.sp, color = Color.Gray, fontWeight = FontWeight.Medium) Text(String.format(Locale.getDefault(), "%.1f Jam", totalHours), fontSize = 16.sp, fontWeight = FontWeight.Bold, color = Color(0xFF059669)) } } } // List of detail recap logs Text( text = "Detil Durasi Bekerja", fontSize = 15.sp, fontWeight = FontWeight.Bold, color = Color(0xFF1F2937) ) Card( modifier = Modifier .fillMaxWidth() .weight(1f), shape = RoundedCornerShape(16.dp), colors = CardDefaults.cardColors(containerColor = Color.White), elevation = CardDefaults.cardElevation(defaultElevation = 2.dp) ) { if (filteredRecords.isEmpty()) { Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) { Text("Tidak ada data rekap", color = Color.Gray, fontSize = 13.sp) } } else { LazyColumn(modifier = Modifier.padding(16.dp)) { items(filteredRecords) { record -> Row( modifier = Modifier .fillMaxWidth() .padding(vertical = 6.dp) .border(0.5.dp, Color(0xFFE5E7EB), RoundedCornerShape(10.dp)) .padding(12.dp), horizontalArrangement = Arrangement.SpaceBetween, verticalAlignment = Alignment.CenterVertically ) { Column(modifier = Modifier.weight(1f)) { Text(record.userName, fontWeight = FontWeight.Bold, fontSize = 13.sp) Text("Tanggal: ${record.date}", fontSize = 11.sp, color = Color.Gray) Text("In: ${record.checkIn.substringAfter(" ")} • Out: ${record.checkOut?.substringAfter(" ") ?: "--:--:--"}", fontSize = 11.sp, color = Color.Gray) } Column(horizontalAlignment = Alignment.End) { Text( text = calculateWorkDuration(record.checkIn, record.checkOut), fontWeight = FontWeight.ExtraBold, fontSize = 13.sp, color = if (record.checkOut == null) Color.Red else Color(0xFF059669) ) Text( text = record.status.uppercase(), fontSize = 9.sp, fontWeight = FontWeight.Bold, color = if (record.status == "present") Color(0xFF059669) else Color(0xFFD97706) ) } } } } } } } }