Role of Thu Ngan
The cashier is the direct operator at the gaming kiosk counter. They use this app onDedicated Android tabletlocated at the cashier counter, acting as a bridge between the player's actual cash and the credits system.
Cash conversion → Credits
Receive cash from the player, enter the amount and payment method, the system automatically adds credits to the player's account.
Payment Credits → Cash
When the player wants to exchange credits for cash, the cashier processes the redeem order and spends money directly at the counter.
Count money according to face value
Each time you open a shift, close a shift, or recharge mid-shift, you require the amount of each denomination to be entered — ensuring accuracy and accountability.
Manage player accounts
Look up players by phone number or username. Create a new account if you don't have one — right at the counter, no need to leave.
Track case history
Review your entire shift list, including transaction totals, fund amounts, and delivery status.
Accountability
All transactions are recorded in shifts. Device fingerprint ensures each Android device is uniquely identified.
Work Shift Lifecycle
Each shift goes through 5 steps in a mandatory order. The app guides the cashier step by step and prevents any steps from being skipped.
Open a fund at the beginning of the shift
The cashier counts all the money in the safe before the shift starts. Enter the quantity of each denomination into the Denomination Grid. The system automatically calculates totals and creates new shift records.
Shift is active
Main working screen. Cashier searches for players, tops up credits, exchanges credits, creates new players. The transaction list of the shift is displayed in real time next to it.
Recharge mid-shift
When the safe needs more cash during the shift, the cashier records this refill using the Denomination Grid. Each cash drop is recorded with full face value details.
Closing funds at the end of shift
At the end of the shift, the cashier counts all the cash and enters it into the Denomination Grid. The system compares with the expected balance and records the difference (if any).
Shift handover
Transfer the shift to the next cashier. Handover records are saved including recipient information, notes, and cash drawer status.
* CashDropPage can be performed multiple times in one shift, it is not a mandatory step. The remaining steps must be in the correct order.
Denomination Grid — Money Counting Grid
DenominationGrid.tsxis the central component of the application — used on all 3 cash counting pages (Opening, Cash Drop, Closing). Supports 7 denominations of notes and 6 denominations of coins according to USD standards.
💵 Sheet of paper — BILL_DENOMINATIONS
🪙 Xu — COIN_DENOMINATIONS
Utils — denominations.ts
Reasons to use Denomination Grid
- Completely eliminate mental math — the cashier just needs to count the number of bills/coins
- The total amount is updated instantly when entering the quantity
- Detailed data by denomination is saved for audit purposes
- In accordance with industry standard treasury procedures
- Supports discrepancies detection when comparing Opening vs Closing
Trade with Players
ActiveShiftPage.tsxis the main working screen. The cashier handles all transactions with players from here — search, top up credits, exchange credits, create new accounts.
Credits (Deposit) Flow
cashierDepositCredits()
Credits Redeem Flow (Redeem)
cashierRedeemCredits()
Create New Player — cashierCreatePlayer()
Component PhoneInputfrom@kioskgaming/uiHandles international standard phone number formatting, cashiers don't need to worry about formatting.
Android Native with Capacitor 7
The app is packaged into an Android APK via Capacitor 7, running directly on a dedicated Android tablet located at the counter. This provides a native app experience while still developing with React/TypeScript.
@capacitor/android v7
Convert React web app to native Android APK. Unique codebase, deployed like a real Android app.
Device Fingerprint
deviceFingerprint.tsCreate unique Device ID for each Android device. Attach the device to the work shift.
CRACO Config
Create React App is extended via CRACO — adding aliases, Tailwind plugins, custom build configuration without eject.
Benefits of Android Native Shell
- WebView loads content from
server.urlremote — requires stable network - Device fingerprint UUID saved in localStorage, case mounted + device registration
- APK build via
npm run apk:dev/apk:prod+ gradlew - Package id:
club.kioskservice.kioskgaming.cashier - New devices require store management to browse in the Shop Portal
- CRACO patch source-map-loader from
packages/ui/scripts/
capacitor.config.ts
Build flow:
npm run build
→
npx cap sync android
→
npx cap run android
→ APK deployed to device
Security & Accountability
The cashier app handles the actual cash, so every layer of security and audit trail is a requirement, not optional.
CashierProtectedRoute
Every page is protected byCashierProtectedRoute.tsx. No valid session → redirect to login page.
useCashierAuth Hook
Separate hooksuseCashierAuth.tsxManage the cashier's authentication, token, and session state.
Device Fingerprint
deviceFingerprint.tsCreate an unforgeable Device ID. Each shift is tied to specific equipment.
Denomination Audit Trail
Every money count is saved in detail according to each denomination. History cannot be edited after submission — any discrepancies will be detected.
Shift Lifecycle Enforcement
Applications must go through in the correct order: Opening → Active → Closing → Handover. No step can be skipped.
axios Client
cashierApi.tsUse singleton axios with interceptor Bearer token and catch 401 → logout. Base URL included/api.
MyShiftsPage.tsx— Cashiers can view their entire shift history: fund amounts, total transactions, status, and handover time. This is a source of proof if there is a dispute over money.
Technical Stack
Services structure
All Pages
| File | Purpose |
|---|---|
| CashierLoginPage | Login cashier |
| OpeningCashPage | Count money to open a fund |
| ActiveShiftPage | Transactions in shifts |
| CashDropPage | Recharge mid-shift |
| ClosingCountPage | Count money to contribute to the fund |
| HandoverPage | Shift handover |
| MyShiftsPage | Shift history |
| Library / Tools | Version | Role |
|---|---|---|
| React | 18 | Main UI framework |
| TypeScript | 4.9 | Type safety for the entire codebase |
| CRACO | — | Extend CRA config (aliases, plugins) does not eject |
| Capacitor | 7 | Android native shell — packages React into an APK |
| @capacitor/android | v7 | Android platform bridge |
| react-hook-form | v7 | Form validation (login, create player, reset password) |
| react-hot-toast | — | Toast notifications for successful/failed transactions |
| Tailwind CSS | 3 | Styling utility-first |
| @kioskgaming/ui | file:../packages/ui | Modal, PhoneInput — shared UI (symlink packages/ui) |
| @kioskgaming/page-loading | file:../packages/page-loading | PageLoadingIndicator for route guard |
| axios | ^1.3 | HTTP client singleton + interceptors |
Components Share