Skip to content

Conversation

@nobodyzero1
Copy link

@nobodyzero1 nobodyzero1 commented Jul 7, 2025

Description

This pull request adds a button for importing person records via CSV on the "All Persons" page, next to the "Add Person" button. The import makes it easier for users to add multiple people at once, which is especially helpful for onboarding and initial setup.

Importing persons data could significantly speed up the onboarding process, as adding each person manually can be tedious.
To implement the import, I extracted reusable logic from the existing "handle" functions into separate utility functions. The CSV import uses these, and the original handlers could also call these functions to avoid code duplication, but to make the testing of the new code easer I did not do this now.

When the import button is clicked, a dialog opens with instructions and an option to download a CSV template. The template headers are based on the PersonType properties, enrollments, privileges, and assignments. The second row contains translations for each header in the user's language. Assignment columns are generated dynamically, so future changes to assignments require no code changes.

The error handling and messaging are still quite basic at this stage, but in my opinion, the feature is already sufficiently robust for practical use and users would benefit from having it available.

Since I am new to contributing to open source projects like this, I am grateful for any suggestions or corrections. Please let me know if there is anything I can improve or if I should follow a different approach.

Dependencies:
No new dependencies were added.

Fixes # (issue)
No related issue

Type of change

Please delete options that are not relevant.

  • New feature (non-breaking change which adds functionality)

Checklist:

  • My code follows the style guidelines of this project
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings
  • Any dependent changes have been merged and published in downstream modules

@vercel
Copy link

vercel bot commented Jul 7, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Updated (UTC)
staging-organized-app Ready Ready Preview Nov 25, 2025 10:36pm
test-organized-app Ready Ready Preview Nov 25, 2025 10:36pm

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jul 7, 2025

Walkthrough

Adds a full CSV import/export feature (UI, parsing, template download), many person-mutating utilities (enrollments, privileges, spiritual-status, emergency contacts), assignment structures and toggle logic, new SVG icon components, All Persons wiring for data-exchange, and removes a legacy export button.

Changes

Cohort / File(s) Summary of changes
Icons
src/components/icons/IconUpload.tsx, src/components/icons/IconImportCSV.tsx, src/components/icons/index.ts
New IconUpload and IconImportCSV SvgIcon components; IconUpload exported from icons index.
Definitions & runtime guards
src/definition/person.ts
Introduced ALL_PRIVILEGE_TYPES / ALL_ENROLLMENT_TYPES; switched unions to const-derived unions; added isPrivilegeType / isEnrollmentType; adjusted StatusHistoryType.end_date and PersonType.first_report types.
Assignment structure & lookup
src/features/persons/assignments/assignmentStructure.ts, src/features/persons/assignments/useAssignments.tsx
Added ASSIGNMENT_SECTIONS static config; memoized assignment lookup and exposed getAssignmentName from useAssignments.
Assignment toggling logic
src/utils/assignments.ts
Added toggleAssignment and helpers (view/language-group handling, unappliable checks, exclusivity, add/remove logic).
Import/Export root & types
src/features/persons/import_export/index.tsx, src/features/persons/import_export/index.types.ts, src/features/persons/import_export/*
Added ImportExport dialog, tab UI, dialog types/state, template download hook, and orchestration for import/export flows.
Import UI & hook
src/features/persons/import_export/import/index.tsx, .../useImport.tsx, .../index.types.ts
New Import dropzone UI and useImport hook to read CSV, detect headers, assemble selected fields/groups, set fileData and advance to confirmation; added related types.
Confirm import UI, parsing & orchestration
src/features/persons/import_export/confirm_import/index.tsx, .../useCSVImport.tsx, .../useConfirmImport.tsx, .../index.types.ts
New ConfirmImport UI, CSV parsing/delimiter detection, parse-to-persons/groups, DB add flows, orchestration hook, and import result types.
Field handlers & import config
src/features/persons/import_export/confirm_import/usePrivilegeHandler.ts, useEnrollmentHandler.ts, useAssignmentHandler.ts, usePersonsImportConfig.ts
Added handler hooks (privilege/enrollment/assignment) and usePersonsImportConfig producing PERSON_FIELD_META mapping CSV headers to handlers/mutators.
CSV conversion utilities
src/features/persons/import_export/confirm_import/useConvertValue.ts
Added useConvertValue converter supporting boolean/number/date/gender/object parsing used by import handlers.
Template generation & download
src/features/persons/import_export/useTemplateDownload.tsx
Added localized CSV template generator and download helper (BOM + blob + anchor) with delimiter helpers.
Export UI & hook update
src/features/persons/import_export/export/index.tsx, .../useExportPersons.tsx, .../export/index.types.ts
Added Export UI component; useExportPersons now exposes fileName; added ExportType type.
Person mutation utilities
src/utils/person.ts, src/utils/enrollments.ts, src/utils/privileges.ts, src/utils/spiritual_status.ts, src/utils/emergencyContacts.tsx
New mutators for name/gender/birth/contact/address/phone, enrollment history helpers, privilege history helpers, spiritual-status lifecycle/history management, and stringAddEmergencyContacts.
Field service group helpers
src/features/persons/import_export/confirm_import/field_service_group.tsx
Helpers to create/find field service groups and append members with sequential sort_index and updatedAt updates.
All Persons wiring
src/pages/persons/all_persons/index.tsx, src/pages/persons/all_persons/useAllPersons.tsx
Added Import/Export trigger to All Persons header and extended useAllPersons return with handleOpenExchange, handleCloseExchange, and isDataExchangeOpen.
Legacy removal
src/features/persons/export_persons/index.tsx
Removed legacy ExportPersons component.
Minor formatting
src/features/persons/assignment_group/useAssignmentGroup.tsx
Trivial whitespace change.
Changelog
CHANGELOG.md
Added an "Unrealesed" entry documenting the persons CSV import feature (typo preserved).

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant U as User
  participant AP as All Persons (header)
  participant D as ImportExport Dialog
  participant I as Import (useImport)
  participant C as ConfirmImport UI
  participant P as CSV Parser (useCSVImport)
  participant H as Field Handlers / Mutators
  participant DB as Database

  U->>AP: Click Import/Export
  AP->>D: open dialog
  U->>D: Select Import tab
  U->>I: Drop CSV file
  I->>P: getCSVHeaders(contents)
  I->>D: set fileData, navigate to confirm
  D->>C: render with fileData
  C->>P: parseCsvToPersonsAndGroups(contents, selectedFields)
  loop per CSV row
    P->>H: map columns → handlers (convert/enrollment/privilege/assignment/fields)
    H->>P: mutate Person objects
  end
  C->>P: addPersonsToDB / addGroupsToDB
  P->>DB: upsert persons & groups
  P-->>C: return import results
  C-->>D: close dialog
Loading
sequenceDiagram
  autonumber
  participant CI as ConfirmImport
  participant CFG as usePersonsImportConfig
  participant HF as HandlerFactory
  participant MUT as Mutators (utils)
  participant PR as Person object

  CI->>CFG: request PERSON_FIELD_META
  CI->>HF: call makeXHandler for a field
  HF->>MUT: invoke specific mutator (e.g., toggleAssignment, privilegesAddHistory)
  MUT->>PR: mutate person.person_data and updatedAt
  MUT-->>HF: done
  HF-->>CI: handler complete
Loading

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~120 minutes

Areas needing careful review:

  • CSV parsing, delimiter detection, and date parsing logic (useCSVImport, useConvertValue).
  • In-place mutating utilities for PersonType (spiritual_status, enrollments, privileges, assignments, person utils) and their handling of _deleted/edge cases.
  • Import orchestration: deduplication, DB write ordering between persons and field_service_groups, and error aggregation.
  • Type changes in src/definition/person.ts and caller compatibility.

Possibly related PRs

Suggested labels

released

Suggested reviewers

  • rhahao

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title 'feat(persons): add CSV import functionality' clearly and concisely summarizes the main change—adding CSV import capability for persons. It follows conventional commit format and accurately reflects the primary feature introduced in this PR.
Description check ✅ Passed The description is comprehensive and directly related to the changeset. It explains the purpose (importing person records via CSV), context (onboarding efficiency), implementation approach (extracted utility functions), key features (dialog with template download, dynamic assignment columns, translations), and known limitations (basic error handling). The description is well-structured and provides meaningful context for the changes.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Tip

📝 Customizable high-level summaries are now available in beta!

You can now customize how CodeRabbit generates the high-level summary in your pull requests — including its content, structure, tone, and formatting.

  • Provide your own instructions using the high_level_summary_instructions setting.
  • Format the summary however you like (bullet lists, tables, multi-section layouts, contributor stats, etc.).
  • Use high_level_summary_in_walkthrough to move the summary from the description to the walkthrough section.

Example instruction:

"Divide the high-level summary into five sections:

  1. 📝 Description — Summarize the main change in 50–60 words, explaining what was done.
  2. 📓 References — List relevant issues, discussions, documentation, or related PRs.
  3. 📦 Dependencies & Requirements — Mention any new/updated dependencies, environment variable changes, or configuration updates.
  4. 📊 Contributor Summary — Include a Markdown table showing contributions:
    | Contributor | Lines Added | Lines Removed | Files Changed |
  5. ✔️ Additional Notes — Add any extra reviewer context.
    Keep each section concise (under 200 words) and use bullet or numbered lists for clarity."

Note: This feature is currently in beta for Pro-tier users, and pricing will be announced later.


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.

@nobodyzero1 nobodyzero1 changed the title Implementing CSV-Import for persons feat(persons): add CSV import functionality Jul 7, 2025
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 16

🧹 Nitpick comments (7)
src/features/persons/import_persons/index.tsx (1)

60-60: Consider adding download icon for consistency.

The commented-out download icon could enhance the user experience by providing visual context for the template download action.

-              // startIcon={<Download />}
+              startIcon={<IconDownload />}

Don't forget to import the IconDownload component if you decide to add it.

src/components/icons/IconUpload.tsx (2)

3-9: Consider reusing the existing IconProps type for consistency.

There's already an IconProps type defined in src/views/components/icons/index.types.ts. Consider importing and extending it if needed, rather than creating a duplicate definition.

-type IconProps = {
-  color?: string;
-  width?: number;
-  height?: number;
-  sx?: SxProps<Theme>;
-  className?: string;
-};
+import { IconProps as BaseIconProps } from '@views/components/icons/index.types';
+
+type IconProps = BaseIconProps & {
+  width?: number;
+  height?: number;
+  sx?: SxProps<Theme>;
+  className?: string;
+};

20-20: Handle undefined className to avoid "undefined" in class string.

When className is undefined, the template literal will produce "organized-icon-upload undefined".

-      className={`organized-icon-upload ${className}`}
+      className={`organized-icon-upload${className ? ` ${className}` : ''}`}
src/utils/person.ts (1)

11-74: Document that these functions mutate the input PersonType object.

All functions in this file mutate the passed PersonType object. Consider adding JSDoc comments to make this behavior explicit.

Example for one function:

+/**
+ * Updates the first name of a person and recalculates the display name.
+ * @param newPerson - The person object to update (will be mutated)
+ * @param value - The new first name
+ */
 export const changeFirstname = (newPerson: PersonType, value: string) => {
src/features/persons/import_persons/useImportPersons.ts (2)

226-226: Remove empty line.

     return dataLines
       .map((line) => {
-        
         try {

369-374: Remove commented out code.

         errorReason = String(error);
         console.error('Fehler beim Speichern:', error);
-        /*         displaySnackNotification({
-          header: t('tr_personAdded'),
-          message: 'Fehler beim Speichern:' + error,
-          severity: 'error',
-        }); */
       }
src/utils/spiritual_status.ts (1)

175-279: Consider extracting common history management logic

This function shares significant logic with toggleUnbaptizedPublisher. Consider extracting the common pattern of closing/deleting history records based on date comparisons into a reusable helper function.

Would you like me to help create a reusable helper function to reduce the code duplication between these toggle functions?

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b440ff3 and 953e03e.

⛔ Files ignored due to path filters (2)
  • src/locales/de-DE/general.json is excluded by !**/*.json
  • src/locales/en/general.json is excluded by !**/*.json
📒 Files selected for processing (12)
  • src/components/icons/IconUpload.tsx (1 hunks)
  • src/components/icons/index.ts (1 hunks)
  • src/definition/person.ts (1 hunks)
  • src/features/persons/assignments/useAssignments.tsx (2 hunks)
  • src/features/persons/import_persons/index.tsx (1 hunks)
  • src/features/persons/import_persons/useImportPersons.ts (1 hunks)
  • src/pages/persons/all_persons/index.tsx (2 hunks)
  • src/utils/assignments.ts (1 hunks)
  • src/utils/enrollments.ts (1 hunks)
  • src/utils/person.ts (1 hunks)
  • src/utils/privileges.ts (1 hunks)
  • src/utils/spiritual_status.ts (1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (6)
src/components/icons/IconUpload.tsx (1)
src/views/components/icons/index.types.ts (1)
  • IconProps (1-5)
src/utils/assignments.ts (1)
src/definition/person.ts (1)
  • PersonType (66-104)
src/utils/person.ts (1)
src/definition/person.ts (1)
  • PersonType (66-104)
src/utils/privileges.ts (2)
src/definition/person.ts (2)
  • PersonType (66-104)
  • PrivilegeType (4-4)
src/utils/date.ts (1)
  • formatDate (15-17)
src/utils/enrollments.ts (2)
src/definition/person.ts (2)
  • PersonType (66-104)
  • EnrollmentType (11-11)
src/utils/date.ts (1)
  • formatDate (15-17)
src/utils/spiritual_status.ts (2)
src/definition/person.ts (1)
  • PersonType (66-104)
src/utils/date.ts (2)
  • formatDate (15-17)
  • dateFirstDayMonth (26-31)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Socket Security: Pull Request Alerts
  • GitHub Check: Summary
🔇 Additional comments (19)
src/definition/person.ts (4)

3-4: LGTM! Excellent type safety improvement.

The pattern of using const arrays to derive types enables both compile-time type checking and runtime validation, which is essential for the CSV import functionality.


6-8: LGTM! Robust type guard implementation.

The type guard correctly uses the includes method with proper type assertion. This will be valuable for validating CSV data at runtime.


10-11: LGTM! Consistent pattern for enrollment types.

Following the same pattern as privilege types ensures consistency across the codebase.


13-15: LGTM! Consistent type guard implementation.

The enrollment type guard follows the same robust pattern as the privilege type guard.

src/components/icons/index.ts (1)

302-302: LGTM! Standard icon export.

The export follows the established pattern and properly integrates the new IconUpload component.

src/pages/persons/all_persons/index.tsx (2)

18-18: LGTM! Proper import placement.

The import is correctly placed with other feature imports and follows the established pattern.


44-44: LGTM! Appropriate UI integration.

The PersonsImport component is properly placed within the person editor conditional, alongside other person management actions. This provides a logical user experience.

src/features/persons/assignments/useAssignments.tsx (3)

141-160: LGTM! Well-structured assignment lookup.

The memoized lookup object efficiently maps assignment codes to human-readable names. The logic correctly handles both string and enum codes, and the dot notation provides a clear hierarchical structure.


162-164: LGTM! Robust assignment name resolver.

The function provides a clean interface for resolving assignment codes to names, with appropriate fallback behavior when no match is found.


335-335: LGTM! Proper hook integration.

The getAssignmentName function is correctly added to the hook's return value, making it accessible to consumers.

src/features/persons/import_persons/index.tsx (5)

1-9: LGTM! Clean imports and dependencies.

The imports are well-organized and include all necessary dependencies for the component functionality.


10-28: LGTM! Proper state management and event handlers.

The component correctly uses React hooks for state management and provides clean event handlers for user interactions.


32-38: LGTM! Clean import button implementation.

The button properly uses the IconUpload component and follows the established button pattern in the application.


40-69: LGTM! Well-structured dialog with clear user flow.

The dialog provides a clear user experience with descriptive text and appropriate action buttons. The three-step flow (cancel, download template, choose file) is intuitive.


71-77: LGTM! Proper hidden file input implementation.

The hidden file input correctly restricts file types to CSV and uses the ref pattern for programmatic access. This is a standard and accessible approach.

src/features/persons/import_persons/useImportPersons.ts (3)

399-411: Verify file encoding handling for international characters.

The FileReader uses default encoding. For CSV files with international characters, explicit UTF-8 encoding might be needed.

Consider specifying the encoding:

-    reader.readAsText(file);
+    reader.readAsText(file, 'UTF-8');

288-291: Fix type error: convertValue returns Date, not string.

The convertValue function with 'date' type returns a Date object, but toLowerCase() is being called on it.

                   privilegeStartDateChange(
                     csvperson,
                     csvperson.person_data.privileges[0].id,
-                    convertValue(cols[index].toLowerCase(), 'date')
+                    convertValue(cols[index], 'date')
                   );

Likely an incorrect or invalid review comment.


317-321: Fix type error: convertValue returns Date, not string.

Same issue as before - calling toLowerCase() on a Date result.

                   enrollmentStartDateChange(
                     csvperson,
                     csvperson.person_data.enrollments[0].id,
-                    convertValue(cols[index].toLowerCase(), 'date')
+                    convertValue(cols[index], 'date')
                   );

Likely an incorrect or invalid review comment.

src/utils/spiritual_status.ts (1)

105-173: Well-structured mutual exclusivity logic

The function correctly handles the complex state transitions between midweek meeting student and unbaptized publisher statuses, with proper consideration for the isAddPerson flag and date boundaries.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (5)
src/features/persons/import_persons/useImportPersons.ts (5)

258-263: Add null check before accessing enrollment array.

The code assumes the enrollment array has at least one element without verification.

+        if (csvperson.person_data.enrollments.length > 0) {
           enrollmentChange(
             csvperson,
             csvperson.person_data.enrollments[0].id,
             enrollmentType
           );
+        }

367-367: Use translation for error message.

The error message is hardcoded in German instead of using the translation system.

-          console.error('Fehler beim Parsen der Zeile:', line, error);
+          console.error('Error parsing line:', line, error);

386-387: Use translation for error messages.

Error messages are hardcoded in German.

-          console.error('UUID-Kollision:', person.person_uid);
+          console.error('UUID collision:', person.person_uid);

396-396: Use translation for error message.

The error message is hardcoded in German instead of using the translation system.

-        console.error('Fehler beim Speichern:', error);
+        console.error('Error saving person:', error);

265-274: Add null check before accessing enrollment array.

Similar to the previous issue, this code accesses enrollments[0] without checking if the array has elements.

     if (
+      Array.isArray(csvperson.person_data.enrollments) &&
+      csvperson.person_data.enrollments.length > 0 &&
       csvperson.person_data.enrollments[0].id !== undefined &&
       enrollmentType === 'start_date'
     ) {
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 953e03e and 914dea5.

📒 Files selected for processing (2)
  • src/features/persons/assignments/useAssignments.tsx (2 hunks)
  • src/features/persons/import_persons/useImportPersons.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/features/persons/assignments/useAssignments.tsx
🧰 Additional context used
🧬 Code Graph Analysis (1)
src/features/persons/import_persons/useImportPersons.ts (11)
src/states/settings.ts (1)
  • userDataViewState (485-494)
src/states/field_service_groups.ts (1)
  • languageGroupsState (91-95)
src/services/dexie/schema.ts (1)
  • personSchema (192-237)
src/states/persons.ts (1)
  • personsState (17-17)
src/definition/person.ts (5)
  • PersonType (66-104)
  • ALL_PRIVILEGE_TYPES (3-3)
  • ALL_ENROLLMENT_TYPES (10-10)
  • isPrivilegeType (6-8)
  • isEnrollmentType (13-15)
src/utils/person.ts (7)
  • changeFirstname (11-22)
  • changeLastname (24-35)
  • toggleGender (37-53)
  • changeBirthDate (55-59)
  • changeEmailAddress (61-64)
  • changeAddress (71-74)
  • changePhone (66-69)
src/utils/spiritual_status.ts (6)
  • toggleMidweekMeetingStudent (5-55)
  • midweekMeetingStudentStartDateChange (57-68)
  • toggleBaptizedPublisher (175-279)
  • changeBaptismDate (281-307)
  • toggleUnbaptizedPublisher (105-173)
  • toggleActive (309-361)
src/utils/assignments.ts (1)
  • toggleAssignment (6-92)
src/utils/privileges.ts (3)
  • privilegesAddHistory (4-15)
  • privilegeChange (32-45)
  • privilegeStartDateChange (17-30)
src/utils/enrollments.ts (3)
  • enrollmentsAddHistory (4-13)
  • enrollmentChange (30-43)
  • enrollmentStartDateChange (15-28)
src/services/dexie/persons.ts (1)
  • dbPersonsSave (19-106)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Socket Security: Pull Request Alerts
  • GitHub Check: Summary
🔇 Additional comments (6)
src/features/persons/import_persons/useImportPersons.ts (6)

63-89: LGTM: Well-structured handler mapping.

The handlers mapping provides a clean approach to connect CSV column paths to person property updates. The comment about translation variables is helpful for maintainability.


145-180: LGTM: Sophisticated CSV delimiter detection.

The delimiter detection algorithm is well-implemented, using multiple sample lines and consistency scoring to determine the most appropriate delimiter. The bonus scoring for consistent column counts is a nice touch.


114-143: LGTM: Comprehensive value conversion function.

The value conversion function handles multiple data types appropriately with proper error handling for JSON parsing and date conversion.


437-444: LGTM: Smart CSV delimiter selection based on locale.

Using the locale's decimal separator to determine the appropriate CSV delimiter is a thoughtful approach that will improve user experience across different regions.


489-503: LGTM: Proper CSV template generation with Excel compatibility.

The BOM addition for Excel compatibility and proper blob handling for file download are well-implemented. The cleanup of the object URL is also handled correctly.


235-241: Add null check before accessing privileges array.

The code accesses privileges[0] without verifying the array has elements, which could cause a runtime error.

     if (
       Array.isArray(csvperson.person_data.privileges) &&
       csvperson.person_data.privileges.length !== 0 &&
       privilegeName === 'start_date'
     ) {
+      if (csvperson.person_data.privileges.length > 0) {
         privilegeStartDateChange(
           csvperson,
           csvperson.person_data.privileges[0].id,
           convertValue(privilegeValue.toLowerCase(), 'date')
         );
+      }
     }

Likely an incorrect or invalid review comment.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (4)
src/features/persons/import_persons/useImportPersons.ts (4)

367-367: Use translation for error messages.

The error message is hardcoded in German instead of using the translation system.

-          console.error('Fehler beim Parsen der Zeile:', line, error);
+          console.error('Error parsing line:', line, error);

386-387: Use translation for error messages.

Error messages are hardcoded in German.

-          console.error('UUID-Kollision:', person.person_uid);
+          console.error('UUID collision:', person.person_uid);

396-396: Use translation for error messages.

Error message is hardcoded in German.

-        console.error('Fehler beim Speichern:', error);
+        console.error('Error saving person:', error);

409-409: Fix inverted logic condition.

The condition !(importedPersons.length !== 0) is equivalent to importedPersons.length === 0, which means the success notification will only show when no persons were imported. This seems incorrect.

-    if (Array.isArray(importedPersons) && importedPersons.length !== 0) {
+    if (Array.isArray(importedPersons) && importedPersons.length > 0) {
🧹 Nitpick comments (1)
src/features/persons/import_persons/useImportPersons.ts (1)

63-89: Consider adding JSDoc documentation for the handlers object.

The handlers object is well-structured with clear mapping between CSV paths and person property handlers. The comment on line 64 is helpful but could be enhanced with JSDoc for better maintainability.

+ /**
+  * Maps CSV column paths to their corresponding person property handlers.
+  * The path after 'person_data.' should correspond to the translation variable.
+  * @example 'person_data.date' → tr_date
+  */
  const handlers: Record<string, (p: PersonType, value: string) => void> = {
-   // for the correct translation in the csv template it is important that the part after 'person_data.' is correspending to the translation variable like date -> tr_date
    'person_data.firstname': (p, v) => changeFirstname(p, v),
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 914dea5 and 4ac06f2.

📒 Files selected for processing (4)
  • src/features/persons/import_persons/useImportPersons.ts (1 hunks)
  • src/utils/assignments.ts (1 hunks)
  • src/utils/person.ts (1 hunks)
  • src/utils/spiritual_status.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • src/utils/person.ts
  • src/utils/assignments.ts
  • src/utils/spiritual_status.ts
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Socket Security: Pull Request Alerts
🔇 Additional comments (7)
src/features/persons/import_persons/useImportPersons.ts (7)

1-48: LGTM: Comprehensive imports and setup.

The imports are well-organized and cover all necessary dependencies for the CSV import functionality. The integration with utility functions and type definitions shows good modular design.


114-143: LGTM: Robust value conversion with proper type handling.

The convertValue function handles various data types appropriately with null checks and error handling for JSON parsing and date conversion.


145-180: LGTM: Sophisticated delimiter detection algorithm.

The delimiter detection logic is well-implemented with scoring based on column count and consistency. The bonus for consistent column counts across sample lines is a good approach.


437-444: LGTM: Clever locale-based delimiter selection.

The logic to determine CSV delimiter based on the locale's decimal separator is a thoughtful approach for better compatibility with regional Excel settings.


481-504: LGTM: Proper CSV template download implementation.

The template download function correctly handles BOM for Excel compatibility and properly cleans up the object URL after download.


506-513: LGTM: Clean hook interface.

The hook returns a focused API with the three main functions needed for CSV import functionality.


205-242: Add array bounds checking for privileges access.

The privilege handling logic correctly checks for empty arrays before adding history, but there's a potential issue when accessing privileges[0] without verifying the array has elements after the history is added.

      if (
        isPrivilegeType(privilegeName) &&
        ['1', 'true'].includes(privilegeValue.toLowerCase())
      ) {
        privilegesAddHistory(csvperson);
-       if (
-         Array.isArray(csvperson.person_data.privileges) &&
-         csvperson.person_data.privileges.length !== 0
-       ) {
+       if (
+         Array.isArray(csvperson.person_data.privileges) &&
+         csvperson.person_data.privileges.length > 0
+       ) {
          privilegeChange(
            csvperson,
            csvperson.person_data.privileges[0].id,
            privilegeName
          );
        }
      }

Likely an incorrect or invalid review comment.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (1)
CHANGELOG.md (1)

1-1: Fix header spelling + markdown-lint violation

The heading is missing the mandatory space after the hashes and “Unrealesed” is misspelled.
Please align with the Keep-a-Changelog convention:

-##[Unrealesed]
+## [Unreleased]
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e626432 and 1141e9b.

📒 Files selected for processing (1)
  • CHANGELOG.md (1 hunks)
🧰 Additional context used
🪛 markdownlint-cli2 (0.17.2)
CHANGELOG.md

1-1: No space after hash on atx style heading

(MD018, no-missing-space-atx)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Socket Security: Pull Request Alerts
  • GitHub Check: Summary

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (1)
CHANGELOG.md (1)

1-5: Fix heading typo & follow Markdown/Keep-a-Changelog conventions

‒ “Unrealesed” is misspelled
‒ Missing space after the hashes triggers MD018 (##[Unrealesed])
‒ Bullet sentence should start with a capital and end with a period for consistency.

-##[Unrealesed]
-
-### Features
-
-- **persons:** add button to import persons from CSV file on "All Persons" page, including template download and dynamic header translation for easier onboarding
+## [Unreleased]
+
+### Features
+
+- **persons:** Add button to import persons from CSV file on "All Persons" page, including template download and dynamic header translation for easier onboarding.
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1141e9b and c9fc5ce.

⛔ Files ignored due to path filters (1)
  • src/locales/de-DE/general.json is excluded by !**/*.json
📒 Files selected for processing (1)
  • CHANGELOG.md (2 hunks)
🧰 Additional context used
🪛 markdownlint-cli2 (0.17.2)
CHANGELOG.md

1-1: No space after hash on atx style heading

(MD018, no-missing-space-atx)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Summary
🔇 Additional comments (1)
CHANGELOG.md (1)

41-50: No additional feedback on these unchanged historical entries.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (2)
src/features/persons/import_export/confirm_import/usePersonsImportConfig.ts (2)

163-170: Standardize boolean examples to "yes" (lowercase) per UX guidance.

Examples currently mix "Yes"/"yes". Normalize to "yes" to match parsing expectations and UX copy.

-      examples: ['Yes', '', 'Yes', ''],
+      examples: ['yes', '', 'yes', ''],

-      examples: ['Yes', 'yes', 'yes', ''],
+      examples: ['yes', 'yes', 'yes', ''],

-      examples: ['', '', '', 'Yes'],
+      examples: ['', '', '', 'yes'],

Also applies to: 185-192, 202-209


285-296: Nice refactor: centralized assignment examples via lookup.

The ASSIGNMENT_EXAMPLES + getExamplesForAssignment pattern improves maintainability over inline includes-chains.

Optional: move ASSIGNMENT_EXAMPLES to a small module (e.g., assignmentExamples.ts) co-located with assignmentStructure to keep data/config together.

Also applies to: 33-46

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e1b95b5 and 8efcbaf.

📒 Files selected for processing (1)
  • src/features/persons/import_export/confirm_import/usePersonsImportConfig.ts (1 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-07-09T14:24:33.861Z
Learnt from: nobodyzero1
PR: sws2apps/organized-app#4326
File: src/utils/enrollments.ts:20-25
Timestamp: 2025-07-09T14:24:33.861Z
Learning: In src/utils/enrollments.ts, the enrollmentStartDateChange function already includes a null check for the current variable to handle cases where the find operation returns undefined.

Applied to files:

  • src/features/persons/import_export/confirm_import/usePersonsImportConfig.ts
🧬 Code graph analysis (1)
src/features/persons/import_export/confirm_import/usePersonsImportConfig.ts (6)
src/definition/person.ts (3)
  • PersonType (66-109)
  • ALL_PRIVILEGE_TYPES (3-3)
  • ALL_ENROLLMENT_TYPES (10-10)
src/utils/person.ts (7)
  • changeFirstname (4-15)
  • changeLastname (17-28)
  • toggleGender (30-49)
  • changeBirthDate (51-55)
  • changeEmailAddress (57-60)
  • changeAddress (67-70)
  • changePhone (62-65)
src/utils/emergencyContacts.tsx (1)
  • stringAddEmergencyContacts (4-39)
src/utils/spiritual_status.ts (6)
  • toggleMidweekMeetingStudent (23-62)
  • midweekMeetingStudentStartDateChange (64-85)
  • toggleBaptizedPublisher (148-172)
  • changeBaptismDate (174-203)
  • toggleUnbaptizedPublisher (123-147)
  • toggleActive (212-278)
src/utils/privileges.ts (1)
  • privilegeStartDateChange (19-38)
src/utils/enrollments.ts (1)
  • enrollmentStartDateChange (16-30)
🔇 Additional comments (2)
src/features/persons/import_export/confirm_import/usePersonsImportConfig.ts (2)

172-183: Good defensive guards on history/privilege/enrollment ids.

Using optional chaining with ?? '' aligns with the change helpers that early-return on empty ids; avoids runtime crashes when start-date is provided without a prior toggle. Nice.

Based on learnings.

Also applies to: 236-250, 269-283


98-108: Implement handler or hide field_service_group from import template.

The handler is confirmed to be a no-op (lines 103–107). Since the field appears in exported templates via useTemplateDownload.tsx and flows through PERSON_FIELD_META into useConfirmImport.tsx, users will see and be able to fill this field, but it will be silently discarded on import—confusing behavior.

Two options:

  • Wire the handler to a setter (if group assignment logic exists elsewhere in the codebase)
  • Add showCheckbox: false to hide it from the template (the interface supports this at line 61)

coderabbitai[bot]
coderabbitai bot previously approved these changes Oct 24, 2025
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (1)
src/features/persons/import_export/confirm_import/usePersonsImportConfig.ts (1)

56-64: Remove the unused showCheckbox property from PersonFieldMeta interface.

The showCheckbox optional property at line 63 is defined but never instantiated or referenced anywhere in the codebase. It should be removed to keep the interface clean.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8efcbaf and 73df0c2.

📒 Files selected for processing (1)
  • src/features/persons/import_export/confirm_import/usePersonsImportConfig.ts (1 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-07-09T14:24:33.861Z
Learnt from: nobodyzero1
PR: sws2apps/organized-app#4326
File: src/utils/enrollments.ts:20-25
Timestamp: 2025-07-09T14:24:33.861Z
Learning: In src/utils/enrollments.ts, the enrollmentStartDateChange function already includes a null check for the current variable to handle cases where the find operation returns undefined.

Applied to files:

  • src/features/persons/import_export/confirm_import/usePersonsImportConfig.ts
🧬 Code graph analysis (1)
src/features/persons/import_export/confirm_import/usePersonsImportConfig.ts (6)
src/definition/person.ts (3)
  • PersonType (66-109)
  • ALL_PRIVILEGE_TYPES (3-3)
  • ALL_ENROLLMENT_TYPES (10-10)
src/utils/person.ts (7)
  • changeFirstname (4-15)
  • changeLastname (17-28)
  • toggleGender (30-49)
  • changeBirthDate (51-55)
  • changeEmailAddress (57-60)
  • changeAddress (67-70)
  • changePhone (62-65)
src/utils/emergencyContacts.tsx (1)
  • stringAddEmergencyContacts (4-39)
src/utils/spiritual_status.ts (6)
  • toggleMidweekMeetingStudent (23-62)
  • midweekMeetingStudentStartDateChange (64-85)
  • toggleBaptizedPublisher (148-172)
  • changeBaptismDate (174-203)
  • toggleUnbaptizedPublisher (123-147)
  • toggleActive (212-278)
src/utils/privileges.ts (1)
  • privilegeStartDateChange (19-38)
src/utils/enrollments.ts (1)
  • enrollmentStartDateChange (16-30)
🔇 Additional comments (9)
src/features/persons/import_export/confirm_import/usePersonsImportConfig.ts (9)

33-48: LGTM! Clean refactor of assignment examples.

The lookup structure with typed 4-tuple examples and readonly return type is well implemented. The nullish coalescing provides a safe fallback, and the separation of data from logic makes future updates straightforward.


173-185: Good fix for safe array access.

The handler now uses optional chaining (history[0]?.id) and nullish coalescing (?? '') to safely access the midweek meeting student history, preventing the runtime error flagged in previous reviews.


222-236: LGTM! Well-structured dynamic privilege fields.

The mapping from ALL_PRIVILEGE_TYPES correctly generates privilege fields with appropriate examples (elder in first, MS in second) and properly transforms the 'ms' key to 'ministerialServant' for the translation label.


238-252: Good fix for safe privilege access.

The handler now uses optional chaining (privileges[0]?.id) and nullish coalescing (?? '') to safely handle cases where no privilege exists. The underlying privilegeStartDateChange function handles the empty string ID gracefully by returning early.


254-263: LGTM! Clean dynamic enrollment field generation.

The mapping correctly generates enrollment fields from ALL_ENROLLMENT_TYPES, with examples showing appropriate variety (AP for the first person, FR for the third).


281-291: LGTM! Elegant dynamic assignment field generation.

The flatMap over ASSIGNMENT_SECTIONS cleanly transforms the nested structure into a flat array of field metadata. Using getExamplesForAssignment with the refactored lookup structure makes this code maintainable and easy to extend.


293-303: LGTM! Clean aggregation and return.

The final assembly spreads all field arrays in a logical order: personal information, privileges with start dates, enrollments with start dates, and assignments. The return structure is simple and clear.


99-110: Remove review comment: field_service_group handler is intentionally empty by design.

The field_service_group handler in usePersonsImportConfig.ts is not incomplete. In useCSVImport.tsx, the import processor explicitly checks for field_service_group and delegates to addPersonToGroupBySortIndex() to handle group assignment. This is a deliberate architectural pattern where the actual processing logic is centralized in the import flow rather than duplicated in the handler function. The empty handler is correct for this field.

Likely an incorrect or invalid review comment.


265-279: Critical null safety bug in enrollmentStartDateChange requires immediate fix.

The learnings claim a null check exists in src/utils/enrollments.ts, but verification shows the function (lines 16-30) does NOT check if current is defined after calling .find(). Accessing current.start_date when current is undefined will crash at runtime.

While the call site mitigates this by passing an empty string ('') when no enrollments exist (triggering an early return), the utility function remains unsafe for any scenario where find() returns undefined. This needs a defensive check:

const current = newPerson.person_data.enrollments.find(
  (history) => history.id === id
);
if (!current) {
  return;
}
⛔ Skipped due to learnings
Learnt from: nobodyzero1
PR: sws2apps/organized-app#4326
File: src/utils/enrollments.ts:20-25
Timestamp: 2025-07-09T14:24:33.861Z
Learning: In src/utils/enrollments.ts, the enrollmentStartDateChange function already includes a null check for the current variable to handle cases where the find operation returns undefined.

coderabbitai[bot]
coderabbitai bot previously approved these changes Oct 24, 2025
@nobodyzero1
Copy link
Author

nobodyzero1 commented Oct 24, 2025

@nobodyzero1 sorry for the delay 🙂

Here's my feedback regarding the user experience flow: Overall, the one-window approach is very nice and easy to use, I like it. We can go even one step further, by combining it with the export button. And the good thing is that we already have a similar interface on the Congregation settings page → Import/Export button. Please take a look and feel free to re-use the existing elements and integrate your feature. The structure and elements are identical with a few minor edits:

1. We can **combine the import and export buttons into a single "Import/Export" secondary button** to keep the layout clean:
Screenshot 2025-07-25 at 21 28 48
2. Once opening the window, we can **keep the import and export content in different tabs**:

Screenshot 2025-07-25 at 21 36 06 Screenshot 2025-07-25 at 21 43 07

3. Instead of the separate "Download template" button, we can **seamlessly integrate the link** into the description text, while still being eye-catchy enough:
Screenshot 2025-07-25 at 21 54 14
4. We can have **a separate list of the tips** for filling in the template under the collapsible accordion, making it possible to mention more info there in a structured way:
Screenshot 2025-07-25 at 21 54 26
5. Right before importing, as a last step, would be great to have the selectors of the data that must be imported. Instead of cleaning the columns, this will allow users to quickly adjust what should be imported on-the-go:
Screenshot 2025-07-25 at 21 54 56
6. After import, let's show the success message to let users know that everything went well:
Screenshot 2025-07-25 at 22 00 49
7. I created a dedicated icon for the .csv data import, it's available in Figma. Please contact us at [[email protected]](mailto:[email protected]) email to discuss how we can collaborate on that so that you're able to view the Figma designs as well, to make the development easier for you. There's even a script to import the icon(s) from the UI Kit.
Screenshot 2025-07-25 at 22 05 18
8. Regarding the template:
   a) Having only one correct option (for activating the qualification) would make it easier to not mix things up. I’d say having “yes” would be user-friendly instead of more tech-minded "true" or "1". What do you think?
   b) Having emergency contacts Field service group (as number 1,2,3) would be also nice to have if possible. But here Haja would suggest better.
   c) Perhaps we can include 3-4 rows of dummy data to help users see how is it correct to fill it out? To show where 'yes' is enough, and where some other kind of input is required? Here's the slightly updated template that I think might be a bit more easier for users to understand and fill in correctly:
   [Template_with_Dates_Contacts_Groups-idea-v4.csv](https://github.com/user-attachments/files/21437627/Template_with_Dates_Contacts_Groups-idea-v4.csv)

9. What do you think about adding an ability to import .xlsx file as well? Since the export of the persons record is in this format, so it might be easier to restore a local copy. Or @rhahao maybe you see any better solutions like making the export in .csv too or any other good ideas?

Let me know your thoughts 🙂

@rhahao feel free to share your comments as well if you have any at this point

Hi @ux-git,

Thank you so much for your extensive and very helpful feedback from July 25th! I've done my best to implement the points you suggested.

Here is a summary of the changes:

  • Combined Import/Export Button: This is done. Import and Export are now consolidated into a single, unified button.
  • Export Functionality: To keep the scope of this pull request manageable, I haven't changed the export function itself for now. It works the same way it did before.
  • Field Selection via Checkboxes: I thought that if we allow field selection via checkboxes, it would be a good idea to enable this for all fields. To make this easier to manage, I've also added group checkboxes to control multiple fields at once. What do you think about this approach?
  • Sample Data & Configuration: Thank you for providing the sample data! I have incorporated it. The examples and the handling of each field during import are now controlled by a configuration array, which should make future extensions much easier.
  • Expanded Import Capabilities: It's now also possible to import emergency contacts and field service groups.
  • Control Values (yes, 1, true): I'd like to propose that we continue to allow not just yes but also 1 and true as control values for activating options. My reasoning is that CSV imports are often handled by more technically-inclined users who are very comfortable working with 1 or true. However, this is just my personal take, and it would be no problem to reduce it to only yes if you prefer.
  • Excel Support: Expanding the import to include Excel files is a great idea. I would be happy to tackle this in a future pull request, as the changes in this one have already become quite extensive.
  • Type Change for first_report: I had to allow null for the first_report date type. The reason is that the base schema for creating new persons pre-fills this property with null, and this change was necessary to avoid type conflicts.

I'm looking forward to any further feedback you might have

coderabbitai[bot]
coderabbitai bot previously approved these changes Nov 11, 2025
@nobodyzero1
Copy link
Author

Hello @ux-git !

Since I'm new to software development and open source contributions, I would appreciate some further feedback on the implementation if you have time.

Specifically, I would like to know if the overall architecture/design is the right direction. If so, I could proceed with expanding the functionality.

Thank you very much!

@ux-git
Copy link
Member

ux-git commented Nov 17, 2025

@nobodyzero1 awesome work done! From the UX design perspective it's great, thank you!

Some really minor styling comments after trying the live version:

Screenshot 2025-11-17 at 22 50 15
  1. We don't normally use the underline for text links, simply blue color is fine :)
  2. Could you remove the hover background for the Template filling tips? The whole area must remain clickable as it is, but without the background hover fill, to make the overall composition more simple
  3. What do you think about making the tips body text into 'body-small-regular' global text style? This will make the whole block more compact.
  4. Could you add the hover fill to the drag-and-drop area as done in tweak(components): add hover fill to congregation import #4647?

@rhahao please share your comments as well. Also, would you want to standartize the import and export formats? Currently as I can see the export is in xslx and import is in csv. Perhaps having both in csv would be more consistent? Or implementing both xslx and csv to be used based on user preference?

This commit implements several UI/UX adjustments to enhance consistency and simplicity:

- **Link Style:** Removed text link underlines, retaining blue color for visual distinction.
- **Template Tips Hover:** Removed background hover fill from the 'Template filling tips' area to simplify the composition, while maintaining clickability.
- **Text Style:** Updated 'Template filling tips' body text to use the 'body-small-regular' global style for a more compact block appearance.
- **Drag-and-Drop:** Added the standardized hover fill effect to the main drag-and-drop area for improved user feedback, consistent with congregation import (sws2apps#4647).
@sonarqubecloud
Copy link

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (3)
src/features/persons/import_export/index.tsx (3)

1-2: Combine React imports into a single statement

react is imported twice; consolidate into one import to satisfy Sonar and keep things tidy.

You can do:

-import { useState } from 'react';
+import React, { useState } from 'react';
@@
-import React from 'react';

This keeps the default React import available (for JSX/runtime) while avoiding duplicate imports.

Based on static analysis hints, this should clear the “react imported multiple times” warning.

Also applies to: 21-21


103-128: Prefer a real <button> element for the tips toggle header

The header is now keyboard-accessible with ARIA (good), but Sonar flags the role="button" pattern. Rendering this Box as a native <button> gives better semantics and built‑in keyboard behavior, letting you drop extra ARIA/handlers.

For example:

-              <Box
-                role="button"
-                aria-expanded={tipsExpanded}
-                aria-controls="tips-content"
-                tabIndex={0}
-                onClick={handleToggleTips}
-                onKeyDown={(e: React.KeyboardEvent<HTMLDivElement>) => {
-                  if (e.key === 'Enter' || e.key === ' ') {
-                    e.preventDefault();
-                    handleToggleTips();
-                  }
-                }}
-                sx={{
-                  display: 'flex',
-                  alignItems: 'center',
-                  gap: '8px',
-                  height: '24px',
-                  width: '100%',
-                  padding: 0,
-                  cursor: 'pointer',
-                  '&:focus-visible': {
-                    outline: '2px solid blue',
-                    outlineOffset: '2px',
-                  },
-                }}
-              >
+              <Box
+                component="button"
+                type="button"
+                aria-expanded={tipsExpanded}
+                aria-controls="tips-content"
+                onClick={handleToggleTips}
+                sx={{
+                  display: 'flex',
+                  alignItems: 'center',
+                  gap: '8px',
+                  height: '24px',
+                  width: '100%',
+                  padding: 0,
+                  border: 'none',
+                  background: 'transparent',
+                  textAlign: 'left',
+                  cursor: 'pointer',
+                  '&:focus-visible': {
+                    outline: '2px solid blue',
+                    outlineOffset: '2px',
+                  },
+                }}
+              >

This keeps UX the same, improves semantics, and removes the need for custom key handling.

Based on static analysis hints about using real button elements instead of role="button".


159-174: Drop role="region" from the tips list container

The collapsible content is rendered as a <ul> (via component="ul"), which already has clear list semantics. Adding role="region" on a list is unnecessary and is exactly what Sonar flags (it prefers a <section> for “regions”).

You can simply rely on the list semantics:

-                <Box
-                  className="body-small-regular"
-                  id="tips-content"
-                  role="region"
-                  component="ul"
+                <Box
+                  className="body-small-regular"
+                  id="tips-content"
+                  component="ul"

aria-controls="tips-content" on the header will still work fine without the extra role.

Based on static analysis hints around role="region" usage.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5589bea and 512e71d.

⛔ Files ignored due to path filters (2)
  • package-lock.json is excluded by !**/package-lock.json, !**/*.json
  • package.json is excluded by !**/*.json
📒 Files selected for processing (3)
  • CHANGELOG.md (1 hunks)
  • src/features/persons/import_export/import/index.tsx (1 hunks)
  • src/features/persons/import_export/index.tsx (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/features/persons/import_export/import/index.tsx
  • CHANGELOG.md
🧰 Additional context used
🧬 Code graph analysis (1)
src/features/persons/import_export/index.tsx (1)
src/features/congregation/settings/import_export/index.types.ts (1)
  • ImportExportType (1-4)
🪛 GitHub Check: SonarCloud Code Analysis
src/features/persons/import_export/index.tsx

[warning] 103-128: Use , , , , or instead of the "button" role to ensure accessibility across all devices.

See more on https://sonarcloud.io/project/issues?id=sws2apps_organized&issues=AZoN6JJ2Y0evts4bNunk&open=AZoN6JJ2Y0evts4bNunk&pullRequest=4326


[warning] 1-1: 'react' imported multiple times.

See more on https://sonarcloud.io/project/issues?id=sws2apps_organized&issues=AZoN6JJ2Y0evts4bNuni&open=AZoN6JJ2Y0evts4bNuni&pullRequest=4326


[warning] 159-174: Use

, or
instead of the "region" role to ensure accessibility across all devices.

See more on https://sonarcloud.io/project/issues?id=sws2apps_organized&issues=AZoQrJs9BntA-LHlk5pB&open=AZoQrJs9BntA-LHlk5pB&pullRequest=4326


[warning] 21-21: 'react' imported multiple times.

See more on https://sonarcloud.io/project/issues?id=sws2apps_organized&issues=AZoN6JJ2Y0evts4bNunj&open=AZoN6JJ2Y0evts4bNunj&pullRequest=4326

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Summary
🔇 Additional comments (1)
src/features/persons/import_export/index.tsx (1)

23-42: Hook wiring and overall component structure look good

The ImportExport component cleanly wires useImportExport, useTemplateDownload, date formatting, and dialog state; the public props align with the shared ImportExportType. Nothing stands out as risky here.

@nobodyzero1
Copy link
Author

nobodyzero1 commented Nov 26, 2025

Hi @ux-git !

Thank you very much for the thorough review and the positive feedback on the UX design! I have implemented all the minor styling adjustments requested:

  • Link Styling: Removed the underline for the text link; now the standard blue color is used.
  • Template Tips Hover: The background hover fill has been removed from the "Template filling tips" area to simplify the composition. The area remains fully clickable.
  • Tips Body Text Style: Updated the tips body text to use the 'body-small-regular' global text style, which makes the entire block more compact.
  • Drag-and-Drop Area: Added the standardized hover fill effect to the drag-and-drop area for improved visual feedback, consistent with PR tweak(components): add hover fill to congregation import #4647.

I have pushed the changes to the branch. Please let me know if any further changes are needed!

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.

2 participants