User Interface high complexity mobile
1
Dependencies
1
Dependents
1
Entities
0
Integrations

Description

Custom multi-select widget that enforces mutual exclusion rules between logically incompatible expense types (e.g. kilometre allowance and bus ticket for the same trip). Groups expense types by exclusive_groups catalogue field and prevents co-selection within the same group at the UI layer.

Feature: Travel & Expense Registration

expense-type-selector-widget

Summaries

The Expense Type Selector Widget enforces company expense policy directly at the point of data entry, preventing employees from submitting logically incompatible expense combinations — such as claiming both a kilometre allowance and a public transport ticket for the same journey. By catching these policy violations before submission rather than during finance review, the organization reduces the volume of rejected claims, accelerates reimbursement cycles, and lowers the administrative cost of manual auditing. The catalogue-driven design means policy updates can be applied centrally without requiring app code changes, giving the finance team direct control over compliance rules.

This widget carries high complexity primarily due to the mutual exclusion logic derived from the exclusive_groups catalogue field. It depends on the expense-type-catalogue-repository being stable and correctly populated before integration testing can begin. Any changes to the catalogue's group structure will require regression testing of all conflict-prevention paths. Testing scope must cover all valid and invalid type combinations, conflict warning display, and reset behaviour.

Since the widget is tightly coupled to catalogue data shape, coordinate with the team managing catalogue ingestion to agree on a stable schema early. The widget is used only within the expense registration flow, so its blast radius for changes is contained.

The Expense Type Selector Widget is a custom stateful mobile widget that consumes the expense-type-catalogue-repository to render a constrained multi-select list. On each selection event, disableConflictingTypes(selectedType, exclusiveGroups) queries the catalogue's exclusive_groups metadata and sets conflicting options to a disabled state, preventing co-selection at the UI layer before any BLoC or backend validation runs. The onSelectionChanged(selectedTypes) callback emits the current valid selection set upstream to the expense-form-bloc. Internal state tracks which types are selected and which are disabled to support resetSelection() correctly.

When evolving this widget, ensure catalogue schema changes are reflected in the group resolution logic to prevent silent conflicts slipping through.

Responsibilities

  • Render constrained list of expense type options from catalogue
  • Enforce exclusive_group rules by disabling incompatible options on selection
  • Emit selected type set on change for downstream validation
  • Display group conflict warnings when attempting invalid combinations

Interfaces

build(availableTypes, selectedTypes)
onSelectionChanged(selectedTypes)
disableConflictingTypes(selectedType, exclusiveGroups)
resetSelection()
getSelectedTypes()

Relationships

Dependencies (1)

Components this component depends on

Dependents (1)

Components that depend on this component

Related Data Entities (1)

Data entities managed by this component