diff --git a/.env.example b/.env.example index 846520e..c6582fe 100644 --- a/.env.example +++ b/.env.example @@ -3,3 +3,7 @@ VITE_BASE_URL={{BACKEND_BASE_URL}} VITE_API_BASE_URL={{BACKEND_BASEURL+api/v1}} VITE_OKTA_CLIENT_ID={{Client_id_given_by client for respective mode (UAT/DEVELOPMENT)) VITE_OKTA_DOMAIN={{OKTA_DOMAIN}} + +# Tanflow (Dealer login) – base URL and client ID; client secret is in backend .env only +VITE_TANFLOW_BASE_URL={{TANFLOW_BASE_URL}} +VITE_TANFLOW_CLIENT_ID={{TANFLOW_CLIENT_ID}} diff --git a/README.md b/README.md index d6ca6c9..27356f3 100644 --- a/README.md +++ b/README.md @@ -1,716 +1,93 @@ -# 🏍️ Royal Enfield Approval Portal - -A modern, enterprise-grade approval and request management system built with React, TypeScript, and Tailwind CSS. - -## πŸ“‹ Table of Contents - -- [Features](#-features) -- [Tech Stack](#️-tech-stack) -- [Prerequisites](#-prerequisites) -- [Installation](#-installation) -- [Development](#-development) -- [Project Structure](#-project-structure) -- [Available Scripts](#-available-scripts) -- [Configuration](#️-configuration) -- [Key Features Deep Dive](#-key-features-deep-dive) -- [Troubleshooting](#-troubleshooting) -- [Contributing](#-contributing) - -## ✨ Features - -### πŸ”„ Dual Workflow System -- **Custom Request Workflow** - User-defined approvers, spectators, and workflow steps -- **Claim Management Workflow** - 8-step predefined process for dealer claim management -- Flexible approval chains with multi-level approvers -- TAT (Turnaround Time) tracking at each approval level - -### πŸ“Š Comprehensive Dashboard -- Real-time statistics and metrics -- High-priority alerts and critical request tracking -- Recent activity feed with pagination -- Upcoming deadlines and SLA breach warnings -- Department-wise performance metrics -- Customizable KPI widgets (Admin only) - -### 🎯 Request Management -- Create, track, and manage approval requests -- Document upload and management with file type validation -- Work notes and comprehensive audit trails -- Spectator and stakeholder management -- Request filtering, search, and export capabilities -- Detailed request lifecycle tracking - -### πŸ‘₯ Admin Control Panel -- **User Management** - Search, assign roles (USER, MANAGEMENT, ADMIN), and manage user permissions -- **User Role Management** - Assign and manage user roles with Okta integration -- **System Configuration** - Comprehensive admin settings: - - **KPI Configuration** - Configure dashboard KPIs, visibility, and thresholds - - **Analytics Configuration** - Data retention, export formats, and analytics features - - **TAT Configuration** - Working hours, priority-based TAT, escalation settings - - **Notification Configuration** - Email templates, notification channels, and settings - - **Notification Preferences** - User-configurable notification settings - - **Document Configuration** - File type restrictions, size limits, upload policies - - **Dashboard Configuration** - Customize dashboard layout and widgets per role - - **AI Configuration** - AI provider settings, parameters, and features - - **Sharing Configuration** - Sharing policies and permissions -- **Holiday Management** - Configure business holidays for SLA calculations - -### πŸ“ˆ Approver Performance Analytics -- Detailed approver performance metrics and statistics -- Request approval history and trends -- Average approval time analysis -- Approval rate and efficiency metrics -- TAT compliance tracking per approver -- Performance comparison and benchmarking -- Export capabilities for performance reports - -### πŸ’¬ Real-Time Live Chat (Work Notes) -- **WebSocket Integration** - Real-time bidirectional communication -- **Live Work Notes** - Instant messaging within request context -- **Presence Indicators** - See who's online/offline in real-time -- **Mention System** - @mention participants for notifications -- **File Attachments** - Share documents directly in chat -- **Message History** - Persistent chat history per request -- **Auto-reconnection** - Automatic reconnection on network issues -- **Room-based Communication** - Isolated chat rooms per request - -### πŸ”” Advanced Notifications -- **Web Push Notifications** - Browser push notifications using VAPID -- **Service Worker Integration** - Background notification delivery -- **Real-time Toast Notifications** - In-app notification system -- **SLA Tracking & Reminders** - Automated TAT breach alerts -- **Approval Status Updates** - Real-time status change notifications -- **Email Notifications** - Configurable email notification channels -- **Notification Preferences** - User-configurable notification settings - -### 🎨 Modern UI/UX -- Responsive design (mobile, tablet, desktop) -- Dark mode support -- Accessible components (WCAG compliant) -- Royal Enfield brand theming -- Smooth animations and transitions -- Intuitive navigation and user flows - -## πŸ› οΈ Tech Stack - -- **Framework:** React 18.3+ -- **Language:** TypeScript 5.6+ -- **Build Tool:** Vite 5.4+ -- **Styling:** Tailwind CSS 3.4+ -- **UI Components:** shadcn/ui + Radix UI -- **Icons:** Lucide React -- **Notifications:** Sonner (Toast) + Web Push API (VAPID) -- **Real-Time Communication:** Socket.IO Client -- **State Management:** React Hooks (useState, useMemo, useContext) -- **Authentication:** Okta SSO Integration -- **HTTP Client:** Axios - -## πŸ“¦ Prerequisites - -- **Node.js:** >= 18.0.0 -- **npm:** >= 9.0.0 (or yarn/pnpm) -- **Git:** Latest version - -## πŸš€ Installation - -### Quick Start Checklist - -- [ ] Clone the repository -- [ ] Install Node.js (>= 18.0.0) and npm (>= 9.0.0) -- [ ] Install project dependencies -- [ ] Set up environment variables (`.env.local`) -- [ ] Ensure backend API is running (optional for initial setup) -- [ ] Start development server - -### 1. Clone the repository - -\`\`\`bash -git clone -cd Re_Frontend_Code -\`\`\` - -### 2. Install dependencies - -\`\`\`bash -npm install -\`\`\` - -### 3. Set up environment variables - -#### Option A: Automated Setup (Recommended - Unix/Linux/Mac) - -Run the setup script to automatically create environment files: - -\`\`\`bash -chmod +x setup-env.sh -./setup-env.sh -\`\`\` - -This script will: -- Create `.env.example` with all required variables -- Create `.env.local` for local development -- Create `.env.production` with your production configuration (interactive) - -#### Option B: Manual Setup (Windows or Custom Configuration) +# RE-Workflow-FE -**For Windows (PowerShell):** -1. Create `.env.local` file in the project root: -\`\`\`powershell -# Create .env.local file -New-Item -Path .env.local -ItemType File -\`\`\` +## Getting started -2. Add the following content to `.env.local`: +To make it easy for you to get started with GitLab, here's a list of recommended next steps. -\`\`\`env -# Local Development Environment -VITE_API_BASE_URL=http://localhost:5000/api/v1 -VITE_BASE_URL=http://localhost:5000 +Already a pro? Just edit this README.md and make it your own. Want to make it easy? [Use the template at the bottom](#editing-this-readme)! -# Okta Authentication Configuration -VITE_OKTA_DOMAIN=your-okta-domain.okta.com -VITE_OKTA_CLIENT_ID=your-okta-client-id +## Add your files -# Push Notifications (Web Push / VAPID) -VITE_PUBLIC_VAPID_KEY=your-vapid-public-key -\`\`\` +- [ ] [Create](https://docs.gitlab.com/ee/user/project/repository/web_editor.html#create-a-file) or [upload](https://docs.gitlab.com/ee/user/project/repository/web_editor.html#upload-a-file) files +- [ ] [Add files using the command line](https://docs.gitlab.com/ee/gitlab-basics/add-file.html#add-a-file-using-the-command-line) or push an existing Git repository with the following command: -**For Production:** +``` +cd existing_repo +git remote add origin http://10.10.1.3:2010/pradeep.jha/re-workflow-fe.git +git branch -M main +git push -uf origin main +``` -Create `.env.production` with production values: +## Integrate with your tools -\`\`\`env -# Production Environment -VITE_API_BASE_URL=https://your-backend-url.com/api/v1 -VITE_BASE_URL=https://your-backend-url.com +- [ ] [Set up project integrations](http://10.10.1.3:2010/pradeep.jha/re-workflow-fe/-/settings/integrations) -# Okta Authentication Configuration -VITE_OKTA_DOMAIN=https://your-org.okta.com -VITE_OKTA_CLIENT_ID=your-production-client-id +## Collaborate with your team -# Push Notifications (Web Push / VAPID) -VITE_PUBLIC_VAPID_KEY=your-production-vapid-key -\`\`\` +- [ ] [Invite team members and collaborators](https://docs.gitlab.com/ee/user/project/members/) +- [ ] [Create a new merge request](https://docs.gitlab.com/ee/user/project/merge_requests/creating_merge_requests.html) +- [ ] [Automatically close issues from merge requests](https://docs.gitlab.com/ee/user/project/issues/managing_issues.html#closing-issues-automatically) +- [ ] [Enable merge request approvals](https://docs.gitlab.com/ee/user/project/merge_requests/approvals/) +- [ ] [Set auto-merge](https://docs.gitlab.com/ee/user/project/merge_requests/merge_when_pipeline_succeeds.html) -#### Environment Variables Reference +## Test and Deploy -| Variable | Description | Required | Default | -|----------|-------------|----------|---------| -| `VITE_API_BASE_URL` | Backend API base URL (with `/api/v1`) | Yes | `http://localhost:5000/api/v1` | -| `VITE_BASE_URL` | Base URL for WebSocket and direct file access (without `/api/v1`) | Yes | `http://localhost:5000` | -| `VITE_OKTA_DOMAIN` | Okta domain for SSO authentication | Yes* | - | -| `VITE_OKTA_CLIENT_ID` | Okta client ID for authentication | Yes* | - | -| `VITE_PUBLIC_VAPID_KEY` | Public VAPID key for web push notifications | No | - | +Use the built-in continuous integration in GitLab. -**Notes:** -- `VITE_BASE_URL` is used for WebSocket connections and must point to the base backend URL (not `/api/v1`) -- `VITE_PUBLIC_VAPID_KEY` is required for web push notifications. Generate using: - \`\`\`bash - npm install -g web-push - web-push generate-vapid-keys - \`\`\` - Use the **public key** in the frontend `.env.local` file - -\*Required if using Okta authentication - -### 4. Verify setup - -Check that all required files exist: - -\`\`\`bash -# Check environment file exists -ls -la .env.local # Unix/Linux/Mac -# or -Test-Path .env.local # Windows PowerShell -\`\`\` - -## πŸ’» Development - -### Prerequisites - -Before starting development, ensure: - -1. **Backend API is running:** - - The backend should be running on `http://localhost:5000` (or your configured URL) - - Backend API should be accessible at `/api/v1` endpoint - - CORS should be configured to allow your frontend origin - -2. **Environment variables are configured:** - - `.env.local` file exists and contains valid configuration - - All required variables are set (see [Environment Variables Reference](#environment-variables-reference)) - -3. **Node.js and npm versions:** - - Verify Node.js version: `node --version` (should be >= 18.0.0) - - Verify npm version: `npm --version` (should be >= 9.0.0) - -### Start development server - -\`\`\`bash -npm run dev -\`\`\` - -The application will open at `http://localhost:5173` (Vite default port) - -> **Note:** If port 5173 is in use, Vite will automatically use the next available port. - -### Build for production - -\`\`\`bash -npm run build -\`\`\` - -### Preview production build - -\`\`\`bash -npm run preview -\`\`\` - -## πŸ“ Project Structure - -\`\`\` -Re_Figma_Code/ -β”œβ”€β”€ src/ -β”‚ β”œβ”€β”€ components/ -β”‚ β”‚ β”œβ”€β”€ ui/ # Reusable UI components (40+) -β”‚ β”‚ β”œβ”€β”€ admin/ # Admin components -β”‚ β”‚ β”‚ β”œβ”€β”€ AIConfig/ # AI configuration -β”‚ β”‚ β”‚ β”œβ”€β”€ AnalyticsConfig/ # Analytics settings -β”‚ β”‚ β”‚ β”œβ”€β”€ DashboardConfig/ # Dashboard customization -β”‚ β”‚ β”‚ β”œβ”€β”€ DocumentConfig/ # Document policies -β”‚ β”‚ β”‚ β”œβ”€β”€ NotificationConfig/ # Notification settings -β”‚ β”‚ β”‚ β”œβ”€β”€ SharingConfig/ # Sharing policies -β”‚ β”‚ β”‚ β”œβ”€β”€ TATConfig/ # TAT configuration -β”‚ β”‚ β”‚ β”œβ”€β”€ UserManagement/ # User management -β”‚ β”‚ β”‚ └── UserRoleManager/ # Role assignment -β”‚ β”‚ β”œβ”€β”€ approval/ # Approval workflow components -β”‚ β”‚ β”œβ”€β”€ common/ # Common reusable components -β”‚ β”‚ β”œβ”€β”€ dashboard/ # Dashboard widgets -β”‚ β”‚ β”œβ”€β”€ modals/ # Modal components -β”‚ β”‚ β”œβ”€β”€ participant/ # Participant management -β”‚ β”‚ β”œβ”€β”€ workflow/ # Workflow components -β”‚ β”‚ └── workNote/ # Work notes/chat components -β”‚ β”œβ”€β”€ pages/ -β”‚ β”‚ β”œβ”€β”€ Admin/ # Admin control panel -β”‚ β”‚ β”œβ”€β”€ ApproverPerformance/ # Approver analytics -β”‚ β”‚ β”œβ”€β”€ Auth/ # Authentication pages -β”‚ β”‚ β”œβ”€β”€ Dashboard/ # Main dashboard -β”‚ β”‚ β”œβ”€β”€ RequestDetail/ # Request detail view -β”‚ β”‚ β”œβ”€β”€ Requests/ # Request listing -β”‚ β”‚ └── ... -β”‚ β”œβ”€β”€ hooks/ # Custom React hooks -β”‚ β”‚ β”œβ”€β”€ useRequestSocket.ts # WebSocket integration -β”‚ β”‚ β”œβ”€β”€ useDocumentUpload.ts # Document management -β”‚ β”‚ β”œβ”€β”€ useSLATracking.ts # SLA tracking -β”‚ β”‚ └── ... -β”‚ β”œβ”€β”€ services/ # API services -β”‚ β”‚ β”œβ”€β”€ adminApi.ts # Admin API calls -β”‚ β”‚ β”œβ”€β”€ authApi.ts # Authentication API -β”‚ β”‚ β”œβ”€β”€ workflowApi.ts # Workflow API -β”‚ β”‚ └── ... -β”‚ β”œβ”€β”€ utils/ -β”‚ β”‚ β”œβ”€β”€ socket.ts # Socket.IO utilities -β”‚ β”‚ β”œβ”€β”€ pushNotifications.ts # Web push notifications -β”‚ β”‚ β”œβ”€β”€ slaTracker.ts # SLA calculation utilities -β”‚ β”‚ └── ... -β”‚ β”œβ”€β”€ contexts/ -β”‚ β”‚ └── AuthContext.tsx # Authentication context -β”‚ β”œβ”€β”€ styles/ -β”‚ β”‚ └── globals.css -β”‚ β”œβ”€β”€ types/ -β”‚ β”‚ └── index.ts -β”‚ β”œβ”€β”€ App.tsx -β”‚ └── main.tsx -β”œβ”€β”€ public/ -β”‚ └── service-worker.js # Service worker for push notifications -β”œβ”€β”€ .vscode/ -β”œβ”€β”€ index.html -β”œβ”€β”€ vite.config.ts -β”œβ”€β”€ tsconfig.json -β”œβ”€β”€ tailwind.config.ts -β”œβ”€β”€ postcss.config.js -β”œβ”€β”€ eslint.config.js -β”œβ”€β”€ .prettierrc -β”œβ”€β”€ .gitignore -β”œβ”€β”€ package.json -└── README.md -\`\`\` - -## πŸ“œ Available Scripts - -| Script | Description | -|--------|-------------| -| `npm run dev` | Start development server | -| `npm run build` | Build for production | -| `npm run preview` | Preview production build | -| `npm run lint` | Run ESLint | -| `npm run lint:fix` | Fix ESLint errors | -| `npm run format` | Format code with Prettier | -| `npm run type-check` | Check TypeScript types | - -## βš™οΈ Configuration - -### TypeScript Path Aliases - -The project uses path aliases for cleaner imports: - -\`\`\`typescript -import { Button } from '@/components/ui/button'; -import { getSocket } from '@/utils/socket'; -\`\`\` - -Path aliases are configured in: -- `tsconfig.json` - TypeScript path mapping -- `vite.config.ts` - Vite resolver configuration - -### Tailwind CSS Customization - -Custom Royal Enfield colors are defined in `tailwind.config.ts`: - -\`\`\`typescript -colors: { - 're-green': '#2d4a3e', - 're-gold': '#c9b037', - 're-dark': '#1a1a1a', - 're-light-green': '#8a9b8e', -} -\`\`\` - -### Environment Variables - -All environment variables must be prefixed with `VITE_` to be accessible in the app: - -\`\`\`typescript -// Access environment variables -const apiUrl = import.meta.env.VITE_API_BASE_URL; -const baseUrl = import.meta.env.VITE_BASE_URL; -const oktaDomain = import.meta.env.VITE_OKTA_DOMAIN; -\`\`\` - -**Important Notes:** -- Environment variables are embedded at build time, not runtime -- Changes to `.env` files require restarting the dev server -- `.env.local` takes precedence over `.env` in development -- `.env.production` is used when building for production (`npm run build`) - -### Backend Integration - -To connect to the backend API: - -1. **Update API base URL** in `.env.local`: - \`\`\`env - VITE_API_BASE_URL=http://localhost:5000/api/v1 - VITE_BASE_URL=http://localhost:5000 - \`\`\` - -2. **Configure CORS** in your backend to allow your frontend origin - -3. **Authentication:** - - Configure Okta credentials in environment variables - - Ensure backend validates JWT tokens from Okta - - Backend should handle token exchange and refresh - -4. **WebSocket Configuration:** - - Backend must support Socket.IO on the base URL - - Socket.IO path: `/socket.io` - - CORS must allow WebSocket connections - - Events: `worknote:new`, `presence:join`, `presence:leave`, `request:online-users` - -5. **Web Push Notifications:** - - Backend must support VAPID push notification delivery - - Service worker registration endpoint required - - Push subscription management API needed - - Generate VAPID keys using: `npm install -g web-push && web-push generate-vapid-keys` - -6. **API Services:** - - API services are located in `src/services/` - - All API calls use `axios` configured with base URL from environment - - WebSocket utilities in `src/utils/socket.ts` - -### Development vs Production - -- **Development:** Uses `.env.local` (git-ignored) -- **Production:** Uses `.env.production` or environment variables set in deployment platform -- **Never commit:** `.env.local` or `.env.production` (use `.env.example` as template) - -## πŸš€ Key Features Deep Dive - -### πŸ‘₯ Admin Control Panel - -The Admin Control Panel (`/admin`) provides comprehensive system management capabilities accessible only to ADMIN role users: - -#### User Management -- **User Search**: Search users via Okta integration with real-time search -- **Role Assignment**: Assign and manage user roles (USER, MANAGEMENT, ADMIN) -- **User Statistics**: View role distribution and user counts -- **Pagination**: Efficient pagination for large user lists -- **Filtering**: Filter users by role (ELEVATED, ADMIN, MANAGEMENT, USER, ALL) - -#### System Configuration Tabs - -1. **KPI Configuration** - - Configure dashboard KPIs with visibility settings per role - - Set alert thresholds and breach conditions - - Organize KPIs by categories (Request Volume, TAT Efficiency, Approver Load, etc.) - - Enable/disable KPIs dynamically - -2. **Analytics Configuration** - - Data retention policies - - Export format settings (CSV, Excel, PDF) - - Analytics feature toggles - - Data collection preferences - -3. **TAT Configuration** - - Working hours configuration (start/end time, days of week) - - Priority-based TAT settings (express, standard, urgent) - - Escalation rules and thresholds - - Holiday calendar integration - -4. **Notification Configuration** - - Email template customization - - Notification channel management (email, push, in-app) - - Notification frequency settings - - Delivery preferences - - **Notification Preferences** - User-configurable notification settings - -5. **Document Configuration** - - Allowed file types and extensions - - File size limits (per file and total) - - Upload validation rules - - Document policy enforcement - -6. **Dashboard Configuration** - - Customize dashboard layout per role - - Widget visibility settings - - Dashboard widget ordering - - Role-specific dashboard views - -7. **AI Configuration** - - AI provider settings (OpenAI, Anthropic, etc.) - - AI parameters and model selection - - AI feature toggles - - API key management - -8. **Sharing Configuration** - - Sharing policies and permissions - - External sharing settings - - Access control rules - -#### Holiday Management -- Configure business holidays for accurate SLA calculations -- Holiday calendar integration -- Regional holiday support - -### πŸ“ˆ Approver Performance Dashboard - -Comprehensive analytics dashboard (`/approver-performance`) for tracking and analyzing approver performance: - -#### Key Metrics -- **Approval Statistics**: Total approvals, approval rate, average approval time -- **TAT Compliance**: Percentage of approvals within TAT -- **Request History**: Complete list of requests handled by approver -- **Performance Trends**: Time-based performance analysis -- **SLA Metrics**: TAT breach analysis and compliance tracking - -#### Features -- **Advanced Filtering**: Filter by date range, status, priority, SLA compliance -- **Search Functionality**: Search requests by title, ID, or description -- **Export Capabilities**: Export performance data in CSV/Excel formats -- **Visual Analytics**: Charts and graphs for performance visualization -- **Comparison Tools**: Compare performance across different time periods -- **Detailed Request List**: View all requests with approval details - -### πŸ’¬ Real-Time Live Chat (Work Notes) - -Powered by Socket.IO for instant, bidirectional communication within request context: - -#### Core Features -- **Real-Time Messaging**: Instant message delivery with Socket.IO -- **Presence Indicators**: See who's online/offline in real-time -- **@Mention System**: Mention participants using @username syntax -- **File Attachments**: Upload and share documents directly in chat -- **Message History**: Persistent chat history per request -- **Rich Text Support**: Format messages with mentions and links - -#### Technical Implementation -- **Socket.IO Client**: Real-time WebSocket communication -- **Room-Based Architecture**: Each request has isolated chat room -- **Auto-Reconnection**: Automatic reconnection on network issues -- **Presence Management**: Real-time user presence tracking -- **Message Persistence**: Messages stored in backend database - -#### Usage -- Access via Request Detail page > Work Notes tab -- Full-screen chat interface available -- Real-time updates for all participants -- Notification on new messages - -### πŸ”” Web Push Notifications - -Browser push notifications using VAPID (Voluntary Application Server Identification) protocol: - -#### Features -- **Service Worker Integration**: Background notification delivery -- **VAPID Protocol**: Secure, standards-based push notifications -- **Permission Management**: User-friendly permission requests -- **Notification Preferences**: User-configurable notification settings -- **Cross-Platform Support**: Works on desktop and mobile browsers -- **Offline Queue**: Notifications queued when browser is offline - -#### Configuration -1. Generate VAPID keys (public/private pair) -2. Set `VITE_PUBLIC_VAPID_KEY` in environment variables -3. Backend must support VAPID push notification delivery -4. Service worker automatically registers on app load - -#### Notification Types -- **SLA Alerts**: TAT breach and approaching deadline notifications -- **Approval Requests**: New requests assigned to approver -- **Status Updates**: Request status change notifications -- **Work Note Mentions**: Notifications when mentioned in chat -- **System Alerts**: Critical system notifications - -#### Browser Support -- Chrome/Edge: Full support -- Firefox: Full support -- Safari: Limited support (macOS/iOS) -- Requires HTTPS in production - -## πŸ”§ Troubleshooting - -### Common Issues - -#### WebSocket Connection Issues - -If real-time features (chat, presence) are not working: - -1. Verify backend Socket.IO server is running -2. Check `VITE_BASE_URL` in `.env.local` (should not include `/api/v1`) -3. Ensure CORS allows WebSocket connections -4. Check browser console for Socket.IO connection errors -5. Verify Socket.IO path is `/socket.io` (default) - -\`\`\`bash -# Test WebSocket connection -# Open browser console and check for Socket.IO connection logs -\`\`\` - -#### Web Push Notifications Not Working - -1. Ensure `VITE_PUBLIC_VAPID_KEY` is set in `.env.local` -2. Verify service worker is registered (check Application tab in DevTools) -3. Check browser notification permissions -4. Ensure HTTPS in production (required for push notifications) -5. Verify backend push notification endpoint is configured - -\`\`\`bash -# Check service worker registration -# Open DevTools > Application > Service Workers -\`\`\` - -#### Port Already in Use +- [ ] [Get started with GitLab CI/CD](https://docs.gitlab.com/ee/ci/quick_start/index.html) +- [ ] [Analyze your code for known vulnerabilities with Static Application Security Testing (SAST)](https://docs.gitlab.com/ee/user/application_security/sast/) +- [ ] [Deploy to Kubernetes, Amazon EC2, or Amazon ECS using Auto Deploy](https://docs.gitlab.com/ee/topics/autodevops/requirements.html) +- [ ] [Use pull-based deployments for improved Kubernetes management](https://docs.gitlab.com/ee/user/clusters/agent/) +- [ ] [Set up protected environments](https://docs.gitlab.com/ee/ci/environments/protected_environments.html) -If the default port (5173) is in use: +*** -\`\`\`bash -# Option 1: Kill the process using the port -# Windows -netstat -ano | findstr :5173 -taskkill /PID /F +# Editing this README -# Unix/Linux/Mac -lsof -ti:5173 | xargs kill -9 +When you're ready to make this README your own, just edit this file and use the handy template below (or feel free to structure it however you want - this is just a starting point!). Thanks to [makeareadme.com](https://www.makeareadme.com/) for this template. -# Option 2: Use a different port -npm run dev -- --port 3000 -\`\`\` +## Suggestions for a good README -#### Environment Variables Not Loading +Every project is different, so consider which of these sections apply to yours. The sections used in the template are suggestions for most open source projects. Also keep in mind that while a README can be too long and detailed, too long is better than too short. If you think your README is too long, consider utilizing another form of documentation rather than cutting out information. -1. Ensure variables are prefixed with `VITE_` -2. Restart the dev server after changing `.env` files -3. Check that `.env.local` exists in the project root -4. Verify no typos in variable names +## Name +Choose a self-explaining name for your project. -#### Backend Connection Issues +## Description +Let people know what your project can do specifically. Provide context and add a link to any reference visitors might be unfamiliar with. A list of Features or a Background subsection can also be added here. If there are alternatives to your project, this is a good place to list differentiating factors. -1. Verify backend is running on the configured port -2. Check `VITE_API_BASE_URL` in `.env.local` matches backend URL -3. Ensure CORS is configured in backend to allow frontend origin -4. Check browser console for detailed error messages +## Badges +On some READMEs, you may see small images that convey metadata, such as whether or not all the tests are passing for the project. You can use Shields to add some to your README. Many services also have instructions for adding a badge. -#### Build Errors +## Visuals +Depending on what you are making, it can be a good idea to include screenshots or even a video (you'll frequently see GIFs rather than actual videos). Tools like ttygif can help, but check out Asciinema for a more sophisticated method. -\`\`\`bash -# Clear cache and rebuild -rm -rf node_modules/.vite -npm run build +## Installation +Within a particular ecosystem, there may be a common way of installing things, such as using Yarn, NuGet, or Homebrew. However, consider the possibility that whoever is reading your README is a novice and would like more guidance. Listing specific steps helps remove ambiguity and gets people to using your project as quickly as possible. If it only runs in a specific context like a particular programming language version or operating system or has dependencies that have to be installed manually, also add a Requirements subsection. -# Check for TypeScript errors -npm run type-check -\`\`\` +## Usage +Use examples liberally, and show the expected output if you can. It's helpful to have inline the smallest example of usage that you can demonstrate, while providing links to more sophisticated examples if they are too long to reasonably include in the README. -### Getting Help +## Support +Tell people where they can go to for help. It can be any combination of an issue tracker, a chat room, an email address, etc. -- Check browser console for errors -- Verify all environment variables are set correctly -- Ensure Node.js and npm versions meet requirements -- Review backend logs for API-related issues -- Check Network tab for WebSocket connection status -- Verify service worker registration in DevTools > Application +## Roadmap +If you have ideas for releases in the future, it is a good idea to list them in the README. -## πŸ” Role-Based Access Control +## Contributing +State if you are open to contributions and what your requirements are for accepting them. -The application supports three user roles with different access levels: +For people who want to make changes to your project, it's helpful to have some documentation on how to get started. Perhaps there is a script that they should run or some environment variables that they need to set. Make these steps explicit. These instructions could also be useful to your future self. -### USER Role -- Create and manage own requests -- View assigned requests -- Approve/reject requests assigned to them -- Add work notes and comments -- Upload documents +You can also document commands to lint the code or run tests. These steps help to ensure high code quality and reduce the likelihood that the changes inadvertently break something. Having instructions for running tests is especially helpful if it requires external setup, such as starting a Selenium server for testing in a browser. -### MANAGEMENT Role -- All USER permissions -- View all requests across the organization -- Access to detailed reports and analytics -- Approver Performance dashboard access -- Export capabilities +## Authors and acknowledgment +Show your appreciation to those who have contributed to the project. -### ADMIN Role -- All MANAGEMENT permissions -- Access to Admin Control Panel (`/admin`) -- User management and role assignment -- System configuration (TAT, Notifications, Documents, etc.) -- KPI configuration and dashboard customization -- Holiday calendar management -- Full system administration capabilities - -## πŸ§ͺ Testing (Future Enhancement) - -Add testing framework: - -\`\`\`bash -npm install -D vitest @testing-library/react @testing-library/jest-dom -\`\`\` - -## 🀝 Contributing - -1. Follow the existing code style -2. Run `npm run lint:fix` before committing -3. Run `npm run type-check` to ensure type safety -4. Write meaningful commit messages - -## πŸ“ License - -Private - Royal Enfield Internal Use Only - -## πŸ‘₯ Team - -Built by the Royal Enfield Development Team - ---- - -**For support or questions, contact the development team.** +## License +For open source projects, say how it is licensed. +## Project status +If you have run out of energy or time for your project, put a note at the top of the README saying that development has slowed down or stopped completely. Someone may choose to fork your project or volunteer to step in as a maintainer or owner, allowing your project to keep going. You can also make an explicit request for maintainers. diff --git a/docs/Form16_SUBMISSION_STATUS_AND_FEATURES.md b/docs/Form16_SUBMISSION_STATUS_AND_FEATURES.md new file mode 100644 index 0000000..81073c0 --- /dev/null +++ b/docs/Form16_SUBMISSION_STATUS_AND_FEATURES.md @@ -0,0 +1,105 @@ +# Form 16 – Submission Status Screen, Alerts, Validations & Versions + +This document describes the **submission status screen** shown to the dealer after submitting Form 16A, and related features: alerts, validations, and submission versions. + +--- + +## 1. Submission status screen (post-submit) + +**URL (after submit):** `http://localhost:3001/form16/submit/result` (or same path on your host). + +**When it appears:** After the dealer uploads Form 16A, OCR extraction runs (Gemini/regex), they correct TAN/deductor if needed, and click **Submit Form 16A**. The app then navigates to this result screen with a status. + +### 1.1 Statuses + +| Status | UI label | When it happens | +|-------------|------------------------------------|-----------------| +| **success** | Matched & Credit Note Generated | Form 16A matched 26AS and a credit note was generated. *(Currently backend does not return this at submit time; matching is async. Can be shown when opening the request detail if a credit note exists.)* | +| **mismatch**| Value Mismatch | Form 16A details did not match 26AS data. *(Requires backend to perform sync validation and return this.)* | +| **duplicate** | Duplicate Submission | Same Form 16A (or same dealer + FY + quarter) already submitted. API returns 400 with duplicate message. | +| **error** | Request Received | Submission accepted; request created and is being processed. Shown for every successful `POST /form16/submissions` until sync matching is implemented. | + +### 1.2 Process flow (timeline on the screen) + +1. **Form 16A Uploaded** – completed once file is uploaded and OCR ran. +2. **Validation** – completed (or failed for duplicate). +3. **26AS Matching** – pending until matching runs; completed on success; failed on mismatch/duplicate. +4. **Credit Note** – pending until a credit note is generated; completed on success. + +### 1.3 Actions on result screen + +- **Success:** β€œBack to My Requests”; auto-redirect after 5 seconds. +- **Request Received (error):** β€œView Request”, β€œTry Again”, β€œBack to My Requests”. +- **Duplicate:** β€œBack to New Submission”, β€œBack to My Requests”. +- **Mismatch:** β€œResubmit Form 16A”, β€œBack to My Requests”. + +State is passed via React Router `location.state` and persisted in `sessionStorage` under `form16_submission_result` so a refresh still shows the result. + +--- + +## 2. Alerts (admin-configured) + +Form 16 alerts are driven by **admin config** (e.g. `Form16AdminConfig`). Relevant keys: + +| Config key | Purpose | +|--------------------------------|---------| +| `alertSubmitForm16Enabled` | Whether to send β€œsubmit Form 16” alerts to dealers. | +| `alertSubmitForm16FrequencyDays` | Frequency (days) for the alert. | +| `alertSubmitForm16FrequencyHours`| Frequency (hours) for the alert. | +| `alertSubmitForm16Template` | Message template; placeholders e.g. `[Name]`, `[DueDate]`. | + +Notifications (success/failure) use: + +- `notificationForm16SuccessCreditNote` – e.g. β€œForm 16 submitted successfully. Credit note: [CreditNoteRef].” +- `notificationForm16Unsuccessful` – e.g. β€œForm 16 submission was unsuccessful. Issue: [Issue].” + +These are stored in the workflow admin config (e.g. `form16` or `FORM16` config blob) and used by backend/cron for sending alerts and notifications. + +--- + +## 3. Validations + +- **Client-side (submit page):** + - Financial year and quarter required. + - File must be PDF. + - TAN and deductor name required (from OCR or manual). + - Toast errors if validation fails. + +- **Backend (`POST /form16/submissions`):** + - Required: `financialYear`, `quarter`, `form16aNumber`, `tanNumber`, `deductorName`. + - `tdsAmount` and `totalAmount` must be valid numbers β‰₯ 0. + - Duplicate check: if the backend detects an existing submission (e.g. same certificate or same dealer + FY + quarter), it returns **400** with a message containing β€œduplicate” or β€œalready exist”; the frontend then shows the **duplicate** status on the result screen. + - No synchronous 26AS matching or credit note creation at submit time in the current implementation; validation status is updated asynchronously (e.g. `form16a_submissions.validation_status`). + +--- + +## 4. Submission versions + +- **Model:** `form16a_submissions.version` (number; default 1). +- **Submit payload:** Optional `version` in the create-submission payload (e.g. for β€œresubmit” or revised certificate). +- **UI note (Form16Submit):** β€œIf you submit multiple versions for the same quarter, only the latest approved version will be processed.” +- Version is stored per submission row; business logic (e.g. β€œlatest approved”) is applied when listing or matching (backend / RE views). + +--- + +## 5. Where things live in the repo + +| Item | Location | +|------|----------| +| Submission result screen | `src/pages/Form16/components/RequestSubmissionSuccess.tsx` | +| Result page (route + state) | `src/pages/Form16/Form16SubmissionResult.tsx` | +| Submit page (navigate to result) | `src/pages/Form16/Form16Submit.tsx` | +| Status chip / timeline | `src/pages/Form16/components/StatusChip.tsx`, `TimelineStep.tsx` | +| Route | `App.tsx`: `/form16/submit/result` | +| Form 16 config (alerts, notifications) | Backend admin config; frontend `Form16AdminConfig` (e.g. under admin settings). | + +--- + +## 6. Local URL + +Form 16 (submit and result) is under the same app; typical local URL: + +- Submit: `http://localhost:3001/form16/submit` +- Result: `http://localhost:3001/form16/submit/result` (after submit or when state is in `sessionStorage`). + +Replace `3001` with your frontend port if different. diff --git a/package-lock.json b/package-lock.json index 77ec0a7..abe9ce5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -73,6 +73,7 @@ "@typescript-eslint/parser": "^8.15.0", "@vitejs/plugin-react": "^4.3.3", "autoprefixer": "^10.4.20", + "baseline-browser-mapping": "^2.10.0", "eslint": "^9.15.0", "eslint-plugin-react-hooks": "^5.0.0", "eslint-plugin-react-refresh": "^0.4.14", @@ -3598,13 +3599,16 @@ "license": "MIT" }, "node_modules/baseline-browser-mapping": { - "version": "2.8.19", - "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.8.19.tgz", - "integrity": "sha512-zoKGUdu6vb2jd3YOq0nnhEDQVbPcHhco3UImJrv5dSkvxTc2pl2WjOPsjZXDwPDSl5eghIMuY3R6J9NDKF3KcQ==", + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.0.tgz", + "integrity": "sha512-lIyg0szRfYbiy67j9KN8IyeD7q7hcmqnJ1ddWmNt19ItGpNN64mnllmxUNFIOdOm6by97jlL6wfpTTJrmnjWAA==", "dev": true, "license": "Apache-2.0", "bin": { - "baseline-browser-mapping": "dist/cli.js" + "baseline-browser-mapping": "dist/cli.cjs" + }, + "engines": { + "node": ">=6.0.0" } }, "node_modules/binary-extensions": { diff --git a/package.json b/package.json index 9962146..ae85146 100644 --- a/package.json +++ b/package.json @@ -78,6 +78,7 @@ "@typescript-eslint/parser": "^8.15.0", "@vitejs/plugin-react": "^4.3.3", "autoprefixer": "^10.4.20", + "baseline-browser-mapping": "^2.10.0", "eslint": "^9.15.0", "eslint-plugin-react-hooks": "^5.0.0", "eslint-plugin-react-refresh": "^0.4.14", diff --git a/src/App.tsx b/src/App.tsx index a9a2fef..61bf503 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -25,6 +25,14 @@ import { DetailedReports } from '@/pages/DetailedReports'; import { AdminTemplatesList } from '@/pages/Admin/Templates/AdminTemplatesList'; import { CreateTemplate } from '@/pages/Admin/Templates/CreateTemplate'; import { CreateAdminRequest } from '@/pages/CreateAdminRequest/CreateAdminRequest'; +import { Admin } from '@/pages/Admin/Admin'; +import { Form16CreditNotes } from '@/pages/Form16/Form16CreditNotes'; +import { Form16CreditNoteDetail } from '@/pages/Form16/Form16CreditNoteDetail'; +import { Form16Submit } from '@/pages/Form16/Form16Submit'; +import { Form16SubmissionResult } from '@/pages/Form16/Form16SubmissionResult'; +import { Form16_26AS } from '@/pages/Form16/Form16_26AS'; +import { Form16NonSubmittedDealers } from '@/pages/Form16/Form16NonSubmittedDealers'; +import { Form16PendingSubmissions } from '@/pages/Form16/Form16PendingSubmissions'; import { ApprovalActionModal } from '@/components/modals/ApprovalActionModal'; import { Toaster } from '@/components/ui/sonner'; import { toast } from 'sonner'; @@ -445,11 +453,12 @@ function AppRoutes({ onLogout }: AppProps) { {/* Admin Routes Group with Shared Layout */} + } > + } /> } /> } /> } /> @@ -505,6 +514,74 @@ function AppRoutes({ onLogout }: AppProps) { } /> + {/* Form 16 – Credit Notes (dealer) */} + + + + } + /> + + + + } + /> + + {/* Form 16 – Submit (dealer) */} + + + + } + /> + + {/* Form 16 – Submission result (after dealer submits) */} + + + + } + /> + + {/* Form 16 – 26AS (RE) */} + + + + } + /> + + {/* Form 16 – Pending Submissions (dealer) */} + + + + } + /> + + {/* Form 16 – Non-submitted dealers (RE) */} + + + + } + /> + {/* My Requests */} void; + onRemove: (email: string) => void; + placeholder?: string; +} + +function ViewerTable({ emails, onAdd, onRemove, placeholder }: ViewerTableProps) { + const [input, setInput] = useState(''); + const add = () => { + const e = input.trim().toLowerCase(); + if (!e) return; + if (!isValidEmail(e)) { + toast.error('Please enter a valid email address'); + return; + } + if (emails.includes(e)) { + toast.error('This email is already in the list'); + return; + } + onAdd(e); + setInput(''); + }; + return ( +
+
+ setInput(e.target.value)} + onKeyDown={(e) => e.key === 'Enter' && (e.preventDefault(), add())} + className="flex-1" + /> + +
+ {emails.length > 0 ? ( +
+ + + + Email + Actions + + + + {emails.map((email) => ( + + {email} + + + + + ))} + +
+
+ ) : ( +

+ No viewers added. Add emails above or leave empty to allow all RE users with access. +

+ )} +
+ ); +} + +function defaultNotif(enabled: boolean, template: string): Form16NotificationItem { + return { enabled, template }; +} + +const default26AsNotif = (): Form16Notification26AsItem => ({ + enabled: true, + templateRe: '26AS data has been added. Please review and use for matching dealer Form 16 submissions.', + templateDealers: 'New 26AS data has been uploaded. You can now submit your Form 16 for the relevant quarter if you haven’t already.', +}); + +export function Form16AdminConfig() { + const [loading, setLoading] = useState(true); + const [saving, setSaving] = useState(false); + const [submissionViewerEmails, setSubmissionViewerEmails] = useState([]); + const [twentySixAsViewerEmails, setTwentySixAsViewerEmails] = useState([]); + const [reminderEnabled, setReminderEnabled] = useState(true); + const [reminderDays, setReminderDays] = useState(7); + + const [notification26AsDataAdded, setNotification26AsDataAdded] = useState(default26AsNotif()); + const [notificationForm16SuccessCreditNote, setNotificationForm16SuccessCreditNote] = useState(defaultNotif(true, 'Form 16 submitted successfully. Credit note: [CreditNoteRef].')); + const [notificationForm16Unsuccessful, setNotificationForm16Unsuccessful] = useState(defaultNotif(true, 'Form 16 submission was unsuccessful. Issue: [Issue]. Please review.')); + const [alertSubmitForm16Enabled, setAlertSubmitForm16Enabled] = useState(true); + const [alertSubmitForm16FrequencyDays, setAlertSubmitForm16FrequencyDays] = useState(0); + const [alertSubmitForm16FrequencyHours, setAlertSubmitForm16FrequencyHours] = useState(24); + const [alertSubmitForm16RunAtTime, setAlertSubmitForm16RunAtTime] = useState('09:00'); + const [alertSubmitForm16Template, setAlertSubmitForm16Template] = useState('Please submit your Form 16 at your earliest. [Name], due date: [DueDate].'); + const [reminderNotificationEnabled, setReminderNotificationEnabled] = useState(true); + const [reminderFrequencyDays, setReminderFrequencyDays] = useState(0); + const [reminderFrequencyHours, setReminderFrequencyHours] = useState(12); + const [reminderRunAtTime, setReminderRunAtTime] = useState('10:00'); + const [reminderNotificationTemplate, setReminderNotificationTemplate] = useState('Reminder: Form 16 submission is pending. [Name], [Request ID]. Please review.'); + + useEffect(() => { + let mounted = true; + getForm16Config() + .then((config: Form16ConfigType) => { + if (!mounted) return; + setSubmissionViewerEmails(config.submissionViewerEmails ?? []); + setTwentySixAsViewerEmails(config.twentySixAsViewerEmails ?? []); + setReminderEnabled(config.reminderEnabled ?? true); + setReminderDays(typeof config.reminderDays === 'number' ? config.reminderDays : 7); + if (config.notification26AsDataAdded) { + const n = config.notification26AsDataAdded as Form16Notification26AsItem & { template?: string }; + setNotification26AsDataAdded({ + enabled: n.enabled ?? true, + templateRe: n.templateRe ?? n.template ?? default26AsNotif().templateRe, + templateDealers: n.templateDealers ?? default26AsNotif().templateDealers, + }); + } + if (config.notificationForm16SuccessCreditNote) setNotificationForm16SuccessCreditNote(config.notificationForm16SuccessCreditNote); + if (config.notificationForm16Unsuccessful) setNotificationForm16Unsuccessful(config.notificationForm16Unsuccessful); + setAlertSubmitForm16Enabled(config.alertSubmitForm16Enabled ?? true); + setAlertSubmitForm16FrequencyDays(config.alertSubmitForm16FrequencyDays ?? 0); + setAlertSubmitForm16FrequencyHours(config.alertSubmitForm16FrequencyHours ?? 24); + setAlertSubmitForm16RunAtTime(config.alertSubmitForm16RunAtTime !== undefined && config.alertSubmitForm16RunAtTime !== null ? config.alertSubmitForm16RunAtTime : '09:00'); + setAlertSubmitForm16Template(config.alertSubmitForm16Template ?? 'Please submit your Form 16 at your earliest. [Name], due date: [DueDate].'); + setReminderNotificationEnabled(config.reminderNotificationEnabled ?? true); + setReminderFrequencyDays(config.reminderFrequencyDays ?? 0); + setReminderFrequencyHours(config.reminderFrequencyHours ?? 12); + setReminderRunAtTime(config.reminderRunAtTime !== undefined && config.reminderRunAtTime !== null ? config.reminderRunAtTime : '10:00'); + setReminderNotificationTemplate(config.reminderNotificationTemplate ?? 'Reminder: Form 16 submission is pending. [Name], [Request ID]. Please review.'); + }) + .catch(() => { + if (mounted) toast.error('Failed to load Form 16 configuration'); + }) + .finally(() => { + if (mounted) setLoading(false); + }); + return () => { + mounted = false; + }; + }, []); + + const handleSave = async () => { + setSaving(true); + try { + await putForm16Config({ + submissionViewerEmails, + twentySixAsViewerEmails, + reminderEnabled, + reminderDays: Math.max(1, Math.min(365, reminderDays)) || 7, + notification26AsDataAdded, + notificationForm16SuccessCreditNote, + notificationForm16Unsuccessful, + alertSubmitForm16Enabled, + alertSubmitForm16FrequencyDays: Math.max(0, Math.min(365, alertSubmitForm16FrequencyDays)), + alertSubmitForm16FrequencyHours: Math.max(0, Math.min(168, alertSubmitForm16FrequencyHours)), + alertSubmitForm16RunAtTime: alertSubmitForm16RunAtTime ?? '', + alertSubmitForm16Template, + reminderNotificationEnabled, + reminderFrequencyDays: Math.max(0, Math.min(365, reminderFrequencyDays)), + reminderFrequencyHours: Math.max(0, Math.min(168, reminderFrequencyHours)), + reminderRunAtTime: reminderRunAtTime ?? '', + reminderNotificationTemplate, + }); + toast.success('Form 16 configuration saved'); + } catch { + toast.error('Failed to save Form 16 configuration'); + } finally { + setSaving(false); + } + }; + + if (loading) { + return ( +
+ +
+ ); + } + + return ( +
+ {/* Page header */} +
+

Form 16 Administration

+

+ Configure Form 16 access, who can view submission data and 26AS, and notification settings. +

+
+ + {/* Summary cards */} +
+
+

Submission data viewers (RE)

+

{submissionViewerEmails.length}

+

Who can see Form 16 submissions

+
+
+

26AS viewers (RE)

+

{twentySixAsViewerEmails.length}

+

Who can see 26AS page

+
+
+

Reminders to dealers

+

{reminderEnabled ? 'On' : 'Off'}

+

Pending Form 16 reminder schedule

+
+
+

Email / in-app notifications

+

+ {[ + notification26AsDataAdded?.enabled, + notificationForm16SuccessCreditNote?.enabled, + notificationForm16Unsuccessful?.enabled, + alertSubmitForm16Enabled, + reminderNotificationEnabled, + ].filter(Boolean).length}{' '} + / 5 enabled +

+

To dealers and RE as per rules below

+
+
+ + {/* Submission data viewers */} + + + + + Submission data – who can see + + + Users with these email addresses can see Form 16 submission data (and the Form 16 menu in the sidebar). Use the exact login email of each user (the same email they use to sign in). Leave the list empty to allow all RE users with Form 16 access. + + + + setSubmissionViewerEmails((prev) => [...prev, email].sort())} + onRemove={(email) => setSubmissionViewerEmails((prev) => prev.filter((e) => e !== email))} + placeholder="e.g., user@royalenfield.com" + /> + + + + {/* 26AS viewers */} + + + + + 26AS page and button – who can see + + + Users with these email addresses can see the 26AS page and 26AS menu item. Use the exact login email of each user. Leave empty to allow all RE users. + + + + setTwentySixAsViewerEmails((prev) => [...prev, email].sort())} + onRemove={(email) => setTwentySixAsViewerEmails((prev) => prev.filter((e) => e !== email))} + placeholder="e.g., user@royalenfield.com" + /> + + + + {/* Notifications and reminders (simple toggles) */} + + + + + Reminder schedule (for dealers) + + + When reminders are enabled, dealers with pending Form 16 for a quarter are reminded at this interval. Set how often (in days) the system may send them a reminder to submit Form 16. + + + +
+ + +
+
+ + setReminderDays(parseInt(e.target.value, 10) || 7)} + /> +
+
+
+ + {/* Notification Configuration – Form 16 events */} + + + Email and in-app notifications + + Configure who receives each notification, what triggers it, and when it is sent. Templates support placeholders such as [Name], [Request ID], [DueDate]. + + + +
+

Form 16 notifications – recipient and trigger

+ + {/* 26AS data added – separate message for RE users and for dealers */} +
+
+

26AS data added

+

+ Sent to: RE users who can view 26AS, and separately to all dealers. When: As soon as new 26AS data is uploaded. +

+
+
+ +