Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
70 commits
Select commit Hold shift + click to select a range
33c23f3
feat(ui): implement reusable SearchBar component
nancymuyeh Sep 17, 2025
dadff60
feat(ui): implement reusable SearchBar component
nancymuyeh Sep 17, 2025
02fdf91
feat(ui): implement reusable SearchBar component
nancymuyeh Sep 18, 2025
07f3c4a
feat(ui): implement reusable SearchBar component
nancymuyeh Sep 18, 2025
581d387
Merge branch 'main' into 31-design-and-implement-shared-reusable-sear…
nancymuyeh Sep 18, 2025
62a576d
fix(ui): mark SearchBar component prop as read-only
nancymuyeh Sep 18, 2025
0f3de59
Merge branch '31-design-and-implement-shared-reusable-search-bar-comp…
nancymuyeh Sep 18, 2025
d886154
fix(ui): increase test coverage
nancymuyeh Sep 18, 2025
b198f93
Merge branch 'main' into 31-design-and-implement-shared-reusable-sear…
nancymuyeh Sep 18, 2025
190f0b3
fix(ui): increase test coverage
nancymuyeh Sep 18, 2025
a24a3d9
fix(ui): refactor useSearchBar hook with extracted helper functions f…
nancymuyeh Sep 18, 2025
a74f693
fix(ui): refactor useSearchBar hook with extracted helper functions f…
nancymuyeh Sep 18, 2025
390b514
Update packages/ui/src/components/SearchBar/SearchBar.view.tsx
nancymuyeh Sep 18, 2025
7f2e481
fix(ui): refactor useSearchBar component for SonarQube compliance
nancymuyeh Sep 19, 2025
5f5396c
fix(ui): refactor useSearchBar component for SonarQube compliance
nancymuyeh Sep 19, 2025
216d993
fix(ui): refactor SearchBar component for SonarQube compliance
nancymuyeh Sep 19, 2025
e04b8bd
fix(ui): refactor SearchBar component for SonarQube compliance
nancymuyeh Sep 19, 2025
3328a72
chore(ui): merge main
nancymuyeh Sep 19, 2025
89b66c6
fix(ui): refactor SearchBar component for SonarQube compliance
nancymuyeh Sep 19, 2025
1161ec1
fix(ui): refactor SearchBar component with more simplifies functionality
nancymuyeh Sep 19, 2025
cd8acd7
fix(ui): update searchbar variants and styling
nancymuyeh Sep 19, 2025
1e6e858
fix(ui): remove unused dependencies
nancymuyeh Sep 19, 2025
103e6c8
fix(ui): remove unused dependencies
nancymuyeh Sep 22, 2025
0cd4017
fix(ui): update searchbar componenet to use global styling from style…
nancymuyeh Sep 22, 2025
8ba9f4b
Merge branch 'main' into 31-design-and-implement-shared-reusable-sear…
nancymuyeh Sep 22, 2025
e885bf6
fix(ui): fix minor lint issue
nancymuyeh Sep 22, 2025
9d2d22f
fix(ui): merge main
nancymuyeh Sep 22, 2025
eafd972
Merge branch 'main' into 31-design-and-implement-shared-reusable-sear…
nancymuyeh Sep 22, 2025
e096608
feat(cashier-app): implement multi-account transactions, UI refinemen…
NkwaTambe Sep 23, 2025
5180f42
feat(cashier-app): implement multi-account transactions, UI refinemen…
NkwaTambe Sep 23, 2025
b47d432
feat(cashier-app): implement multi-account transactions, UI refinemen…
NkwaTambe Sep 23, 2025
ff7ba22
refactor(cashier-app): use shared Button component in ClientDetails view
NkwaTambe Sep 23, 2025
90075f8
docs(api): document fineract api services for cashier-app
NkwaTambe Sep 23, 2025
7218016
fix(ui): correct responsive layout for AppLayout and Navbar
NkwaTambe Sep 24, 2025
7188495
refactor(ui): remove Settings from cashier sidebar menu
NkwaTambe Sep 24, 2025
4832b78
refactor(ui): update ui
NkwaTambe Sep 24, 2025
27f6007
refactor(ui): update dashboad
NkwaTambe Sep 24, 2025
dbb9f3f
refactor(ui): update dashboad
NkwaTambe Sep 24, 2025
537fbd8
fix(codegen): suppress TypeScript errors in generated files via post-…
NkwaTambe Sep 24, 2025
99339db
fix(sonarqube): fix oeprator issues
NkwaTambe Sep 24, 2025
06f1ed8
fix(dashboard): remove unneccessary prop definitions
NkwaTambe Sep 25, 2025
81620e1
fix(clientDetails): add more fields to cashier ( phone number and ema…
NkwaTambe Sep 25, 2025
f047a3c
fix(ui): resolve sidebar overlapping navbar in AppLayout by refactori…
NkwaTambe Sep 25, 2025
32993d0
feat(cashier): add receipt number to transaction form and optimize qu…
NkwaTambe Sep 26, 2025
d9ce089
refactor(cashier-app): remove all client-side auth logic for proxy ha…
NkwaTambe Oct 2, 2025
e256fef
feat(cashier-app): fetch detailed cashier transactions
NkwaTambe Oct 8, 2025
7cb4559
feat(cashier-app): fetch detailed cashier transactions
NkwaTambe Oct 8, 2025
426917d
refactor(cashier-app): migrate date formatting to date-fns and remove…
NkwaTambe Oct 8, 2025
4836672
feat(cashier-app): redesign cashier transaction summary view to a sin…
NkwaTambe Oct 8, 2025
01fd217
perf(cashier-app): cache static data in useCashierTransactionSummary …
NkwaTambe Oct 9, 2025
80423d7
fix: correctly parse client name from transaction note
NkwaTambe Oct 9, 2025
766ebf4
perf: cache client image data indefinitely
NkwaTambe Oct 9, 2025
4e050d2
feat(cashier-app): implement proxy-based OIDC logout
NkwaTambe Oct 9, 2025
6c26501
feat(cashier-app): search now uses account number and calls SavingsAc…
NkwaTambe Oct 13, 2025
8ddd934
feat(cashier-app): display backend developer message on client search…
NkwaTambe Oct 13, 2025
6d974c9
feat(cashier-app): add Docker and CI for production deployment
NkwaTambe Oct 13, 2025
bc27af1
ci(cashier-app): correct workflow trigger paths
NkwaTambe Oct 13, 2025
f795a35
fix(ci): resolve docker build error due to uppercase image name
NkwaTambe Oct 13, 2025
feb494e
ci(cashier-app): correct workflow trigger paths
NkwaTambe Oct 13, 2025
a3305fd
ci(cashier-app): correct workflow trigger paths
NkwaTambe Oct 13, 2025
22eb2d7
fix(docker): correct COPY paths for root build context
NkwaTambe Oct 13, 2025
f74fc2d
fix(docker): copy fineract.json before pnpm install
NkwaTambe Oct 13, 2025
6b5d276
fix(docker): defer postinstall scripts until after source copy
NkwaTambe Oct 13, 2025
229d7a9
feat: refactor currency display to use dynamic currency codes from th…
NkwaTambe Oct 14, 2025
6a68177
feat(cashier-app): correct client search navigation for multiple acco…
NkwaTambe Oct 14, 2025
ef1605f
feat(cashier-app): added logo
NkwaTambe Oct 14, 2025
39058ff
feat(ui, cashier-app): allow sidebar logo customization
NkwaTambe Oct 14, 2025
8dd79b9
feat(cashier-app): update transaction form and improve client search …
NkwaTambe Oct 15, 2025
980a945
feat: disable deposit and withdraw buttons for inactive clients
NkwaTambe Oct 16, 2025
6fbc107
feat(cashier): implement on-demand loading for the transaction summary
NkwaTambe Oct 20, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 39 additions & 0 deletions .github/workflows/deploy-cashier-app.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
name: Build and Push Cashier App Image

on:
push:
branches:
- feat/cashier-app-transactions-ui-ux
paths:
- 'frontend/cashier-app/**'
- '.github/workflows/deploy-cashier-app.yml'

env:
REGISTRY: ghcr.io
IMAGE_NAME: adorsys-gis/fineract-apps/cashier-app

jobs:
build-and-push:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write

steps:
- name: Checkout repository
uses: actions/checkout@v3

- name: Log in to the GitHub Container Registry
uses: docker/login-action@v2
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Build and push Docker image
uses: docker/build-push-action@v4
with:
context: .
file: ./frontend/cashier-app/Dockerfile
push: true
tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest, ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }}
106 changes: 106 additions & 0 deletions cashier-app-reasoning.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
# Cashier App Epic: Design and Implementation Journey

## 1. Project Overview

This document outlines the development plan and chronicles the implementation of the **Cashier Application**, a core tool for frontline staff to manage client cash transactions efficiently and securely. The application provides key functionality, including secure authentication, client account access, and seamless handling of deposit and withdrawal operations.

The primary goal is to ensure a smooth user experience for cashiers while maintaining system integrity, data accuracy, and compliance with security standards. All development is based on the existing monorepo architecture, leveraging shared UI components and the Fineract API client.

## 2. Authentication Strategy and Debugging

For the initial phase of development, we implemented a basic authentication mechanism using the default Fineract credentials (`username: mifos`, `password: password`). This allowed us to focus on core application features without the immediate complexity of third-party integration. The long-term plan is to integrate **Keycloak** for robust, single sign-on (SSO) authentication.

### Authentication Implementation and Debugging

During development, we encountered a persistent `400 Bad Request` error when communicating with the Fineract backend. This issue blocked all progress on features requiring API interaction.

**Problem Diagnosis:**

The API calls were failing because they were missing two critical HTTP headers required by the Fineract platform:
1. **`Authorization`**: Containing the user's credentials, Base64 encoded (`Basic <token>`).
2. **`Fineract-Platform-TenantId`**: Identifying the specific tenant (`default`).

**Solution:**

We implemented a centralized authentication mechanism using an API interceptor. This approach ensures every outgoing request is automatically populated with the necessary headers.

1. **API Client Configuration**: We leveraged the `OpenAPI` configuration object from the `@fineract-apps/fineract-api` package.
2. **Request Interceptor**: We added a request interceptor in the application's entry point (`frontend/cashier-app/src/main.tsx`).
3. **Header Injection**: Inside the interceptor, we retrieve the user's authentication state from the `authStore` and inject the `Authorization` and `Fineract-Platform-TenantId` headers.

**Temporary Login Bypass:**

To facilitate development, we implemented a temporary login bypass in the dashboard's logic (`useDashboard.ts`). This involves programmatically calling the `login` function with a hardcoded, valid authentication token (`bWlmb3M6cGFzc3dvcmQ=`) when the component mounts. This temporary solution will be removed once the final login functionality is implemented.

## 3. Core Features & Implementation Journey

The development was broken down into the following tasks:

### Task 1: Secure Login (Phase 1 Complete)

- **Description**: As a Cashier, I want to securely log in to the application.
- **Implementation**: A login form will be created. For now, a temporary login bypass is in place to facilitate development of other features.

### Task 2: View Client Account Details (Complete)

- **Description**: As a Cashier, I want to view a client's basic account details to verify their identity.
- **Implementation**:
1. **Client Search**: A client search feature was implemented on the dashboard. The search query is stored in the URL's search parameters, making the search state bookmarkable and shareable.
2. **Client Details Page**: A dynamic route (`/clients/$clientId`) was created to display the details of a specific client. This page fetches and displays the client's information, including their name, account number, and status.
3. **UI/UX Refinements**: The client details page was iteratively refined based on feedback, including layout adjustments and the addition of "Deposit" and "Withdrawal" buttons. A significant performance enhancement was implemented to prevent the client's image from blocking the rendering of the main content. The page now loads instantly, with a dedicated loading state for the image.

### Task 3: Deposit Cash (Complete)

- **Description**: As a Cashier, I want to deposit cash into a client's account.
- **Implementation**: A "Deposit" button on the client details page opens a modal form for the transaction. The form includes robust error handling, provides clear feedback on submission and success, and is connected to the Fineract API.

### Task 4: Withdraw Cash (Complete)

- **Description**: As a Cashier, I want to withdraw cash from a client's account.
- **Implementation**: The same transaction form is used for withdrawals. The logic dynamically adjusts the API call and user feedback based on the transaction type. Specific API errors, such as "insufficient balance," are now handled gracefully and displayed to the user.

## 4. Architectural Evolution: The Container/Hook/View Pattern

A significant part of our development process involved a major refactoring to align with the project's established **Container/Hook/View** architectural pattern. This pattern enforces a strict separation of concerns, making the codebase more modular, maintainable, and testable.

- **Initial Implementation**: Initially, some business logic was placed directly within the route components.
- **Refactoring**: We refactored the `Dashboard` and `ClientDetails` components to adhere to the pattern:
- **Hook (`use*.ts`)**: All business logic, state management, and API calls were moved into custom hooks (e.g., `useDashboard.ts`, `useClientDetails.ts`).
- **View (`*.view.tsx`)**: The view components were made purely presentational, receiving all data and functions as props.
- **Container (`index.tsx`)**: The container component is responsible for calling the hook and passing the results to the view.
- **Route (`/routes/...`)**: The route files are now responsible only for defining the route and rendering the container component.

This refactoring has resulted in a much cleaner and more scalable architecture.

## 6. Multi-Account Architecture and Data Fetching Refactor

A pivotal moment in the application's development was the realization that the initial design had two significant limitations: it only handled a client's first savings account, and it couldn't display the account balance due to a limitation in the API. This prompted a major architectural refactoring.

### The Problem: Single-Account Focus and Missing Data

1. **Multi-Account Requirement**: The initial implementation incorrectly assumed a client would only have one savings account. The design needed to be extended to support clients with multiple accounts.
2. **API Limitation**: We discovered that the API endpoint used to fetch the list of a client's accounts (`GET /clients/{id}/accounts`) returns a summary view that **does not include the `accountBalance`**. To retrieve the balance, a separate, more detailed API call (`GET /savingsaccounts/{id}`) is required for each individual account.

### The Solution: The "Smart" Child Component Pattern

To address these challenges, we implemented the **"Smart" Child Component** pattern.

1. **`SavingsAccountCard` Component**: We created a new, self-contained component called `SavingsAccountCard`.
2. **Delegated Data Fetching**: This component is responsible for its own data. It receives a `savingsAccountId` as a prop and uses its own internal hook (`useSavingsAccountCard`) to make a specific API call to fetch the detailed information for that single account, including its balance.
3. **Parent Component Update**: The main `ClientDetails` component was updated to simply map over the list of accounts and render a `SavingsAccountCard` for each one.

This architectural shift not only solved the immediate problem of the missing balances but also resulted in a more robust, scalable, and encapsulated design that correctly handles the multi-account requirement.

## 7. Development Roadmap (Updated)

The development has proceeded in the following order:

1. **Project Setup**: Established the basic file structure for the `cashier-app`. (Complete)
2. **Authentication & API Integration**: Set up the API interceptor and temporary login bypass. (Complete)
3. **Client Search & Details**: Developed the client search functionality and the account details view. (Complete)
4. **Architectural Refactoring**: Refactored the `Dashboard` and `ClientDetails` components to the Container/Hook/View pattern. (Complete)
5. **Responsiveness**: Made the application layout responsive. (Complete)
6. **Deposit & Withdrawal**: Implement the deposit and withdrawal forms and connect them to the Fineract API. (Complete)
7. **Multi-Account Refactoring**: Refactored the `ClientDetails` page to support multiple savings accounts and implemented the "Smart" Child Component pattern to fetch and display account balances correctly. (Complete)
8. **Documentation**: Create and update detailed documentation for the architecture, API integration, and transaction flow. (Complete)
9. **Finalize Authentication**: Remove the temporary login bypass and integrate with Keycloak. (Next)
3 changes: 2 additions & 1 deletion docs/fineract-api-codegen-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ The process uses the `@7nohe/openapi-react-query-codegen` tool to read an OpenAP
1. **API Specification**: A local copy of the Fineract OpenAPI spec is stored in `packages/fineract-api/fineract.json`.
2. **Codegen Script**: The `codegen` script in `packages/fineract-api/package.json` runs the generator tool.
3. **Output**: The tool generates a complete TypeScript client in the `packages/fineract-api/src/generated/` directory.
4. **Exports**: The main `packages/fineract-api/src/index.ts` file exports all the generated code, making it available to other packages in the monorepo.
4. **Post-processing**: After generation, the `scripts/add-ts-nocheck.mjs` script is executed. This script recursively finds all generated `.ts` files and adds a `// @ts-nocheck` comment at the top. This is a necessary workaround to suppress TypeScript errors that arise from the generated code, as excluding the directory in `tsconfig.json` was not effective.
5. **Exports**: The main `packages/fineract-api/src/index.ts` file exports all the generated code, making it available to other packages in the monorepo.

## 3. Workflow: Updating the API Client

Expand Down
Loading
Loading