Ukrywaj wybrane salda w aplikacji kierowcy
This commit is contained in:
@@ -88,6 +88,13 @@ data class DriverAppSettingsDto(
|
||||
data class LeaveRequestsConfigDto(
|
||||
val enabled: Boolean = false,
|
||||
val types: List<String> = listOf("URLOP"),
|
||||
val usagePoolCodes: List<String> = listOf(
|
||||
"ANNUAL",
|
||||
"ANNUAL_DISABILITY",
|
||||
"FORCE_MAJEURE",
|
||||
"CHILD_CARE_14",
|
||||
"CARE_LEAVE",
|
||||
),
|
||||
)
|
||||
|
||||
data class DispatchSheetReminderDto(
|
||||
@@ -252,6 +259,13 @@ data class DriverLeaveSummaryDto(
|
||||
val dailyNormMinutes: Int = 480,
|
||||
val balanceConfigured: Boolean = false,
|
||||
val overdueQuantity: Int = 0,
|
||||
val visibleUsagePoolCodes: List<String> = listOf(
|
||||
"ANNUAL",
|
||||
"ANNUAL_DISABILITY",
|
||||
"FORCE_MAJEURE",
|
||||
"CHILD_CARE_14",
|
||||
"CARE_LEAVE",
|
||||
),
|
||||
val availableTypes: List<LeaveRequestTypeDto> = emptyList(),
|
||||
val reminders: List<DriverLeaveReminderDto> = emptyList(),
|
||||
)
|
||||
|
||||
@@ -1547,6 +1547,12 @@ private fun LeaveBalanceOverview(state: DriverUiState) {
|
||||
val summary = state.leaveSummary
|
||||
val totals = DriverLeaveRequestUiRules.annualTotals(summary)
|
||||
val norm = summary?.dailyNormMinutes ?: 480
|
||||
val showAnnualUsage = DriverLeaveRequestUiRules.isUsageVisible(summary, "ANNUAL")
|
||||
val otherPools = DriverLeaveRequestUiRules.otherEntitlementPools(summary)
|
||||
|
||||
if (summary != null && !showAnnualUsage && otherPools.isEmpty()) {
|
||||
return
|
||||
}
|
||||
|
||||
Card(
|
||||
colors = CardDefaults.cardColors(containerColor = TppTheme.colors.card),
|
||||
@@ -1555,99 +1561,107 @@ private fun LeaveBalanceOverview(state: DriverUiState) {
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
) {
|
||||
Column(Modifier.padding(18.dp), verticalArrangement = Arrangement.spacedBy(14.dp)) {
|
||||
Text("Twój urlop wypoczynkowy", color = TppTheme.colors.ink, fontWeight = FontWeight.Bold, fontSize = 20.sp)
|
||||
Text(
|
||||
if (showAnnualUsage) "Twój urlop wypoczynkowy" else "Twoje limity nieobecności",
|
||||
color = TppTheme.colors.ink,
|
||||
fontWeight = FontWeight.Bold,
|
||||
fontSize = 20.sp,
|
||||
)
|
||||
|
||||
when {
|
||||
summary == null -> {
|
||||
Text("Pobieramy aktualne saldo…", color = TppTheme.colors.muted)
|
||||
}
|
||||
!summary.balanceConfigured -> {
|
||||
Text(
|
||||
"Kadry przygotowują Twoje saldo",
|
||||
color = Color(0xFF7A5A00),
|
||||
fontWeight = FontWeight.Bold,
|
||||
)
|
||||
Text(
|
||||
"Możesz zapisać wniosek, ale jego godziny zostaną odjęte dopiero po potwierdzeniu puli urlopu.",
|
||||
color = TppTheme.colors.muted,
|
||||
)
|
||||
}
|
||||
else -> {
|
||||
Text("Pozostało do wykorzystania", color = TppTheme.colors.muted, fontWeight = FontWeight.SemiBold)
|
||||
Text(
|
||||
DriverLeaveRequestUiRules.formatQuantity(totals.availableMinutes, "minutes", norm),
|
||||
color = TppTheme.colors.forest,
|
||||
fontWeight = FontWeight.Bold,
|
||||
fontSize = 26.sp,
|
||||
)
|
||||
val denominator = (totals.grantedMinutes).coerceAtLeast(1)
|
||||
LinearProgressIndicator(
|
||||
progress = { (totals.usedMinutes.toFloat() / denominator).coerceIn(0f, 1f) },
|
||||
modifier = Modifier.fillMaxWidth().height(7.dp),
|
||||
color = TppTheme.colors.forest,
|
||||
trackColor = TppTheme.colors.successContainer,
|
||||
)
|
||||
Row(Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.spacedBy(10.dp)) {
|
||||
LeaveBalanceStat(
|
||||
title = "Wykorzystano",
|
||||
value = DriverLeaveRequestUiRules.formatQuantity(totals.usedMinutes, "minutes", norm),
|
||||
modifier = Modifier.weight(1f),
|
||||
)
|
||||
LeaveBalanceStat(
|
||||
title = "W przyszłych urlopach",
|
||||
value = DriverLeaveRequestUiRules.formatQuantity(totals.reservedMinutes, "minutes", norm),
|
||||
modifier = Modifier.weight(1f),
|
||||
)
|
||||
if (showAnnualUsage) {
|
||||
when {
|
||||
summary == null -> {
|
||||
Text("Pobieramy aktualne saldo…", color = TppTheme.colors.muted)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (totals.overdueMinutes > 0) {
|
||||
Row(
|
||||
Modifier
|
||||
.fillMaxWidth()
|
||||
.background(TppTheme.colors.warningContainer, RoundedCornerShape(6.dp))
|
||||
.border(1.dp, TppTheme.colors.warningOutline, RoundedCornerShape(6.dp))
|
||||
.padding(12.dp),
|
||||
horizontalArrangement = Arrangement.spacedBy(10.dp),
|
||||
verticalAlignment = Alignment.Top,
|
||||
) {
|
||||
Icon(Icons.Outlined.Info, contentDescription = null, tint = Color(0xFF7A5A00))
|
||||
Column(Modifier.weight(1f), verticalArrangement = Arrangement.spacedBy(3.dp)) {
|
||||
Text("Masz zaległy urlop", color = Color(0xFF7A5A00), fontWeight = FontWeight.Bold)
|
||||
!summary.balanceConfigured -> {
|
||||
Text(
|
||||
"${DriverLeaveRequestUiRules.formatQuantity(totals.overdueMinutes, "minutes", norm)} zaplanuj możliwie szybko, najpóźniej do 30 września. Saldo nie zniknie automatycznie.",
|
||||
"Kadry przygotowują Twoje saldo",
|
||||
color = Color(0xFF7A5A00),
|
||||
fontSize = 13.sp,
|
||||
fontWeight = FontWeight.Bold,
|
||||
)
|
||||
Text(
|
||||
"Możesz zapisać wniosek, ale jego godziny zostaną odjęte dopiero po potwierdzeniu puli urlopu.",
|
||||
color = TppTheme.colors.muted,
|
||||
)
|
||||
}
|
||||
else -> {
|
||||
Text("Pozostało do wykorzystania", color = TppTheme.colors.muted, fontWeight = FontWeight.SemiBold)
|
||||
Text(
|
||||
DriverLeaveRequestUiRules.formatQuantity(totals.availableMinutes, "minutes", norm),
|
||||
color = TppTheme.colors.forest,
|
||||
fontWeight = FontWeight.Bold,
|
||||
fontSize = 26.sp,
|
||||
)
|
||||
val denominator = (totals.grantedMinutes).coerceAtLeast(1)
|
||||
LinearProgressIndicator(
|
||||
progress = { (totals.usedMinutes.toFloat() / denominator).coerceIn(0f, 1f) },
|
||||
modifier = Modifier.fillMaxWidth().height(7.dp),
|
||||
color = TppTheme.colors.forest,
|
||||
trackColor = TppTheme.colors.successContainer,
|
||||
)
|
||||
Row(Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.spacedBy(10.dp)) {
|
||||
LeaveBalanceStat(
|
||||
title = "Wykorzystano",
|
||||
value = DriverLeaveRequestUiRules.formatQuantity(totals.usedMinutes, "minutes", norm),
|
||||
modifier = Modifier.weight(1f),
|
||||
)
|
||||
LeaveBalanceStat(
|
||||
title = "W przyszłych urlopach",
|
||||
value = DriverLeaveRequestUiRules.formatQuantity(totals.reservedMinutes, "minutes", norm),
|
||||
modifier = Modifier.weight(1f),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (totals.overdueMinutes > 0) {
|
||||
Row(
|
||||
Modifier
|
||||
.fillMaxWidth()
|
||||
.background(TppTheme.colors.warningContainer, RoundedCornerShape(6.dp))
|
||||
.border(1.dp, TppTheme.colors.warningOutline, RoundedCornerShape(6.dp))
|
||||
.padding(12.dp),
|
||||
horizontalArrangement = Arrangement.spacedBy(10.dp),
|
||||
verticalAlignment = Alignment.Top,
|
||||
) {
|
||||
Icon(Icons.Outlined.Info, contentDescription = null, tint = Color(0xFF7A5A00))
|
||||
Column(Modifier.weight(1f), verticalArrangement = Arrangement.spacedBy(3.dp)) {
|
||||
Text("Masz zaległy urlop", color = Color(0xFF7A5A00), fontWeight = FontWeight.Bold)
|
||||
Text(
|
||||
"${DriverLeaveRequestUiRules.formatQuantity(totals.overdueMinutes, "minutes", norm)} zaplanuj możliwie szybko, najpóźniej do 30 września. Saldo nie zniknie automatycznie.",
|
||||
color = Color(0xFF7A5A00),
|
||||
fontSize = 13.sp,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DriverLeaveRequestUiRules.annualPools(summary).forEach { pool ->
|
||||
Row(Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween) {
|
||||
Text(
|
||||
if (pool.year < LocalDate.now().year) "Urlop zaległy z ${pool.year} r." else "Pula na ${pool.year} r.",
|
||||
color = TppTheme.colors.muted,
|
||||
)
|
||||
Text(
|
||||
DriverLeaveRequestUiRules.formatQuantity(pool.availableQuantity, pool.unit, norm),
|
||||
color = TppTheme.colors.ink,
|
||||
fontWeight = FontWeight.Bold,
|
||||
textAlign = TextAlign.End,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DriverLeaveRequestUiRules.annualPools(summary).forEach { pool ->
|
||||
Row(Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween) {
|
||||
if (otherPools.isNotEmpty()) {
|
||||
if (showAnnualUsage) {
|
||||
HorizontalDivider(color = TppTheme.colors.outline)
|
||||
Text(
|
||||
if (pool.year < LocalDate.now().year) "Urlop zaległy z ${pool.year} r." else "Pula na ${pool.year} r.",
|
||||
color = TppTheme.colors.muted,
|
||||
)
|
||||
Text(
|
||||
DriverLeaveRequestUiRules.formatQuantity(pool.availableQuantity, pool.unit, norm),
|
||||
"Pozostałe dostępne limity",
|
||||
color = TppTheme.colors.ink,
|
||||
fontWeight = FontWeight.Bold,
|
||||
textAlign = TextAlign.End,
|
||||
fontSize = 17.sp,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
val otherPools = DriverLeaveRequestUiRules.otherEntitlementPools(summary)
|
||||
if (otherPools.isNotEmpty()) {
|
||||
HorizontalDivider(color = TppTheme.colors.outline)
|
||||
Text(
|
||||
"Pozostałe dostępne limity",
|
||||
color = TppTheme.colors.ink,
|
||||
fontWeight = FontWeight.Bold,
|
||||
fontSize = 17.sp,
|
||||
)
|
||||
Text(
|
||||
"Te limity są rozliczane osobno i nie zmniejszają zwykłego urlopu wypoczynkowego.",
|
||||
color = TppTheme.colors.muted,
|
||||
|
||||
@@ -106,6 +106,9 @@ object DriverLeaveRequestUiRules {
|
||||
.filter { it.poolCode == "ANNUAL" && it.status == "active" }
|
||||
.sortedByDescending { it.year }
|
||||
|
||||
fun isUsageVisible(summary: DriverLeaveSummaryDto?, poolCode: String): Boolean =
|
||||
summary?.visibleUsagePoolCodes?.contains(poolCode) ?: true
|
||||
|
||||
fun otherEntitlementPools(summary: DriverLeaveSummaryDto?): List<DriverLeavePoolDto> =
|
||||
summary?.pools.orEmpty()
|
||||
.filter { it.poolCode != "ANNUAL" && it.status == "active" }
|
||||
|
||||
@@ -19,6 +19,7 @@ class DriverLeaveApiContractTest {
|
||||
"dailyNormMinutes": 480,
|
||||
"balanceConfigured": true,
|
||||
"overdueQuantity": 480,
|
||||
"visibleUsagePoolCodes": ["ANNUAL", "CHILD_CARE_14"],
|
||||
"pools": [{
|
||||
"id": 7,
|
||||
"poolCode": "ANNUAL",
|
||||
@@ -49,6 +50,7 @@ class DriverLeaveApiContractTest {
|
||||
)
|
||||
|
||||
assertEquals(480, response.data.dailyNormMinutes)
|
||||
assertEquals(listOf("ANNUAL", "CHILD_CARE_14"), response.data.visibleUsagePoolCodes)
|
||||
assertEquals(7680, response.data.pools.single().availableQuantity)
|
||||
assertEquals("URLOP", response.data.availableTypes.single().value)
|
||||
assertEquals("ANNUAL", response.data.availableTypes.single().code)
|
||||
|
||||
@@ -124,6 +124,13 @@ class DriverLeaveRequestUiRulesTest {
|
||||
assertEquals(listOf("CHILD_CARE_14", "CARE_LEAVE"), pools.map { it.poolCode })
|
||||
assertEquals("Urlop opiekuńczy", DriverLeaveRequestUiRules.poolLabel("CARE_LEAVE"))
|
||||
assertEquals("Rodzina i opieka", DriverLeaveRequestUiRules.categoryLabel("family"))
|
||||
assertTrue(DriverLeaveRequestUiRules.isUsageVisible(summary, "ANNUAL"))
|
||||
assertFalse(
|
||||
DriverLeaveRequestUiRules.isUsageVisible(
|
||||
summary.copy(visibleUsagePoolCodes = emptyList()),
|
||||
"ANNUAL",
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
Reference in New Issue
Block a user