Coverage Summary for Class: DashboardRecurringWidgetKt (com.georgeci.moneysurfer.feature.dashboard)

Class Class, % Method, % Branch, % Line, % Instruction, %
DashboardRecurringWidgetKt 100% (1/1) 100% (2/2) 40% (4/10) 100% (24/24) 97.5% (269/276)


 package com.georgeci.moneysurfer.feature.dashboard
 
 import androidx.compose.foundation.layout.defaultMinSize
 import androidx.compose.foundation.layout.fillMaxWidth
 import androidx.compose.foundation.layout.padding
 import androidx.compose.runtime.Composable
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.platform.testTag
 import androidx.compose.ui.unit.dp
 import com.georgeci.moneysurfer.uikit.widgets.SurferRecurringItem
 import com.georgeci.moneysurfer.uikit.widgets.SurferRecurringWidget
 import moneysurfer.feature.dashboard.generated.resources.Res
 import moneysurfer.feature.dashboard.generated.resources.dashboard_recurring_due_today
 import moneysurfer.feature.dashboard.generated.resources.dashboard_recurring_due_tomorrow
 import moneysurfer.feature.dashboard.generated.resources.dashboard_recurring_empty_subtitle
 import moneysurfer.feature.dashboard.generated.resources.dashboard_recurring_empty_title
 import moneysurfer.feature.dashboard.generated.resources.dashboard_recurring_see_all
 import moneysurfer.feature.dashboard.generated.resources.dashboard_recurring_title
 import org.jetbrains.compose.resources.stringResource
 
 /**
  * The scheduled payments about to land: the soonest few recurring rules, each with the day it falls
  * due and what it will cost.
  *
  * The rows are handed over exactly as [DashboardState.Content.upcoming] holds them — already sorted
  * and already capped — and how many of them fit is the widget's own call (Hero 3 / Compact 2). The
  * action opens the transactions list rather than a rules screen, which the app does not have yet.
  */
 @Composable
 internal fun RecurringWidget(
     state: DashboardState.Content,
     onEvent: (DashboardEvent) -> Unit,
 ) {
     SurferRecurringWidget(
         items = state.upcoming.map { it.toWidgetItem() },
         title = stringResource(Res.string.dashboard_recurring_title),
         actionLabel = stringResource(Res.string.dashboard_recurring_see_all),
         onActionClick = { onEvent(DashboardEvent.OnSeeAllTransactionsClick) },
         emptyTitle = stringResource(Res.string.dashboard_recurring_empty_title),
         emptySubtitle = stringResource(Res.string.dashboard_recurring_empty_subtitle),
         modifier = Modifier
             .fillMaxWidth()
             .padding(horizontal = 16.dp)
             .defaultMinSize(minHeight = DASHBOARD_WIDGET_MIN_HEIGHT)
             .padding(vertical = 8.dp)
             .testTag(DashboardTestTags.Recurring),
     )
 }
 
 /**
  * The due label: "Today" and "Tomorrow" for the two days a user plans around by name, and the ISO
  * date for everything further out — the app ships no date locale rules, and a date is unambiguous
  * without them. Same call as the balance card's "as of" line.
  */
 @Composable
 private fun UpcomingRecurringUi.toWidgetItem(): SurferRecurringItem = SurferRecurringItem(
     id = id.value,
     name = name,
     dueLabel = when (daysUntil) {
         0 -> stringResource(Res.string.dashboard_recurring_due_today)
         1 -> stringResource(Res.string.dashboard_recurring_due_tomorrow)
         else -> dueDateIso
     },
     amountFormatted = amountFormatted,
     isImminent = isImminent,
 )