fix: form email validation
This commit is contained in:
parent
34573cf3ab
commit
1d57bf042f
10
.agents/rules/build_on_change.md
Normal file
10
.agents/rules/build_on_change.md
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
---
|
||||||
|
name: build-after-changes
|
||||||
|
description: Always run the build command and verify it passes after making any code changes.
|
||||||
|
---
|
||||||
|
|
||||||
|
# Build on Change
|
||||||
|
|
||||||
|
Whenever you finish making code changes to the project:
|
||||||
|
1. You MUST automatically run the build command (e.g., `npm run build` or `npm run typecheck` depending on the project configuration) to verify that the changes do not introduce any compilation or type errors.
|
||||||
|
2. If the build command fails, you MUST investigate and fix those build errors before concluding your task or presenting the final code to the user.
|
||||||
198
README.md
198
README.md
@ -1,70 +1,166 @@
|
|||||||
# Krishna Sales
|
# Krishna Sales Mobile App
|
||||||
|
|
||||||
Field-sales console for **Zino sandbox app 434**. A Vite + React + TypeScript SPA that browses the app's three workflows (Order Booking, Store, Daily Reports) over the Zino gateway.
|
This is a Progressive Web App (Pwa) built for the Krishna Sales team.
|
||||||
|
|
||||||
- **Base URL:** `https://sandbox.getzino.in`
|
## Version
|
||||||
- **Stack:** React 19 · TypeScript · Vite 8 · Tailwind v4 · react-router v7 · lucide-react
|
**1.0.2**
|
||||||
|
|
||||||
## Getting started
|
## Sitemap
|
||||||
|
|
||||||
```bash
|
### Public Routes
|
||||||
npm install
|
- `/login` - User Authentication
|
||||||
npm run dev # http://localhost:5173
|
|
||||||
|
### Authenticated Routes (Console)
|
||||||
|
These routes require the user to be logged in. Roles determine access.
|
||||||
|
|
||||||
|
#### Daily Logs
|
||||||
|
- `/daily` - My Daily Logs (Sales Officer, Manager, Admin)
|
||||||
|
- `/daily/:instanceId` - View specific daily log
|
||||||
|
- `/all-daily` - All Daily Logs (Manager, Admin)
|
||||||
|
- `/all-daily/:instanceId` - View specific daily log from all
|
||||||
|
|
||||||
|
#### Orders
|
||||||
|
- `/orders` - View Orders (Sales Officer, Manager, Admin)
|
||||||
|
- `/orders/:instanceId` - View specific order
|
||||||
|
|
||||||
|
#### Calls
|
||||||
|
- `/calls` - View Calls (Sales Officer, Manager, Admin)
|
||||||
|
- `/calls/:instanceId` - View specific call
|
||||||
|
|
||||||
|
#### Stores
|
||||||
|
- `/stores` - View Stores (Sales Officer, Manager, Admin)
|
||||||
|
- `/stores/:instanceId` - View specific store
|
||||||
|
|
||||||
|
#### Reports & Analytics
|
||||||
|
- `/analytics` - Analytics Dashboard (Sales Officer, Manager, Admin)
|
||||||
|
- `/sales-report` - Daily Sales Report (Manager, Admin)
|
||||||
|
|
||||||
|
#### Admin
|
||||||
|
- `/admin/users` - Manage Users (Manager, Admin)
|
||||||
|
- `/admin/datasets` - Manage Datasets (Admin Only)
|
||||||
|
- `/admin/datasets/:id` - Manage Dataset Items (Admin Only)
|
||||||
|
|
||||||
|
## Architecture & Workflows (How Things Work)
|
||||||
|
|
||||||
|
This app interfaces with a generic backend platform via `ZinoClient` (see `src/api/client.ts`). The business logic is driven by configuring Workflows, Activities, and Views.
|
||||||
|
|
||||||
|
### 1. Workflows
|
||||||
|
The app is divided into three primary Workflows, mapped out in `src/api/config.ts`:
|
||||||
|
- **ORDER_BOOKING**: Manages everything from logging a visit, taking an order, to closing an order.
|
||||||
|
- **STORE**: Manages the creation and editing of stores/retailers.
|
||||||
|
- **DAILY_REPORTS**: Manages the Sales Officer's daily punch-in (Day Plan) and punch-out (End of Day report).
|
||||||
|
|
||||||
|
Each workflow has a unique `workflowUuid` and `versionUuid`.
|
||||||
|
|
||||||
|
### 2. How to Add or Start a New Instance
|
||||||
|
When a user submits a form to create something new (e.g., adding a new Store or starting a new Daily Log), the app "starts an instance" of that specific workflow.
|
||||||
|
|
||||||
|
1. **Instantiate the Client**: A `ZinoClient` is created for the specific workflow.
|
||||||
|
```typescript
|
||||||
|
const client = new ZinoClient(BASE_URL, STORE.workflowUuid);
|
||||||
|
```
|
||||||
|
2. **Start the Instance**: The app calls the API to begin the first activity (e.g., `INIT` activity) with the form payload.
|
||||||
|
```typescript
|
||||||
|
const res = await client.startInstance(
|
||||||
|
STORE.activities.INIT.uid,
|
||||||
|
payload,
|
||||||
|
{ version_uuid: STORE.versionUuid }
|
||||||
|
);
|
||||||
|
```
|
||||||
|
3. **Progressing the Instance**: If the workflow has multiple steps (like Order Booking, which progresses from `LOG_VISIT` to `PLACE_ORDER` to `CLOSE_ORDER`), subsequent updates use `progressInstance` with the existing `instance_id`.
|
||||||
|
```typescript
|
||||||
|
const res = await client.progressInstance(
|
||||||
|
instanceId,
|
||||||
|
ORDER_BOOKING.activities.PLACE_ORDER.uid,
|
||||||
|
payload
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Views (Listing Data)
|
||||||
|
To display lists of data (like the tables on the `/orders` or `/stores` pages), the app queries "Record Views" configured on the backend.
|
||||||
|
```typescript
|
||||||
|
const data = await client.listInstances(STORE.recordViews.STORE, filters);
|
||||||
```
|
```
|
||||||
|
These views return tabular data containing the latest state of all instances in that workflow.
|
||||||
|
|
||||||
Sign in with your sandbox credentials (email / password, optional org id). The JWT is stored in `localStorage` and shared across all three workflow clients.
|
### 4. Workflows Deep Dive & Activity Chains
|
||||||
|
|
||||||
Other scripts:
|
#### 4.1 Order Booking Workflow
|
||||||
|
Manages the end-to-end process of visiting a store and taking an order.
|
||||||
|
**Activity Chain:**
|
||||||
|
`LOG_VISIT` ➔ `PLACE_ORDER` ➔ `EDIT_ORDER` ➔ `PRODUCTIVITY_OF_VISIT` ➔ `POTENTIAL_MINING` ➔ `CLOSE_ORDER`
|
||||||
|
|
||||||
```bash
|
- **LOG_VISIT (Init)**
|
||||||
npm run build # tsc -b && vite build → dist/
|
- Fields: `select_store` (wf_lookup), `date_of_visit` (date), `time_of_visit` (time), `upload_image` (image)
|
||||||
npm run preview # serve the production build
|
- **PLACE_ORDER**
|
||||||
npm run lint # eslint
|
- Fields: `date_of_order` (date), `order_details` (grid), `total_bags` (number), `total_kgs` (number)
|
||||||
```
|
- **EDIT_ORDER**
|
||||||
|
- Fields: Same as Place Order, allowing modifications before closure.
|
||||||
|
- **PRODUCTIVITY_OF_VISIT**
|
||||||
|
- Fields: `is_productive_call` (radio), `store_status` (select), `order_received_channel` (select), `remarks` (longtext), `action` (radio)
|
||||||
|
- **POTENTIAL_MINING**
|
||||||
|
- Fields: `potential` (grid - tracks actual potential vs ordered)
|
||||||
|
- **CLOSE_ORDER**
|
||||||
|
- Fields: `remarks_2` (longtext)
|
||||||
|
|
||||||
## Workflows (app 434)
|
#### 4.2 Store Workflow
|
||||||
|
Manages onboarding and updating retailers in the system.
|
||||||
|
**Activity Chain:**
|
||||||
|
`INIT` ➔ `EDIT_STORE`
|
||||||
|
|
||||||
The app has three workflows, each with its own `workflow_uuid` (shared `APP_ID` 434). One `ZinoClient` is bound per workflow.
|
- **INIT (Store Creation)**
|
||||||
|
- Fields: `business_name_2` (text), `area_2` (text), `complete_address_2` (longtext), `pin_code_2` (number), `owner_name_2` (text), `phone_number_2` (phone), `email_2` (email), `store_location_2` (geolocation), `store_image_2` (image), `route_name_2` (select), `route_code_2` (select), `sub_route_2` (select), `distributor_name_2` (select), `distributor_owner_name_2` (text), `distributor_email_2` (email), `distributor_phone_number_2` (phone), `notes_2` (longtext), `potential_2` (grid)
|
||||||
|
- **EDIT_STORE**
|
||||||
|
- Fields: Matches the INIT fields (uses `_3` suffix) to allow updates to store metadata.
|
||||||
|
|
||||||
| Slug (`config.ts`) | UI | Record views | Detail views |
|
#### 4.3 Daily Reports Workflow
|
||||||
| --- | --- | --- | --- |
|
Tracks Sales Officer attendance, daily planning, and end-of-day reports.
|
||||||
| `orderBooking` | Order Booking | Orders, Calls | Orders, Calls |
|
**Activity Chain:**
|
||||||
| `store` | Store | Store | Store |
|
`INIT` (Day Plan) ➔ `PUNCH_OUT` (EOD)
|
||||||
| `dailyReports` | Daily Reports | Daily Logs | Daily Logs |
|
|
||||||
|
|
||||||
All ids live in `src/api/config.ts`, sourced from the API docs in `src/docs/api/`.
|
- **INIT (Punch In)**
|
||||||
|
- Fields: `sales_officer_name` (app_user), `date` (date), `time` (time), `route_code` (select), `sub_route` (select), `store_image` (image), `day_plan_notes` (longtext)
|
||||||
|
- **PUNCH_OUT (Punch Out)**
|
||||||
|
- Fields: `total_productive_calls` (number), `total_non_productive_calls` (number), `eod_notes_remarks` (longtext)
|
||||||
|
|
||||||
## Structure
|
#### 4.4 User Management Workflow
|
||||||
|
Manages Sales Officers and their credentials.
|
||||||
|
**Activity Chain:**
|
||||||
|
`ADD_USER` ➔ `EDIT_USER`
|
||||||
|
|
||||||
```
|
- **ADD_USER**
|
||||||
src/
|
- Fields: `name` (text), `email` (email), `password` (password)
|
||||||
api/
|
- **EDIT_USER**
|
||||||
client.ts ZinoClient — HTTP client (login, views, activities, upload)
|
- Fields: `name_3` (text), `email_3` (email)
|
||||||
clients.ts per-workflow client singletons + shared auth (loginAll…)
|
|
||||||
config.ts app 434 ids: APP_ID, workflow uuids, activities, fields, views
|
|
||||||
types.ts API response types
|
|
||||||
auth/ AuthProvider + useAuth (JWT session)
|
|
||||||
components/
|
|
||||||
buttons/ Button, IconButton
|
|
||||||
reusable/ Card, Badge, Input, Select, Pagination, Modal, Spinner, EmptyState
|
|
||||||
rv/ generic RecordView + wired Orders/Calls/Stores/DailyLogs views
|
|
||||||
dv/ generic DetailView + wired Order/Call/Store/DailyLog details
|
|
||||||
screens/ LoginPage, ConsoleLayout, WorkflowPage, tab defs
|
|
||||||
lib/ cn (classnames), format (value formatting)
|
|
||||||
styles/ Tailwind v4 theme + design tokens
|
|
||||||
docs/api/ source API docs (one per workflow)
|
|
||||||
```
|
|
||||||
|
|
||||||
## Routing
|
### 5. Custom Pipelines
|
||||||
|
The app uses backend pipelines (custom API endpoints) to fetch aggregated data that standard Record Views cannot provide. These are defined in `src/api/config.ts`:
|
||||||
|
|
||||||
| Path | Screen |
|
- `/api/p/krishna-group/v1/nearest-stores`: Fetches stores near the user's geolocation for logging visits. **(Used in: `NearestStoresMap.tsx`)**
|
||||||
| --- | --- |
|
- `/api/p/krishna-group/v1/daily-sales-report`: Aggregates the daily sales report for managers. **(Used in: `DailySalesReportPage.tsx` via `client.ts`)**
|
||||||
| `/login` | Login gate |
|
- `/api/p/krishna-group/v1/productive-call-summary`: Summarizes productive vs non-productive calls. **(Used in: `DynamicForm.tsx` during order workflows)**
|
||||||
| `/:tab` | Record view (`orders` · `calls` · `stores` · `daily`) |
|
- `/api/p/krishna-group/v1/sales-officers`: Retrieves a list of Sales Officers for filtering. **(Used in: `DailySalesReportPage.tsx`)**
|
||||||
| `/:tab/:instanceId` | Same list with the detail modal open (deep-linkable) |
|
- `/api/p/krishna-group/v1/auto-close-orders`: Batch process to close pending orders. **(Defined in config, executed via backend CRON or specific admin actions)**
|
||||||
|
- `/api/p/krishna-group/v1/edit-orders`: Pipeline to handle order modifications. **(Configured for future implementation)**
|
||||||
|
- `/api/p/krishna-group/v1/orders`: Fetches order summaries. **(Configured for future implementation)**
|
||||||
|
- `/api/p/krishna-group/v1/potential-mining`: Retrieves potential data for stores to pre-fill the smart grid. **(Used in: `DynamicForm.tsx`, `CallDetail.tsx`, `OrdersPage.tsx`, `CallsPage.tsx`)**
|
||||||
|
|
||||||
Unknown paths redirect to `/orders`. Routes under the console require an authenticated session; a 401 bounces back to `/login`.
|
### 6. Admin Pages
|
||||||
|
|
||||||
## Design system
|
The application includes two dedicated administrative panels restricted to users with the Admin role (and sometimes Manager).
|
||||||
|
|
||||||
Tailwind v4 with CSS-variable design tokens (`src/styles/`) — navy brand surface, sunrise accent gradient, slate neutrals. Utility names (`bg-navy-900`, `text-strong`, `shadow-md`, `rounded-lg`) resolve to the tokens via an `@theme` block. Referenced from the lead-to-policy console.
|
- **Manage Datasets (`/admin/datasets`)**:
|
||||||
|
Connects to Zino's dataset API via `client.getDatasets()`. It dynamically renders a dual-pane UI where admins can select a dataset (either a `List` or a `Table` of objects) from the left sidebar and manage its items on the right via `DatasetItemsPage.tsx`. This allows admins to update core master data (like product lists, route configurations) without deploying new code.
|
||||||
|
|
||||||
|
- **Manage Users (`/admin/users`)**:
|
||||||
|
Operates on the `USER` workflow (`ADD_USER`, `EDIT_USER` activities) to onboard new Sales Officers and edit their profiles or access roles, using standard workflow instances.
|
||||||
|
|
||||||
|
### 7. Daily Sales Report (DSR)
|
||||||
|
|
||||||
|
The **Daily Sales Report (`/sales-report`)** page provides managers and administrators with a consolidated view of all orders booked on a specific day.
|
||||||
|
|
||||||
|
#### How it works:
|
||||||
|
- **Filtering**: The user selects a specific Date, Route, Distributor, and Sales Officer.
|
||||||
|
- **Pipeline Aggregation**: Instead of relying on raw workflow lists, it queries a custom pipeline (`/api/p/krishna-group/v1/daily-sales-report`) that heavily aggregates order data from the backend, matching the selected filters.
|
||||||
|
- **PDF Generation**: It uses `jspdf` and `jspdf-autotable` to generate a dynamic, printable PDF in landscape mode.
|
||||||
|
- **SKU Chunking**: Because a store might order many different SKUs across multiple brands, the PDF logic dynamically splits columns (SKUs) into printable chunks (`PDF_MAX_SKUS_PER_CHUNK` defined in config) so that tables never overflow the page horizontally. It generates subsequent pages for overflowed SKUs automatically.
|
||||||
|
|||||||
@ -538,6 +538,10 @@ export function DynamicForm({ client, activityId: initialActivityId, instanceId:
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (f.data_type === 'email' && (val === '' || val == null)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (val == null) continue;
|
if (val == null) continue;
|
||||||
|
|
||||||
if (f.data_type === 'number' && typeof val === 'string') {
|
if (f.data_type === 'number' && typeof val === 'string') {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user