Skip to content

Implemented a Export Dialog Box in Transaction Screen#2607

Open
gurnoorpannu wants to merge 3 commits intoopenMF:developmentfrom
gurnoorpannu:feature/loan-transactions-export-dialog
Open

Implemented a Export Dialog Box in Transaction Screen#2607
gurnoorpannu wants to merge 3 commits intoopenMF:developmentfrom
gurnoorpannu:feature/loan-transactions-export-dialog

Conversation

@gurnoorpannu
Copy link
Contributor

@gurnoorpannu gurnoorpannu commented Feb 10, 2026

Fixes - Jira-#657

Before:-
image

After:-

image

Please make sure these boxes are checked before submitting your pull request - thanks!

  • Run the static analysis check ./gradlew check or ci-prepush.sh to make sure you didn't break anything

  • If you have multiple commits please combine them into one commit by squashing them.

Summary by CodeRabbit

  • New Features
    • Added loan transaction export capability with date range selection
    • Users can generate transaction reports by selecting custom from and to dates
    • Date validation ensures valid date ranges before generating reports
    • New export action button added to loan transactions screen

@coderabbitai
Copy link

coderabbitai bot commented Feb 10, 2026

📝 Walkthrough

Walkthrough

This PR introduces a loan transaction export feature by adding UI strings for export/reporting functionality, a new ExportTransactionsDialog composable with date range selection and validation, and integrating the export dialog into the LoanTransactionsScreen with a new toolbar export button.

Changes

Cohort / File(s) Summary
String Resources
feature/loan/src/commonMain/composeResources/values/strings.xml
Added six new localized strings for export functionality: feature_loan_export, feature_loan_export_transactions, feature_loan_from_date, feature_loan_to_date, feature_loan_generate_report, and feature_loan_invalid_date_range for supporting export UI and date-range validation messaging.
Export Dialog Component
feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/loanTransaction/ExportTransactionsDialog.kt
New composable dialog with dual DatePicker components for selecting from/to dates, date range validation logic, and a generate-report callback. Includes helper utilities for date formatting and date picker initialization using Material 3 date pickers.
Screen Integration
feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/loanTransaction/LoanTransactionsScreen.kt
Added export button (FileUpload icon) to the scaffold toolbar actions, UI state for controlling export dialog visibility, and conditional ExportTransactionsDialog invocation with onGenerateReport callback wired as a placeholder.

Sequence Diagram

sequenceDiagram
    actor User
    participant LoanTransactionsScreen as LoanTransactionsScreen
    participant ExportTransactionsDialog as ExportTransactionsDialog
    participant DatePicker as DatePicker Component
    
    User->>LoanTransactionsScreen: Tap export button
    LoanTransactionsScreen->>LoanTransactionsScreen: Set showExportDialog = true
    LoanTransactionsScreen->>ExportTransactionsDialog: Show dialog
    
    User->>ExportTransactionsDialog: Select from date
    ExportTransactionsDialog->>DatePicker: Open from-date picker
    DatePicker->>ExportTransactionsDialog: Return selected date
    ExportTransactionsDialog->>ExportTransactionsDialog: Update fromDate state
    
    User->>ExportTransactionsDialog: Select to date
    ExportTransactionsDialog->>DatePicker: Open to-date picker
    DatePicker->>ExportTransactionsDialog: Return selected date
    ExportTransactionsDialog->>ExportTransactionsDialog: Update toDate state & validate range
    
    alt Valid date range
        User->>ExportTransactionsDialog: Tap generate report
        ExportTransactionsDialog->>LoanTransactionsScreen: onGenerateReport(fromDate, toDate)
        LoanTransactionsScreen->>ExportTransactionsDialog: Dismiss dialog
    else Invalid date range
        ExportTransactionsDialog->>ExportTransactionsDialog: Show error message
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Suggested reviewers

  • itsPronay
  • TheKalpeshPawar

Poem

🐰 Hops with glee, export's alive!
Date pickers dance, logic will thrive,
From and to dates now validate so true,
Reports shall flourish, transactions anew!

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly describes the main change: implementing an export dialog in the transaction screen, which aligns with the PR's core objective of adding export functionality to the Loan Transactions screen.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

No actionable comments were generated in the recent review. 🎉

🧹 Recent nitpick comments
feature/loan/src/commonMain/composeResources/values/strings.xml (1)

297-298: Duplicate string values for feature_loan_export and feature_loan_export_transactions.

Both keys resolve to "Export". If they're meant to serve distinct purposes (icon label vs. dialog title), consider making the dialog title more descriptive (e.g., "Export Transactions") to improve clarity and differentiate them. Otherwise, consolidate into a single key.

feature/loan/src/commonMain/kotlin/com/mifos/feature/loan/loanTransaction/ExportTransactionsDialog.kt (4)

137-145: Close icon lacks proper touch target and accessibility.

Using a raw Icon with .clickable gives a 30×30dp hit area, below the Material recommended 48dp minimum touch target. Wrap with IconButton for proper sizing and ripple feedback, consistent with how the export button is implemented in LoanTransactionsScreen.kt.

♻️ Proposed fix
-                        Icon(
-                            imageVector = MifosIcons.Cancel,
-                            contentDescription = stringResource(Res.string.feature_loan_cancel),
-                            tint = MaterialTheme.colorScheme.outline,
-                            modifier = Modifier
-                                .width(30.dp)
-                                .height(30.dp)
-                                .clickable { onDismiss() },
-                        )
+                        IconButton(onClick = onDismiss) {
+                            Icon(
+                                imageVector = MifosIcons.Cancel,
+                                contentDescription = stringResource(Res.string.feature_loan_cancel),
+                                tint = MaterialTheme.colorScheme.outline,
+                            )
+                        }

225-233: formatDateFromMillis doesn't need the @Composable annotation.

This function performs pure date formatting with no composable calls. Removing @Composable allows it to be called from non-composable contexts (e.g., tests, ViewModels) and avoids unnecessary recomposition tracking.

♻️ Proposed fix
 `@OptIn`(ExperimentalTime::class)
-@Composable
 private fun formatDateFromMillis(millis: Long?): String {

76-76: showInvalidDateRangeError uses remember while other state vars use rememberSaveable.

On configuration change (e.g., rotation), the error message will disappear while fromDate/toDate persist, which could leave the user in an inconsistent state where an invalid range no longer shows the error. Use rememberSaveable for consistency.

♻️ Proposed fix
-    var showInvalidDateRangeError by remember { mutableStateOf(false) }
+    var showInvalidDateRangeError by rememberSaveable { mutableStateOf(false) }

200-209: Dead code path: the !isValidDateRange guard inside onClick is unreachable.

Since the button has enabled = isValidDateRange, the onClick lambda can only fire when isValidDateRange is true. The guard on line 202 and the showInvalidDateRangeError = true branch will never execute. Either remove the guard or, if you want the error to be triggerable, remove the enabled constraint.

♻️ Simplified onClick
                         MifosButton(
                             onClick = {
-                                if (!isValidDateRange) {
-                                    showInvalidDateRangeError = true
-                                    return@MifosButton
-                                }
-                                showInvalidDateRangeError = false
                                 onGenerateReport(fromDate!!, toDate!!)
                             },
                             enabled = isValidDateRange,

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@Kartikey15dem
Copy link
Contributor

I think the the close(x) button should be black with transparent background.

@sonarqubecloud
Copy link

private fun formatDateFromMillis(millis: Long?): String {
if (millis == null) return ""
val localDate = Instant.fromEpochMilliseconds(millis)
.toLocalDateTime(TimeZone.currentSystemDefault())

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

there is a time zone mismatch with fun createSelectableDatesFrom(minDate: LocalDate) = object : SelectableDates I suggest using TimeZone.UTC for consistency


<!-- Export Loan Transactions -->
<string name="feature_loan_export">Export</string>
<string name="feature_loan_export_transactions">Export</string>

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why two different keys with same values ? you meant the second one to be Export Transactions did't you

}

@OptIn(ExperimentalTime::class)
@Composable

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this function should not be annotated with Composable it does not emit UI, call remember or other compose APIs or take compose parameter, marking it with compose it triggers unnecessary recomposition tracking overhead.

var showToDatePicker by rememberSaveable { mutableStateOf(false) }
var fromDate: Long? by rememberSaveable { mutableStateOf(null) }
var toDate: Long? by rememberSaveable { mutableStateOf(null) }
var showInvalidDateRangeError by remember { mutableStateOf(false) }

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this will be lost on config change, should not it be rememberSaveable also ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants