A multi-role, real-time cash collection and reconciliation system
for ARY Financial Services merchant alliances.
ARY Cash Collection Portal manages the complete lifecycle of physical cash collected from customers at merchant kiosks, converting it into ARY Wallet top-ups, and tracking it through recovery to final bank deposit — with full reconciliation at every stage.
Customer (Cash Payment)
│
▼
BDO at Kiosk ──────────► ARY Wallet Top-Up (SC / BookGold / ...)
│
▼
Recovery Officer ────────► Physical Cash Pickup from BDO
│
▼
Accounts Department ──────► Bank Deposit + Reconciliation
- Firebase Email/Password authentication
- Role-based routing — each role has a fully isolated dashboard
- Four access levels: Admin, BDO, Recovery Officer, Accounts
- Merchant management — add, edit, deactivate business alliance partners
- Kiosk management — locations linked to merchants
- User management — create users, assign roles and kiosks
- Top-up Types — dynamically manage wallet service types (SC, BookGold, and any future type)
- Reports — date-range reports with CSV export
- Dashboard — 7-day collection chart with live stats
- New cash entry form — amount, top-up type, wallet number, customer name
- Personal transaction history with status filters
- Dashboard showing today's totals and pending recovery balance
- All pending cash grouped by kiosk location
- Bulk-select transactions and mark as collected in a single action
- Full collection history with deposit status
- View all collected cash pending bank deposit
- Select collections and record deposit with bank name and slip number
- Complete deposit history
- Reconciliation — gap analysis across BDO entries, recoveries, and deposits
- Real-time updates via Firestore
onSnapshotlisteners - Responsive layout — desktop and mobile
- Transaction status chain:
pending→collected→deposited
| Layer | Technology |
|---|---|
| Frontend Framework | React 18 + Vite 6 |
| Styling | Tailwind CSS 3 |
| Database | Firebase Firestore |
| Authentication | Firebase Authentication |
| Routing | React Router v6 |
| Forms | React Hook Form |
| Charts | Recharts |
| Icons | Lucide React |
| Notifications | React Hot Toast |
| Date Utilities | date-fns |
- Node.js
>= 18.x - npm
>= 9.x - A Firebase project with Firestore and Authentication enabled
git clone https://github.com/techpeer-pk/occapp-cx.git
cd occapp-cxnpm install- Open Firebase Console and create a new project
- Navigate to Authentication → Sign-in method → enable Email/Password
- Navigate to Firestore Database → Create database → Start in test mode
- Go to Project Settings → Your apps → Add Web App → copy the config object
cp .env.example .envEdit .env with your Firebase project values:
VITE_FIREBASE_API_KEY=your_api_key
VITE_FIREBASE_AUTH_DOMAIN=your_project.firebaseapp.com
VITE_FIREBASE_DATABASE_URL=https://your_project-default-rtdb.firebaseio.com
VITE_FIREBASE_PROJECT_ID=your_project_id
VITE_FIREBASE_STORAGE_BUCKET=your_project.appspot.com
VITE_FIREBASE_MESSAGING_SENDER_ID=your_sender_id
VITE_FIREBASE_APP_ID=your_app_idIn Firebase Console — Authentication tab:
Add a user with email and password, then copy the generated UID.
In Firestore — users collection:
Create a document with the UID as the document ID:
{
"uid": "paste-uid-here",
"name": "Admin User",
"email": "admin@example.com",
"role": "admin",
"active": true
}npm run devnpm run build
npm run previewoccapp-cx/
├── public/
├── src/
│ ├── firebase/
│ │ └── config.js Firebase initialization
│ ├── context/
│ │ └── AuthContext.jsx Auth state and profile management
│ ├── layouts/
│ │ ├── AdminLayout.jsx
│ │ ├── BDOLayout.jsx
│ │ ├── RecoveryLayout.jsx
│ │ └── AccountsLayout.jsx
│ ├── pages/
│ │ ├── Login.jsx
│ │ ├── admin/
│ │ │ ├── Dashboard.jsx Live stats and 7-day chart
│ │ │ ├── Merchants.jsx CRUD — merchant management
│ │ │ ├── Kiosks.jsx CRUD — kiosk management
│ │ │ ├── Users.jsx CRUD — user and role management
│ │ │ ├── TopupTypes.jsx Dynamic top-up type management
│ │ │ └── Reports.jsx Date-range reports with CSV export
│ │ ├── bdo/
│ │ │ ├── Dashboard.jsx Summary and recent transactions
│ │ │ ├── NewTransaction.jsx Cash entry form
│ │ │ └── Transactions.jsx Full transaction history
│ │ ├── recovery/
│ │ │ ├── Dashboard.jsx Pending overview grouped by kiosk
│ │ │ ├── PendingPickups.jsx Bulk collection marking
│ │ │ └── History.jsx Collection history
│ │ └── accounts/
│ │ ├── Dashboard.jsx Awaiting deposit and recent deposits
│ │ ├── Deposits.jsx Bank deposit recording
│ │ └── Reconciliation.jsx Gap analysis across all stages
│ ├── App.jsx Routes and role-based guards
│ ├── main.jsx
│ └── index.css Tailwind base and custom utilities
├── .env.example
├── .gitignore
├── tailwind.config.js
├── vite.config.js
└── package.json
| Role | Access |
|---|---|
| Admin | Full access — merchants, kiosks, users, top-up types, reports, dashboard |
| BDO | New cash entry, own transaction history and summary |
| Recovery Officer | Pending pickups, bulk collection, own collection history |
| Accounts | Record bank deposits, full reconciliation view |
| Collection | Purpose |
|---|---|
users |
User profiles with roles and kiosk assignments |
merchants |
Business alliance merchant records |
kiosks |
Kiosk locations linked to merchants |
topupTypes |
Wallet top-up service types — admin-managed |
transactions |
BDO cash entries — status: pending → collected → deposited |
collections |
Recovery officer pickup records |
deposits |
Bank deposit records with slip numbers |
BDO Entry Recovery Officer Accounts
───────── ──────────────── ────────
pending ───► collected ───► deposited
| Command | Description |
|---|---|
npm run dev |
Start development server on localhost:5173 |
npm run build |
Build for production |
npm run preview |
Preview production build locally |
npm run lint |
Run ESLint |
.envis gitignored — Firebase credentials are never committed- Update Firestore security rules before deploying to production
Recommended Firestore Rules:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /users/{userId} {
allow read: if request.auth != null;
allow write: if request.auth != null &&
get(/databases/$(database)/documents/users/$(request.auth.uid)).data.role == 'admin';
}
match /transactions/{id} {
allow read, write: if request.auth != null;
}
match /collections/{id} {
allow read, write: if request.auth != null;
}
match /deposits/{id} {
allow read, write: if request.auth != null;
}
match /{document=**} {
allow read, write: if request.auth != null;
}
}
}- Fork the repository
- Create a feature branch —
git checkout -b feature/your-feature - Commit your changes —
git commit -m 'Add your feature' - Push to the branch —
git push origin feature/your-feature - Open a Pull Request
Released under the MIT License.