From 1d57bf042f3a7a723aaf262ad692771d4d55d1a1 Mon Sep 17 00:00:00 2001 From: suryac Date: Mon, 5 Oct 2026 13:21:06 +0530 Subject: [PATCH] fix: form email validation --- .agents/rules/build_on_change.md | 10 ++ README.md | 198 ++++++++++++++++++++------- src/components/forms/DynamicForm.tsx | 4 + 3 files changed, 161 insertions(+), 51 deletions(-) create mode 100644 .agents/rules/build_on_change.md diff --git a/.agents/rules/build_on_change.md b/.agents/rules/build_on_change.md new file mode 100644 index 0000000..b3bd800 --- /dev/null +++ b/.agents/rules/build_on_change.md @@ -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. diff --git a/README.md b/README.md index 38c4031..22c21f6 100644 --- a/README.md +++ b/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` -- **Stack:** React 19 · TypeScript · Vite 8 · Tailwind v4 · react-router v7 · lucide-react +## Version +**1.0.2** -## Getting started +## Sitemap -```bash -npm install -npm run dev # http://localhost:5173 +### Public Routes +- `/login` - User Authentication + +### 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 -npm run build # tsc -b && vite build → dist/ -npm run preview # serve the production build -npm run lint # eslint -``` +- **LOG_VISIT (Init)** + - Fields: `select_store` (wf_lookup), `date_of_visit` (date), `time_of_visit` (time), `upload_image` (image) +- **PLACE_ORDER** + - 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 | -| --- | --- | --- | --- | -| `orderBooking` | Order Booking | Orders, Calls | Orders, Calls | -| `store` | Store | Store | Store | -| `dailyReports` | Daily Reports | Daily Logs | Daily Logs | +#### 4.3 Daily Reports Workflow +Tracks Sales Officer attendance, daily planning, and end-of-day reports. +**Activity Chain:** +`INIT` (Day Plan) ➔ `PUNCH_OUT` (EOD) -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` -``` -src/ - api/ - client.ts ZinoClient — HTTP client (login, views, activities, upload) - 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) -``` +- **ADD_USER** + - Fields: `name` (text), `email` (email), `password` (password) +- **EDIT_USER** + - Fields: `name_3` (text), `email_3` (email) -## 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 | -| --- | --- | -| `/login` | Login gate | -| `/:tab` | Record view (`orders` · `calls` · `stores` · `daily`) | -| `/:tab/:instanceId` | Same list with the detail modal open (deep-linkable) | +- `/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`)** +- `/api/p/krishna-group/v1/productive-call-summary`: Summarizes productive vs non-productive calls. **(Used in: `DynamicForm.tsx` during order workflows)** +- `/api/p/krishna-group/v1/sales-officers`: Retrieves a list of Sales Officers for filtering. **(Used in: `DailySalesReportPage.tsx`)** +- `/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. diff --git a/src/components/forms/DynamicForm.tsx b/src/components/forms/DynamicForm.tsx index 70aa40f..f97f905 100644 --- a/src/components/forms/DynamicForm.tsx +++ b/src/components/forms/DynamicForm.tsx @@ -538,6 +538,10 @@ export function DynamicForm({ client, activityId: initialActivityId, instanceId: continue; } + if (f.data_type === 'email' && (val === '' || val == null)) { + continue; + } + if (val == null) continue; if (f.data_type === 'number' && typeof val === 'string') {