diff --git a/frontend/mobile-ui/.eslintrc.cjs b/frontend/mobile-ui/.eslintrc.cjs new file mode 100644 index 0000000..83a5444 --- /dev/null +++ b/frontend/mobile-ui/.eslintrc.cjs @@ -0,0 +1,18 @@ +module.exports = { + root: true, + env: { browser: true, es2020: true, node: true }, + parser: '@typescript-eslint/parser', + parserOptions: { ecmaVersion: 'latest', sourceType: 'module' }, + settings: { react: { version: 'detect' } }, + plugins: ['react-refresh', 'react-hooks', '@typescript-eslint'], + extends: [ + 'eslint:recommended', + 'plugin:@typescript-eslint/recommended', + 'plugin:react-hooks/recommended', + 'plugin:react-refresh/recommended', + 'prettier' + ], + rules: { + 'react-refresh/only-export-components': ['warn', { allowConstantExport: true }] + } +}; diff --git a/frontend/mobile-ui/.gitignore b/frontend/mobile-ui/.gitignore new file mode 100644 index 0000000..a4ab49a --- /dev/null +++ b/frontend/mobile-ui/.gitignore @@ -0,0 +1,22 @@ +# Dependencies +node_modules + +.env.* +.env +*.zip +# Logs +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* + +# Editor +.idea +.vscode/*.log +.DS_Store + +# Build +/dist +*.tsbuildinfo + + \ No newline at end of file diff --git a/frontend/mobile-ui/.prettierrc b/frontend/mobile-ui/.prettierrc new file mode 100644 index 0000000..9365378 --- /dev/null +++ b/frontend/mobile-ui/.prettierrc @@ -0,0 +1,6 @@ +{ + "singleQuote": true, + "semi": true, + "trailingComma": "es5", + "printWidth": 90 +} diff --git a/frontend/mobile-ui/DATA_MANAGEMENT.md b/frontend/mobile-ui/DATA_MANAGEMENT.md new file mode 100644 index 0000000..1460790 --- /dev/null +++ b/frontend/mobile-ui/DATA_MANAGEMENT.md @@ -0,0 +1,155 @@ +# Data Management & Filtering System + +## Overview +The application now uses a centralized `db.json` file for all data instead of hardcoded values in components. This provides a clean separation of data and logic, making it easier to maintain and update. + +## Database Structure + +### `db.json` Structure +```json +{ + "properties": [...], // Array of property items with filtering flags + "location": {...}, // Location data with coordinates + "searchResults": [...], // Search results data + "messages": [...], // Inbox messages data + "insights": {...}, // Insights page data + "drafts": [...] // Draft properties data +} +``` + +### Property Item Schema +Each property item has the following structure: +- `id`: Unique property identifier +- `type`: Property type (Survey, Residential, Commercial) +- `description`: Property description +- `address`: Full address +- `dueDate`: Due date in YYYY-MM-DD format +- `status`: Priority level (High, Medium, Low) +- `phoneNumber`: Contact phone number +- `area`: Property area with units +- `propertyType`: Residential or Commercial +- `isVerified`: Boolean - true if property is verified/reviewed +- `isDraft`: Boolean - true if property is in draft status +- `isNew`: Boolean - true if property is newly created +- `createdDate`: Creation date in YYYY-MM-DD format + +## Filtering System + +The home page now supports four filter types: + +### 1. All Button +- Shows all properties regardless of status +- Default view showing complete property list + +### 2. New Button +- Shows only properties where `isNew: true` +- Sorted by `createdDate` with latest first +- Helps identify recently added properties + +### 3. Reviewed Button +- Shows only properties where `isVerified: true` +- Displays completed/verified properties + +### 4. Draft Button +- Shows only properties where `isDraft: true` +- Special draft layout with continue functionality +- Shows map when "View Map" is clicked + +## Data Service (`dataService.ts`) + +### Key Functions +- `fetchData()`: Loads data from db.json +- `filterProperties()`: Filters properties by type +- `searchProperties()`: Search functionality +- `getPropertiesByStatus()`: Filter by priority status + +### Usage Example +```typescript +import { fetchData, filterProperties } from './services/dataService'; + +// Load all data +const data = await fetchData(); + +// Filter for new properties +const newProperties = filterProperties(data.properties, 'new'); +``` + +## Implementation Details + +### App.tsx Changes +- Removed hardcoded `mockProperties` and `mockLocation` +- Added `useEffect` to fetch data on component mount +- Added loading state management +- Updated all data references to use fetched data + +### HomePage.tsx Changes +- Added filtering logic with `useEffect` +- Updated calendar tab functionality +- Dynamic property rendering based on filter +- Added status badges (Verified, New) +- Improved draft mode with map toggle + +### SearchPropertyPage.tsx Changes +- Removed hardcoded `mockSearchResults` +- Now uses `searchResults` prop from App component + +## Benefits + +1. **Centralized Data**: All data in one JSON file +2. **Easy Updates**: Modify db.json without touching code +3. **Flexible Filtering**: Multiple filter criteria +4. **Better UX**: Clear status indicators and sorting +5. **Maintainable**: Clean separation of concerns + +## Complete Functionality Testing + +### HomePage Filter Testing +1. **All**: Should show 7 properties total from db.json +2. **New**: Should show 2 properties (PRP-2025-003, PRP-2025-005) sorted by latest date first +3. **Reviewed**: Should show 3 verified properties (PRP-2024-001, PRP-2024-234, PRP-2024-150) +4. **Draft**: Should show 2 draft properties (PRP-2024-002, PRP-2024-324) with special draft layout + +### Other Pages Testing +1. **SearchPropertyPage**: Uses searchResults from db.json (3 properties) +2. **LocationPage**: Uses location data from db.json +3. **InboxPage**: Uses hardcoded messages (can be connected to db.json messages later) +4. **InsightsPage**: Uses hardcoded insights (can be connected to db.json insights later) +5. **DraftPage**: Uses hardcoded drafts (can be connected to db.json drafts later) + +### Navigation Testing +- All bottom navigation tabs should work +- Back buttons should navigate properly +- Header icons should be functional + +### Map Component Testing +- Map should render on HomePage for non-Draft filters +- Map should be toggleable in Draft view with "View Map" button +- Map tabs (Map/Land Use) should switch properly + +### Data Integrity +- All data comes from centralized db.json +- No hardcoded property data in components (except pages not yet connected) +- Filtering logic works with database flags (isNew, isVerified, isDraft) + +## Adding New Data + +To add new properties, simply edit `db.json` and add objects to the `properties` array with the required schema. The application will automatically pick up the changes on next load. + +### Sample Property Object +```json +{ + "id": "PRP-2025-NEW", + "type": "Survey", + "description": "New property description", + "address": "New Address, Guntur, Andhra Pradesh", + "dueDate": "2025-10-30", + "status": "High", + "phoneNumber": "+91 12345 67890", + "area": "1,00,000 sqft", + "propertyType": "Residential", + "isVerified": false, + "isDraft": false, + "isNew": true, + "createdDate": "2025-10-13" +} +``` \ No newline at end of file diff --git a/frontend/mobile-ui/LICENSE b/frontend/mobile-ui/LICENSE new file mode 100644 index 0000000..b77bf2a --- /dev/null +++ b/frontend/mobile-ui/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2025 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/frontend/mobile-ui/README.md b/frontend/mobile-ui/README.md new file mode 100644 index 0000000..3505d98 --- /dev/null +++ b/frontend/mobile-ui/README.md @@ -0,0 +1,462 @@ + + +# ๐Ÿ  Property Tax Frontend + + +A modern, mobile-first React + TypeScript application for property tax management. This frontend provides agents and citizens with workflows to submit, verify, and manage property tax forms, upload documents, and track application status. The UI is optimized for usability, accessibility, and seamless integration with backend APIs. + + + +## ๐Ÿ› ๏ธ Tech Stack + + +- **โš›๏ธ Framework:** React 19 (with TypeScript) +- **๐Ÿ—‚๏ธ State Management:** Redux Toolkit (RTK Query) +- **๐ŸŽจ UI Library:** Material-UI (MUI) +- **๐Ÿงญ Routing:** React Router v7 +- **๐Ÿ’… Styling:** CSS Modules, custom CSS, MUI theming +- **๐ŸŒ Localization:** Custom context-based localization +- **โšก Build Tool:** Vite +- **๐Ÿงช Testing:** Vitest, React Testing Library +- **๐Ÿ—„๏ธ API Mocking:** json-server +- **๐Ÿ“ฆ Package Manager:** npm + +--- + + +## ๐Ÿ“‹ Prerequisites + + +- **๐ŸŸข Node.js:** v18.x or higher recommended +- **๐Ÿ“ฆ npm:** v9.x or higher (comes with Node.js) +- No global dependencies required + +--- + + +## ๐Ÿ“ฅ Installation + +1. **๐Ÿ”— Clone the repository:** + ```sh + git clone https://github.com/your-org/property-tax-frontend.git + cd property-tax-frontend + ``` + +2. **๐Ÿ“ฆ Install dependencies:** + ```sh + npm install + ``` + + + +--- + + +## ๐Ÿš€ Running the Project + + +### ๐Ÿ› ๏ธ Development mode + +```sh +npm run dev +``` +- Starts the Vite development server at http://localhost:5174. + + +### ๐Ÿ—๏ธ Build for production + +```sh +npm run build +``` +- Builds the app for production (output in `dist/`). + + +### ๐Ÿ‘€ Preview production build + +```sh +npm run preview +``` +- Serves the production build locally for testing. + +--- + + +## ๐Ÿ—‚๏ธ Project Structure + +``` +src/ +โ”œโ”€โ”€ App.tsx # Main app component and route definitions +โ”œโ”€โ”€ app/ # Feature modules, pages, and services +โ”œโ”€โ”€ assets/ # Images, icons, and static assets +โ”œโ”€โ”€ components/ # Shared and agent-specific components +โ”œโ”€โ”€ config/ # App configuration (env, theme, httpClient) +โ”œโ”€โ”€ context/ # React context providers +โ”œโ”€โ”€ hooks/ # Custom React hooks +โ”œโ”€โ”€ localization/ # Localization utilities +โ”œโ”€โ”€ models/ # Data models and types +โ”œโ”€โ”€ pages/ # Page-level components +โ”œโ”€โ”€ redux/ # Redux slices, store, and API logic +โ”œโ”€โ”€ services/ # API and business logic services +โ”œโ”€โ”€ storage/ # Local storage helpers +โ”œโ”€โ”€ styles/ # CSS styles +โ”œโ”€โ”€ types/ # TypeScript types +โ”œโ”€โ”€ validations/ # Validation logic +public/ # Static assets and manifest +json-server/ # Mock backend data for development/testing +docs/ # Documentation +``` + +--- + + +## ๐Ÿ“œ Scripts + + +- `npm run dev` โ†’ โšก Start dev server +- `npm run build` โ†’ ๐Ÿ—๏ธ Build production bundle +- `npm run preview` โ†’ ๐Ÿ‘€ Preview production build +- `npm run lint` โ†’ ๐Ÿงน Run linter + +--- + + +## ๐ŸŽจ Styling & UI + +- **CSS Methodology:** Uses CSS Modules for component-scoped styles, along with custom CSS files for global and utility styles. +- **UI Library & Theming:** Material-UI (MUI) is used for consistent design and theming, with theme configuration in `src/config/theme.ts`. +- **Organization:** + - Component-specific styles are placed alongside their components. + - Global styles and resets are in `src/styles/` and `src/index.css`. + - Asset-specific styles (icons, images) are organized under `src/assets/`. + - Supports responsive layouts and dark/light theme customization. + +--- + + +## ๐Ÿ”— API Integration + +- **API Layer:** All backend interactions are organized by feature in `src/app/features/`: + - `src/app/features/Agent/api/` โ€“ Agent-specific API calls + - `src/app/features/Citizen/api/` โ€“ Citizen-specific API calls + - `src/app/features/PropertyForm/api/` โ€“ Property form API calls + Each feature's `api` folder contains logic for interacting with backend services, typically using RTK Query. +- **Mock API:** Use `json-server` for local development and testing. +- **Example endpoint:** + - `GET /propertyApplications` (mocked via `json-server/propertyApplications.json`) + + + + +## ๐Ÿ‘จโ€๐Ÿ”ง Agent Module in DIGIT 3.0 + +The Agent module in DIGIT 3.0 is designed to assist field agents in managing property tax-related tasks efficiently. Agents can add new properties, verify property details, review applications, and communicate with other stakeholders. The user interface is optimized for mobile and field use, providing map-based property management and streamlined workflows. + + + +## โญ Features of Each Page + +### ๐Ÿ‘ค Profile Page +- **๐Ÿ”“ Access:** Click the Profile icon at the top right of the Home page. +- **๐Ÿ“ Personal Details:** + - Agent name and verification status (e.g., โœ… Verified Agent) + - ๐Ÿ“ง Email address and ๐Ÿ“ฑ phone number + - ๐Ÿ—บ๏ธ Assigned jurisdictions/wards +- **๐Ÿ”” Notification Settings:** + - Toggle application updates (receive updates on new or updated applications) + - Toggle appointment scheduling notifications (for rescheduling and scheduling appointments) + - Select delivery methods for notifications: + - ๐Ÿ“ฉ SMS Notifications + - ๐ŸŸข WhatsApp Notifications + - ๐Ÿ“ง Email Notifications +- **๐Ÿšช Log Out:** Securely log out of the application from the profile page +- **โฌ…๏ธ Navigation:** Use the Previous button to return to the previous screen + +### ๐ŸŒ Language Selection +- **๐Ÿ”“ Access:** Click the Language icon beside the Profile icon on the Home page. +- **๐ŸŒ Functionality:** Allows the agent to select the preferred language from the list of languages assigned to them. +- **โœจ Dynamic Language Support:** The interface updates to reflect the selected language for a personalized experience. + +### ๐Ÿ  Home Page +- **๐Ÿ—บ๏ธ Jurisdiction Display:** Shows the agent's assigned wards. +- **๐ŸŒ & ๐Ÿ‘ค Language & Profile:** Quick access to language selection and profile management. +- **๐Ÿ†” & ๐Ÿ†˜ Agent ID & Help:** Access agent credentials and help resources. +- **๐Ÿ—บ๏ธ/๐Ÿ—พ Map/Land Use Toggle:** Switch between property map and land use zoning view. +- **โž• Add New Property:** Start a new property application. +- **๐Ÿ“„ Generate No Dues:** Generate a no-dues certificate for a property. +- **๐Ÿ“‘ Tabs (All/New/Drafts/Others):** Filter properties by status. +- **๐Ÿท๏ธ Property List:** View properties with status, category, address, and date. Click to view or edit. +- **โ–ถ๏ธ Pagination:** Navigate through multiple pages of property records. +- **๐Ÿ”ฝ Bottom Navigation:** Quick access to Home, Inbox, Notifications, and Search. + +### ๐Ÿ“ Property Form Verification Page +- **๐Ÿ—บ๏ธ & ๐Ÿ  Map & Address:** Visualize property location and details. +- **โš ๏ธ Summary of Required/Review Fields:** Highlights missing or unverified fields. +- **โžก๏ธ Continue to Form:** Proceed to complete or verify property details. +- **โœ‰๏ธ Send Email:** Internal correspondence with Service Manager. +- **๐Ÿ“œ Application Log:** View property application history and comments. +- **โž• Add Comment/Request:** Submit comments or upload documents. + +### ๐Ÿ“‹ Reviewed Properties Page +- **๐Ÿ” Search & Filter:** Search reviewed properties by location and filter by date. +- **โœ… Verified Status:** See which properties are verified. +- **๐Ÿ—‚๏ธ Property List:** View details and navigate to Form Summary. +- **โ–ถ๏ธ Pagination:** Navigate through reviewed properties. + +### ๐Ÿ—ƒ๏ธ Form Summary Page +- **๐Ÿ“„ Property Details:** View all submitted property information. +- **๐Ÿ—บ๏ธ IGSR Details:** Survey, GIS, cadastral, and registration info. +- **๐Ÿ‘ค Owner & Assessment Details:** Owner contact, usage, construction, tax zone, etc. +- **๐Ÿ“‘ Documents Uploaded:** List and download supporting documents. +- **๐Ÿ—บ๏ธ Map Integration:** View property on Google Maps, Apple Maps, or Open Street Maps. + +### ๐Ÿ” Search Property Page +- **๐Ÿ“ Field Selection:** Search by owner name, location, or phone number. +- **๐ŸŽ™๏ธ Voice Input:** Option to use voice for search fields. +- **๐Ÿ“„ Search Results:** List of properties with status and location. +- **๐ŸŒ View Location:** Directly view property location on map. + +### ๐Ÿ•’ Application Log +- **โณ Timeline View:** Chronological history of application events and comments. +- **๐Ÿ” Status Updates:** See inspection, verification, and admin actions. +- **โฌ‡๏ธ Document Download:** Download attached documents. +- **โœ๏ธ Add Request:** Add new requests or comments. + +### ๐Ÿ’ฌ Add Comment or Request +- **๐Ÿ’ญ Comment/Request Input:** Enter comments or requests for the application log. +- **๐Ÿ“ File Upload:** Attach supporting documents (PDF, images, etc.). +- **โœ…/โŒ Submit/Cancel:** Submit or cancel the comment/request. + +### ๐Ÿ“ง Send Email +- **โœ๏ธ Compose Email:** Internal communication with Service Manager. +- **๐Ÿ“Ž Attachment Support:** Attach documents to emails. +- **๐Ÿ’พ/๐Ÿ—‘๏ธ Draft/Discard:** Save as draft or discard the email. + +## ๐Ÿงญ Agent Workflow and Navigation + +### 1๏ธโƒฃ Home Page +- **๐Ÿ—บ๏ธ Map Section:** + - Two views: **Map** (shows properties on a map) and **Land Use** (shows land use zoning). +- **๐Ÿš€ Action Buttons:** + - **โž• Add New Property:** Start a new property application. + - **๐Ÿ“„ Generate No Dues:** Generate a no-dues certificate for a property. + - **๐Ÿ“‘ Tabs:** + - **All:** View all properties assigned to the agent. + - **New:** View newly assigned or finished properties. + - **Drafts:** View properties with incomplete applications. + - **Others:** Other property categories. +- **๐Ÿท๏ธ Property List:** + - Shows properties with status (๐Ÿ”ด High/๐ŸŸก Medium), category ID, address, and date. + - Clicking a property navigates to the **Property Form Verification** page. + +### 2๏ธโƒฃ Property Form Verification Page +- **๐Ÿ“ƒ Summary of Property:** + - Map location, address, and property details. + - Shows missing required fields and fields needing verification. +- **๐Ÿ”” Actions:** + - **โžก๏ธ Continue to Form:** Proceed to complete or verify property details. + - **โœ‰๏ธ Send Email:** Internal correspondence with the Service Manager. + - **๐Ÿ“œ Application Log:** View the history of comments and requests for the property. + - **โž• Add Comment/Request:** Submit comments or upload documents for the application log. + +### 3๏ธโƒฃ Reviewed Properties Page +- Accessed by clicking the โœ… tick button on the Home page. +- Shows a list of properties that have been reviewed and verified. +- Clicking a property navigates to the **Form Summary** page. + +### 4๏ธโƒฃ Form Summary Page +- Displays detailed information about the submitted property, including: + - ๐Ÿ  Property details (type, zone, door number, area) + - ๐Ÿ—บ๏ธ IGSR details (survey number, GIS reference, cadastral map) + - ๐Ÿ‘ค Owner information + - ๐Ÿ“‘ Assessment details (usage, construction year, built-up area, tax zone) + - ๐Ÿ“ Uploaded documents +- Provides options to view the property location on Google Maps, Apple Maps, or Open Street Maps. + +### 5๏ธโƒฃ Search Property Page +- Accessed from the bottom navigation bar (๐Ÿ” Search icon). +- Allows searching for properties by owner name, location, or phone number. +- Displays search results with property status (โœ… Verified/๐Ÿ•— Pending) and location. + +### 6๏ธโƒฃ Application Log & Comments +- **๐Ÿ•’ Application Log:** + - Timeline of actions, comments, and document uploads related to a property application. + - โฌ‡๏ธ Downloadable documents and status updates. +- **๐Ÿ’ฌ Add Comment/Request:** + - Submit comments or requests and upload supporting documents. + +### 7๏ธโƒฃ Send Email +- Internal communication tool for agents to correspond with the Service Manager. +- ๐Ÿ“Ž Attach documents and send messages regarding property applications. + +--- + +## ๐Ÿ—บ๏ธ Navigation Flow (Agent) +1. **๐Ÿ  Home Page** โ†’ Select property โ†’ **๐Ÿ“ Property Form Verification** +2. **๐Ÿ“ Property Form Verification** โ†’ + - โžก๏ธ Continue to Form + - โœ‰๏ธ Send Email + - ๐Ÿ“œ Application Log + - โž• Add Comment/Request +3. **โœ… Reviewed Properties** (via tick button on Home) โ†’ Select property โ†’ **๐Ÿ—ƒ๏ธ Form Summary** +4. **๐Ÿ” Search** (bottom nav) โ†’ **๐Ÿท๏ธ Search Property** + +--- + +## ๐Ÿ  Add New Property Flow (Agent) + +When the agent clicks the **โž• Add New Property** button from the Home page, the following step-by-step workflow is initiated. Each step corresponds to a form page where the agent must enter or select relevant property details. Navigation between steps is performed using the **Next** button, and drafts can be saved at any stage. + +### 1๏ธโƒฃ Property Information +- **Fields:** + - ๐Ÿข Category of Ownership (e.g., Private, Government, Vacant Land) + - ๐Ÿ˜๏ธ Building Use (Mixed, Non-Residential, Residential) + - ๐Ÿข Apartment/Complex Name +- **๐Ÿ“ Location Tag/Polygon:** + - Click **Add Location Tag** or **Add Polygon** to open the map interface. + - Select the property location or draw a polygon on the map. + - โœ”๏ธ Confirm the location; the selected address and coordinates are displayed on the form. + +### 2๏ธโƒฃ Owner Details +- **Fields:** + - ๐Ÿ†” Aadhaar Number + - ๐Ÿ‘ค Owner Name + - ๐Ÿ“ฑ Mobile Number + - โšง Gender + - ๐Ÿ“ง Email Address + - ๐Ÿง‘โ€๐Ÿฆณ Guardian and Guardian Relationship (optional) +- **โž• Add Owner:** Add multiple owners as needed. Each ownerโ€™s details are displayed in a list. + +### 3๏ธโƒฃ Owner Details - Identity Proof +- **Fields:** + - ๐Ÿ‘ค Select the primary owner + - ๐Ÿชช Upload proof of identity (Aadhaar, Voter ID, PAN, etc.) + +### 4๏ธโƒฃ Property Address +- **Fields:** + - ๐Ÿ˜๏ธ Locality, ๐Ÿท๏ธ Zone No, ๐Ÿ›๏ธ Ward No, ๐Ÿงฑ Block No, ๐Ÿ›ฃ๏ธ Street, ๐Ÿ—ณ๏ธ Election Ward, ๐Ÿข Secretariat Ward, ๐Ÿ”ข Pincode + - Option to specify a correspondence address if different from the property address + +### 5๏ธโƒฃ Assessment Details +- **Fields:** + - ๐Ÿ“„ Reason for Creation + - ๐Ÿ“„ Occupancy Certificate Number & Date + - ๐Ÿ“ Extent of Site (Sq.Yds) + - ๐Ÿ  Land Underneath the Building (Sq.Yds) + - Option for Unspecified/Undivided Share + +### 6๏ธโƒฃ IGRS and Building Setback Details +- **Fields:** + - ๐Ÿ˜๏ธ Habitation, ๐Ÿ—บ๏ธ IGRS Ward, ๐Ÿ“ Locality, ๐Ÿงฑ Block, ๐Ÿ”ข Door No (From/To), ๐Ÿ—‚๏ธ Classification + - ๐Ÿ“Š Built Up Area (percentage) + - โ†”๏ธ Front, Rear, Side Setbacks (meters) + - โ—ป๏ธ Total Plinth Area (meters square) + +### 7๏ธโƒฃ IGRS Details (Amenities) +- **Fields:** + - โšก Select amenities (Lift, Toilets, Water Tap, Cable Connection, Electricity, Attached Bathroom, Water Harvesting) + +### 8๏ธโƒฃ Construction Details +- **Fields:** + - ๐Ÿ—๏ธ Floor Type, ๐Ÿ  Roof Type, ๐Ÿงฑ Wall Type, ๐Ÿชต Wood Type + +### 9๏ธโƒฃ Floor Details +- **Fields:** + - ๐Ÿ”ข Floor Number, ๐Ÿ—‚๏ธ Classification of Building, ๐Ÿญ Nature of Usage, ๐Ÿข Firm Name, ๐Ÿšถ Occupancy, ๐Ÿ‘ค Occupant Name + - ๐Ÿ—๏ธ Construction Date, ๐Ÿ—“๏ธ Effective From Date + - ๐ŸŒพ Unstructured Land, ๐Ÿ“ Length, Breadth, Plinth Area, ๐Ÿ“‹ Building Permission No + - ๐ŸŒ€ **Clone Floor:** Option to copy details to other floors + - โฌœ๏ธ **Select Fields to be Copied:** Choose which fields to clone for additional floors + +### ๐Ÿ”Ÿ Document Upload +- **Fields:** + - ๐Ÿ“„ Document Type, ๐Ÿ”ข Serial No, ๐Ÿงพ Revenue Document No + - ๐Ÿ“Ž Upload supporting documents (PDF, images, etc.) + +### 1๏ธโƒฃ1๏ธโƒฃ Summary & Submission +- **๐Ÿ“‹ Summary Page:** + - ๐Ÿง Review all entered property, owner, assessment, and document details + - โœ๏ธ Edit any section if needed + - ๐Ÿ—’๏ธ Add important notes and upload photos if required +- **๐Ÿ“ค Submit:** Final submission of the new property application + +--- + +**โ„น๏ธ Note:** At each step, agents can save the form as a draft and return later to complete the process. The form is designed to ensure all mandatory fields are filled and all required documents are uploaded before submission. + +--- + +This is the complete flow of the Agent role in the DIGIT 3.0 Property Tax frontend. + +By following this structured workflow, agents can efficiently manage property tax applications, ensure data accuracy, and streamline communication with other stakeholders. The intuitive interface and stepwise process help reduce errors, improve compliance, and enhance the overall service delivery experience for both agents and citizens. + +๐Ÿ“š This documentation serves as a comprehensive guide for understanding and utilizing all features available to agents in the DIGIT 3.0 Property Tax system. + +# ๐Ÿก Citizen Module Documentation + +## ๐Ÿ“ Overview + +The Citizen module in DIGIT 3.0 enables property owners and residents to manage their property-related information, view notifications, and interact with municipal services through a user-friendly interface. The module is designed to provide transparency, convenience, and self-service capabilities for citizens. + +--- + +## โœจ Features of Each Page + +### ๐Ÿ  Home Page +- **๐Ÿ“„ Active Licenses & Number of Properties:** Quick summary cards showing the count of active licenses and registered properties. +- **๐Ÿšจ Urgent Attention:** Alerts for important actions (e.g., license renewal, bill payments, tax registration). +- **๐Ÿ—บ๏ธ/๐Ÿ“‹ Map/List Toggle:** Switch between map view and list view of properties. +- **๐Ÿ“ Property Markers:** Visual representation of properties on the map with enumeration progress. +- **โž• Add New Property:** Start a new property application (uses the same form flow as Agent). +- **๐Ÿ”– Navigation Bar:** Access Home, Utilities, Properties, and My City sections. +- **๐ŸŒ, ๐Ÿ”” & ๐Ÿ‘ค Language, Notification, and Profile:** Quick access icons at the top for language selection, notifications, and profile management. + +### ๐Ÿ˜๏ธ My Properties Page +- **๐Ÿ“œ Property List:** View all registered properties and draft applications. +- **๐Ÿงฎ Tax Calculator:** Access property tax calculation tool. +- **๐Ÿท๏ธ Property Cards:** Each card shows address, status (Enumerated/Under Enumeration), and map location. +- **๐Ÿ—บ๏ธ View Location:** Directly view property location on the map. +- **๐Ÿ“ Draft Applications:** Access and manage draft property applications. + +### ๐Ÿข Property Information Page +- **๐Ÿ—‚๏ธ Overview Tab:** + - Property type, construction year, built-up area, plot area, property value, survey number, ward. + - Land use and zoning details (current use, approved use, zoning, FSI). +- **๐Ÿ“ Plot Info Tab:** + - Survey number, subdivision, village, district, hobli, taluk, and building setbacks (front, rear, side, coverage). +- **๐Ÿ“š History Tab:** + - Ownership and registration history, including owner names, property type, registration dates, and status. +- **๐Ÿ“„ Documents Tab:** + - Upload and view property-related documents (sale deed, affidavit, permission documents, property card, etc.). + - Take image or upload files (PDF, JPG, PNG). + - View, download, or delete uploaded documents. +- **๐Ÿ“Š Enumeration Progress:** + - Progress bar showing the completion status of property enumeration. +- **๐Ÿ—บ๏ธ/๐Ÿ—พ Map/Land Use Toggle:** + - Switch between map and land use zoning view for the property. + +--- + +## ๐Ÿงญ Citizen Workflow and Navigation + +1. **๐Ÿ”‘ Login โ†’ ๐Ÿ  Home Page** + - Citizen logs in and lands on the Home page, viewing summary cards, urgent notifications, and a map/list of properties. +2. **๐Ÿ—บ๏ธ/๐Ÿ“‹ Map/List Toggle** + - Switch between map and list view to see properties visually or in a list format. +3. **โž• Add New Property** + - Click the Add New Property button to start a new property application (follows the same multi-step form as Agent). +4. **๐Ÿ˜๏ธ Properties Tab (Bottom Navigation)** + - Navigate to the My Properties page to view all properties and drafts. +5. **๐Ÿ‘๏ธโ€๐Ÿ—จ๏ธ View Property Details** + - Click on a property card to open the Property Information page. + - Access Overview, Plot Info, History, and Documents tabs for detailed information and actions. +6. **โฌ†๏ธ/๐Ÿ‘๏ธ Upload/View Documents** + - In the Documents tab, upload new documents or view/download existing ones. + +--- + +**๐Ÿ› ๏ธ Note:** Some features and pages are under development and will be documented as they are completed. + + +--- + +๐Ÿ“„ This is brief documentation. For more details, refer to the codebase or contact the maintainers. \ No newline at end of file diff --git a/frontend/mobile-ui/TESTING_CHECKLIST.md b/frontend/mobile-ui/TESTING_CHECKLIST.md new file mode 100644 index 0000000..ce79a21 --- /dev/null +++ b/frontend/mobile-ui/TESTING_CHECKLIST.md @@ -0,0 +1,116 @@ +# FUNCTIONALITY TESTING CHECKLIST + +## โœ… COMPLETE TESTING GUIDE + +### ๐Ÿ  HomePage Filter Testing +- [ ] **All Button**: Shows 7 properties from db.json +- [ ] **New Button**: Shows 2 properties (PRP-2025-003, PRP-2025-005), latest first +- [ ] **Reviewed Button**: Shows 3 verified properties (PRP-2024-001, PRP-2024-234, PRP-2024-150) +- [ ] **Draft Button**: Shows 2 draft properties with special layout and Continue buttons + +### ๐Ÿ—บ๏ธ Map Component Testing +- [ ] Map renders on HomePage for All, New, Reviewed filters +- [ ] Map hidden when Draft filter is active +- [ ] "View Map" button appears only in Draft mode +- [ ] Map toggles properly when "View Map" clicked in Draft mode +- [ ] Map/Land Use tabs switch correctly + +### ๐Ÿ” SearchPropertyPage Testing +- [ ] Search dropdown has options: All, Location, Owner Name, Phone Number +- [ ] Shows 3 search results from db.json by default +- [ ] Property cards display correctly with area, verification status +- [ ] Voice search button present and clickable + +### ๐Ÿ“ LocationPage Testing +- [ ] Shows location from db.json (123 Gandhi Nagar...) +- [ ] Phone number displays from db.json (+91 39243 22342) +- [ ] Map placeholder renders + +### ๐Ÿ“ง InboxPage Testing +- [ ] Shows 5 messages with different types (tax, verification, notification) +- [ ] Message stats show: 2 Unread, 5 Total, 1 High Priority +- [ ] Unread messages have visual indicators +- [ ] Priority colors display correctly (High=Red, Medium=Orange, Low=Green) + +### ๐Ÿ“Š InsightsPage Testing +- [ ] Overview section shows 4 insight cards +- [ ] Property performance shows 3 properties +- [ ] Trend indicators display correctly (๐Ÿ“ˆ๐Ÿ“‰โžก๏ธ) +- [ ] Quick action buttons render (4 actions) + +### ๐Ÿ“ DraftPage Testing +- [ ] Shows draft properties with delete buttons +- [ ] Continue buttons functional +- [ ] Saved timestamps display +- [ ] Location pins show correctly + +### ๐Ÿงญ Navigation Testing +- [ ] Bottom navigation works on: Home, Inbox, Insights, Search pages +- [ ] Back buttons navigate to previous page correctly +- [ ] Header icons (Language, Profile, Home) clickable +- [ ] Page transitions smooth + +### ๐Ÿ“Š Data Integrity Testing +- [ ] All HomePage data comes from db.json properties array +- [ ] Location data comes from db.json location object +- [ ] Search results come from db.json searchResults array +- [ ] No hardcoded property data in HomePage +- [ ] Filter functions work with database flags (isNew, isVerified, isDraft) + +### ๐ŸŽจ UI Consistency Testing +- [ ] Original date format preserved (e.g., "Oct 13 2025") +- [ ] No UI changes to property cards (reverted changes) +- [ ] Original saved date format in Draft mode +- [ ] Property status badges removed (UI reverted) + +## ๐Ÿš€ HOW TO TEST + +1. **Start the application:** + ```powershell + npm run dev + ``` + +2. **Test Homepage Filters:** + - Click each filter button (All, New, Reviewed, Draft) + - Verify correct number of properties show for each filter + - Check Draft mode shows special layout with map toggle + +3. **Test Navigation:** + - Use bottom navigation to visit each page + - Use back buttons to return to previous pages + - Test header icons functionality + +4. **Test Search:** + - Navigate to Search page + - Try different search field options + - Verify search results display + +5. **Test Other Pages:** + - Visit Inbox, Insights, Location, Draft pages + - Verify content displays correctly + - Check all interactive elements + +## ๐Ÿ› EXPECTED RESULTS + +### Filter Counts: +- **All**: 7 properties +- **New**: 2 properties (sorted by date, latest first) +- **Reviewed**: 3 properties +- **Draft**: 2 properties (with special draft layout) + +### Data Sources: +- HomePage properties: `db.json โ†’ properties` +- Search results: `db.json โ†’ searchResults` +- Location: `db.json โ†’ location` +- Other pages: Still use hardcoded data (can be migrated later) + +## โšก QUICK VERIFICATION + +**Essential checks in 2 minutes:** +1. HomePage filter buttons change property list โœ… +2. Draft filter shows different layout with map button โœ… +3. Search page shows results โœ… +4. Navigation between pages works โœ… +5. No console errors โœ… + +If all these pass, the core functionality is working! \ No newline at end of file diff --git a/frontend/mobile-ui/db.json b/frontend/mobile-ui/db.json new file mode 100644 index 0000000..298f329 --- /dev/null +++ b/frontend/mobile-ui/db.json @@ -0,0 +1,892 @@ +{ + "documentTypes": [ + { "id": 1, "name": "Patta Certificate (Issued by Revenue Department)" }, + { "id": 2, "name": "Registered Will Document" }, + { "id": 3, "name": "Un-registered Will Document" }, + { "id": 4, "name": "Decree by Civil Court" }, + { "id": 5, "name": "Registered Document" }, + { "id": 6, "name": "Un-registered Document / Notary document" } + ], + "ownershipOptions": [ + { + "name": "Vacant Land", + "id": "2755" + }, + { + "name": "Private", + "id": "7db4" + }, + { + "name": "Central Government 50%", + "id": "6de8" + }, + { + "name": "Central Government 75%", + "id": "dd6c" + }, + { + "name": "State Government", + "id": "dc86" + } + , + { + "name": "Central Government 33.33%", + "id": "33d3" + } + ], + "propertyTypeOptions": [ + { + "name": "Mixed", + "id": "dd67" + }, + { + "name": "Residential", + "id": "e7a4" + }, + { + "name": "Non- Residential", + "id": "7f3f" + } + ], + "vacantLandPropertyTypes": [ + { + "name": "Central Government Land", + "id": "vlt-1" + }, + { + "name": "State Government Land", + "id": "vlt-2" + }, + { + "name": "Private Land", + "id": "vlt-3" + } + ], + "guardianRelationshipOptions": [ + { + "name": "Father", + "id": "9531" + }, + { + "name": "Mother", + "id": "2fa2" + }, + { + "name": "Spouse", + "id": "d1bd" + }, + { + "name": "Husband", + "id": "0e1d" + }, + { + "name": "Other", + "id": "2e47" + } + ], + "genderOptions": [ + { + "name": "MALE", + "id": "73d3" + }, + { + "name": "FEMALE", + "id": "ce22" + }, + { + "name": "OTHERS", + "id": "8e52" + } + ], + "owners": [], + "wardNoOptions": [ + { + "name": "Ward 1", + "id": "8508" + }, + { + "name": "Ward 2", + "id": "a05c" + }, + { + "name": "Ward 3", + "id": "c0ab" + }, + { + "name": "Ward 4", + "id": "9fa9" + } + ], + "blockNoOptions": [ + { + "name": "Block A", + "id": "1885" + }, + { + "name": "Block B", + "id": "d9ed" + }, + { + "name": "Block C", + "id": "a765" + }, + { + "name": "Block D", + "id": "d600" + } + ], + "streetOptions": [ + { + "name": "Main Street", + "id": "c6e7" + }, + { + "name": "First Street", + "id": "39f1" + }, + { + "name": "Second Street", + "id": "1dc1" + }, + { + "name": "Third Street", + "id": "00a9" + } + ], + "reason": [ + { + "id": "1", + "label": "New Construction" + }, + { + "id": "2", + "label": "Renovation" + }, + { + "id": "3", + "label": "Extension" + }, + { + "id": "4", + "label": "Demolition" + }, + { + "id": "5", + "label": "Change of Use" + } + ], + "habitation": [ + { + "id": "1", + "label": "Central Park Colony" + }, + { + "id": "2", + "label": "Sunrise Apartments" + }, + { + "id": "3", + "label": "Hilltop Residency" + }, + { + "id": "4", + "label": "Riverfront Homes" + }, + { + "id": "5", + "label": "Maple Street Villas" + } + ], + "igrsWard": [ + { + "id": "1", + "label": "Ward A" + }, + { + "id": "2", + "label": "Ward B" + }, + { + "id": "3", + "label": "Ward C" + }, + { + "id": "4", + "label": "Ward D" + }, + { + "id": "5", + "label": "Ward E" + } + ], + "igrsLocality": [ + { + "id": "1", + "label": "Green Meadows" + }, + { + "id": "2", + "label": "Lakeview" + }, + { + "id": "3", + "label": "Sunshine Valley" + }, + { + "id": "4", + "label": "Riverdale" + }, + { + "id": "5", + "label": "Maple Gardens" + } + ], + "igrsBlock": [ + { + "id": "1", + "label": "Block 12" + }, + { + "id": "2", + "label": "Block 7" + }, + { + "id": "3", + "label": "Block 3" + }, + { + "id": "4", + "label": "Block 9" + }, + { + "id": "5", + "label": "Block 1" + } + ], + "doorNoFrom": [ + { + "id": "1", + "label": "10" + }, + { + "id": "2", + "label": "101" + }, + { + "id": "3", + "label": "201" + }, + { + "id": "4", + "label": "301" + }, + { + "id": "5", + "label": "401" + } + ], + "doorNoTo": [ + { + "id": "1", + "label": "15" + }, + { + "id": "2", + "label": "110" + }, + { + "id": "3", + "label": "210" + }, + { + "id": "4", + "label": "310" + }, + { + "id": "5", + "label": "410" + } + ], + "floorNumber": [ + { + "id": "1", + "label": "Ground Floor" + }, + { + "id": "2", + "label": "First Floor" + }, + { + "id": "3", + "label": "Second Floor" + }, + { + "id": "4", + "label": "Third Floor" + }, + { + "id": "5", + "label": "Fourth Floor" + } + ], + "buildingClassification": [ + { "id": "bc-0", "label": "select" }, + { "id": "bc-1", "label": "ACC Sheet" }, + { "id": "bc-2", "label": "ACC Sheet Exceeding 10 Feet Height" }, + { "id": "bc-3", "label": "GI Sheet" }, + { "id": "bc-4", "label": "Huts" }, + { "id": "bc-5", "label": "Jack Arch" }, + { "id": "bc-6", "label": "Madras Terrace" }, + { "id": "bc-7", "label": "Mangalore/Country Tiled" }, + { "id": "bc-8", "label": "RCC" }, + { "id": "bc-9", "label": "RCC High Rise Structure" }, + { "id": "bc-10", "label": "Slates/Stone Roofed" } + ], + "igrsClassification": [ + { + "id": "1", + "label": "A" + }, + { + "id": "2", + "label": "B" + }, + { + "id": "3", + "label": "C" + } + ], + "natureOfUsage": [ + { + "id": "1", + "label": "Self Use" + }, + { + "id": "2", + "label": "Rental" + } + ], + "occupancy": [ + { + "id": "1", + "label": "Owner" + }, + { + "id": "2", + "label": "Tenant" + } + ], + "occupantName": [ + { + "id": "1", + "label": "Ravi Kumar" + }, + { + "id": "2", + "label": "Anita Sharma" + }, + { + "id": "3", + "label": "Vikas Patel" + }, + { + "id": "4", + "label": "Priya Singh" + }, + { + "id": "5", + "label": "Meera Joshi" + } + ], + "unstructuredLand": [ + { + "id": "1", + "label": "Yes" + }, + { + "id": "2", + "label": "No" + } + ], + "length": [ + { + "id": "1", + "label": "30" + }, + { + "id": "2", + "label": "25" + }, + { + "id": "3", + "label": "28" + }, + { + "id": "4", + "label": "18" + }, + { + "id": "5", + "label": "22" + } + ], + "breadth": [ + { + "id": "1", + "label": "20" + }, + { + "id": "2", + "label": "15" + }, + { + "id": "3", + "label": "18" + }, + { + "id": "4", + "label": "15" + }, + { + "id": "5", + "label": "16" + } + ], + "plinthArea": [ + { + "id": "1", + "label": "600" + }, + { + "id": "2", + "label": "375" + }, + { + "id": "3", + "label": "504" + }, + { + "id": "4", + "label": "270" + }, + { + "id": "5", + "label": "352" + } + ], + "buildingPermissionNo": [ + { + "id": "1", + "label": "BP-2023-001" + }, + { + "id": "2", + "label": "BP-2022-015" + }, + { + "id": "3", + "label": "BP-2021-032" + }, + { + "id": "4", + "label": "BP-2020-087" + }, + { + "id": "5", + "label": "BP-2019-021" + } + ], + "floorType": [ + { + "id": "1", + "label": "Marble" + }, + { + "id": "2", + "label": "Tiles" + }, + { + "id": "3", + "label": "Granite" + }, + { + "id": "4", + "label": "Concrete" + }, + { + "id": "5", + "label": "Other" + } + ], + "roofType": [ + { + "id": "1", + "label": "Concrete" + }, + { + "id": "2", + "label": "Metal" + }, + { + "id": "3", + "label": "Asbestos" + }, + { + "id": "4", + "label": "Tiles" + }, + { + "id": "5", + "label": "Other" + } + ], + "wallType": [ + { + "id": "1", + "label": "Brick" + }, + { + "id": "2", + "label": "Stone" + }, + { + "id": "3", + "label": "Concrete" + }, + { + "id": "4", + "label": "Wood" + }, + { + "id": "5", + "label": "Other" + } + ], + "woodType": [ + { + "id": "1", + "label": "Teak" + }, + { + "id": "2", + "label": "Sal" + }, + { + "id": "3", + "label": "Rosewood" + }, + { + "id": "4", + "label": "Mango" + }, + { + "id": "5", + "label": "Other" + } + ], + "properties": [ + { + "id": "PRP-2024-001", + "type": "Survey", + "description": "New residential property verification required", + "address": "123 Gandhi Nagar, Guntur, Andhra Pradesh", + "dueDate": "2025-10-13", + "status": "High", + "phoneNumber": "+91 98765 43210", + "area": "35,400 sqft", + "propertyType": "Residential", + "isVerified": true, + "isDraft": false, + "isNew": false, + "createdDate": "2025-10-10" + }, + { + "id": "PRP-2024-002", + "type": "Survey", + "description": "Commercial property compliance check required", + "address": "456 Brodipet, Guntur, Andhra Pradesh", + "dueDate": "2025-10-20", + "status": "Medium", + "phoneNumber": "+91 98765 43211", + "area": "3,43,500 sqft", + "propertyType": "Commercial", + "isVerified": false, + "isDraft": true, + "isNew": false, + "createdDate": "2025-10-08" + }, + { + "id": "PRP-2025-003", + "type": "Survey", + "description": "Apartment complex verification pending final review", + "address": "789 Lakshmipuram, Guntur, Andhra Pradesh", + "dueDate": "2025-10-10", + "status": "Low", + "phoneNumber": "+91 98765 43212", + "area": "1,32,400 sqft", + "propertyType": "Residential", + "isVerified": false, + "isDraft": false, + "isNew": true, + "createdDate": "2025-10-13" + }, + { + "id": "PRP-2024-234", + "type": "Commercial", + "description": "456 Brodipet Main Road, Guntur, Andhra Pradesh 522002", + "address": "456 Brodipet Main Road, Guntur, Andhra Pradesh 522002", + "dueDate": "2025-10-15", + "status": "Medium", + "phoneNumber": "+91 98765 43213", + "area": "3,43,500 sqft", + "propertyType": "Commercial", + "isVerified": true, + "isDraft": false, + "isNew": false, + "createdDate": "2025-10-05" + }, + { + "id": "PRP-2024-324", + "type": "Residential", + "description": "231 Brodipet Main Road, Guntur, Andhra Pradesh 522002", + "address": "231 Brodipet Main Road, Guntur, Andhra Pradesh 522002", + "dueDate": "2025-10-18", + "status": "Low", + "phoneNumber": "+91 98765 43214", + "area": "1,32,400 sqft", + "propertyType": "Residential", + "isVerified": false, + "isDraft": true, + "isNew": false, + "createdDate": "2025-10-07" + }, + { + "id": "PRP-2025-005", + "type": "Survey", + "description": "New office complex verification required", + "address": "567 Ring Road, Guntur, Andhra Pradesh", + "dueDate": "2025-10-25", + "status": "High", + "phoneNumber": "+91 98765 43215", + "area": "2,45,000 sqft", + "propertyType": "Commercial", + "isVerified": false, + "isDraft": false, + "isNew": true, + "createdDate": "2025-10-12" + }, + { + "id": "PRP-2024-150", + "type": "Survey", + "description": "Residential villa verification completed", + "address": "890 Kothapet, Guntur, Andhra Pradesh", + "dueDate": "2025-10-05", + "status": "Low", + "phoneNumber": "+91 98765 43216", + "area": "5,200 sqft", + "propertyType": "Residential", + "isVerified": true, + "isDraft": false, + "isNew": false, + "createdDate": "2025-09-28" + }, + { + "id": "PRP-2024-403", + "type": "Survey", + "description": "Commercial property assessment draft", + "address": "456 Brodipet, Guntur, Andhra Pradesh, 522402", + "dueDate": "2025-10-10", + "status": "Medium", + "phoneNumber": "+91 98765 43217", + "area": "4,20,000 sqft", + "propertyType": "Commercial", + "isVerified": false, + "isDraft": true, + "isNew": false, + "createdDate": "2025-09-30" + } + ], + "location": { + "address": "123 Gandhi Nagar, Guntur, Andhra Pradesh 522003", + "coordinates": { + "lat": 16.2973, + "lng": 80.4364 + }, + "phoneNumber": "+91 39243 22342" + }, + "searchResults": [ + { + "id": "PRP-2024-001", + "type": "Residential", + "description": "123 Gandhi Nagar, Guntur, Andhra Pradesh 522003", + "address": "123 Gandhi Nagar, Guntur, Andhra Pradesh 522003", + "dueDate": "2025-10-13", + "status": "High", + "area": "35,400 sqft", + "isVerified": true, + "propertyType": "Residential" + }, + { + "id": "PRP-2024-234", + "type": "Commercial", + "description": "456 Brodipet Main Road, Guntur, Andhra Pradesh 522002", + "address": "456 Brodipet Main Road, Guntur, Andhra Pradesh 522002", + "dueDate": "2025-10-15", + "status": "Medium", + "area": "3,43,500 sqft", + "isVerified": true, + "propertyType": "Commercial" + }, + { + "id": "PRP-2024-324", + "type": "Residential", + "description": "231 Brodipet Main Road, Guntur, Andhra Pradesh 522002", + "address": "231 Brodipet Main Road, Guntur, Andhra Pradesh 522002", + "dueDate": "2025-10-18", + "status": "Low", + "area": "1,32,400 sqft", + "isVerified": false, + "propertyType": "Residential" + } + ], + "searchFields": [ + { + "value": "", + "label": "All", + "id": "b5f3" + }, + { + "value": "location", + "label": "Location", + "id": "d9f2" + }, + { + "value": "owner", + "label": "Owner Name", + "id": "a646" + }, + { + "value": "phone", + "label": "Phone Number", + "id": "e8a3" + } + ], + "messages": [ + { + "id": "MSG-001", + "title": "Property Tax Due - Gandhi Nagar", + "description": "Your property tax payment for PRP-2024-001 is due on Oct 15, 2025", + "date": "Oct 10, 2025", + "type": "tax", + "isRead": false, + "priority": "high" + }, + { + "id": "MSG-002", + "title": "Verification Complete - Brodipet", + "description": "Property verification for PRP-2024-002 has been completed successfully", + "date": "Oct 09, 2025", + "type": "verification", + "isRead": false, + "priority": "medium" + }, + { + "id": "MSG-003", + "title": "Document Update Required", + "description": "Please update ownership documents for property in Lakshmipuram", + "date": "Oct 08, 2025", + "type": "notification", + "isRead": true, + "priority": "medium" + }, + { + "id": "MSG-004", + "title": "Property Assessment Scheduled", + "description": "Assessment scheduled for Oct 20, 2025 for your commercial property", + "date": "Oct 07, 2025", + "type": "notification", + "isRead": true, + "priority": "low" + }, + { + "id": "MSG-005", + "title": "Tax Payment Confirmation", + "description": "Payment of โ‚น15,000 received for property tax PRP-2024-003", + "date": "Oct 05, 2025", + "type": "tax", + "isRead": true, + "priority": "low" + } + ], + "insights": { + "overview": [ + { + "id": "total-properties", + "title": "Total Properties", + "value": "7", + "change": "+2", + "trend": "up", + "period": "This Month" + }, + { + "id": "total-tax", + "title": "Total Tax Paid", + "value": "โ‚น45,000", + "change": "+โ‚น5,000", + "trend": "up", + "period": "This Year" + }, + { + "id": "pending-payments", + "title": "Pending Payments", + "value": "โ‚น12,000", + "change": "-โ‚น3,000", + "trend": "down", + "period": "Due This Month" + }, + { + "id": "avg-assessment", + "title": "Avg. Assessment Value", + "value": "โ‚น25,00,000", + "change": "+12%", + "trend": "up", + "period": "From Last Year" + } + ], + "properties": [ + { + "id": "prop-1", + "address": "123 Gandhi Nagar, Guntur", + "marketValue": "โ‚น32,00,000", + "taxAmount": "โ‚น15,000", + "lastAssessment": "Oct 2025", + "appreciation": "+8%" + }, + { + "id": "prop-2", + "address": "456 Brodipet, Guntur", + "marketValue": "โ‚น18,50,000", + "taxAmount": "โ‚น8,500", + "lastAssessment": "Sep 2025", + "appreciation": "+5%" + }, + { + "id": "prop-3", + "address": "789 Lakshmipuram, Guntur", + "marketValue": "โ‚น24,75,000", + "taxAmount": "โ‚น11,200", + "lastAssessment": "Aug 2025", + "appreciation": "+15%" + } + ] + }, + "isgrAdditionalOptions": [ + { "key": "lifts", "label": "Lifts" }, + { "key": "toilet", "label": "Toilet" }, + { "key": "watertap", "label": "Water Tap" }, + { "key": "cableConnection", "label": "Cable Connection" }, + { "key": "electricity", "label": "Electricity" }, + { "key": "attachedBathroom", "label": "Attached Bathroom" }, + { "key": "waterHarvesting", "label": "Water Harvesting" } + ] +} \ No newline at end of file diff --git a/frontend/mobile-ui/eslint.config.js b/frontend/mobile-ui/eslint.config.js new file mode 100644 index 0000000..b19330b --- /dev/null +++ b/frontend/mobile-ui/eslint.config.js @@ -0,0 +1,23 @@ +import js from '@eslint/js' +import globals from 'globals' +import reactHooks from 'eslint-plugin-react-hooks' +import reactRefresh from 'eslint-plugin-react-refresh' +import tseslint from 'typescript-eslint' +import { defineConfig, globalIgnores } from 'eslint/config' + +export default defineConfig([ + globalIgnores(['dist']), + { + files: ['**/*.{ts,tsx}'], + extends: [ + js.configs.recommended, + tseslint.configs.recommended, + reactHooks.configs['recommended-latest'], + reactRefresh.configs.vite, + ], + languageOptions: { + ecmaVersion: 2020, + globals: globals.browser, + }, + }, +]) diff --git a/frontend/mobile-ui/index.html b/frontend/mobile-ui/index.html new file mode 100644 index 0000000..e062e51 --- /dev/null +++ b/frontend/mobile-ui/index.html @@ -0,0 +1,52 @@ + + + + + + + + + + + + Property Tax Portal + + + +
+ + + + diff --git a/frontend/mobile-ui/package-lock.json b/frontend/mobile-ui/package-lock.json new file mode 100644 index 0000000..2cc258f --- /dev/null +++ b/frontend/mobile-ui/package-lock.json @@ -0,0 +1,6108 @@ +{ + "name": "egov-digit", + "version": "0.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "egov-digit", + "version": "0.0.0", + "dependencies": { + "@emotion/react": "^11.14.0", + "@emotion/styled": "^11.14.1", + "@mapbox/mapbox-gl-draw": "^1.5.1", + "@mui/icons-material": "^7.3.5", + "@mui/lab": "^7.0.1-beta.18", + "@mui/material": "^7.3.6", + "@mui/x-date-pickers": "^8.16.0", + "@reduxjs/toolkit": "^2.10.1", + "@types/leaflet": "^1.9.21", + "@types/react-redux": "^7.1.34", + "axios": "^1.12.2", + "clsx": "^2.1.1", + "date-fns": "^4.1.0", + "dayjs": "^1.11.19", + "dotenv": "^17.2.3", + "leaflet": "^1.9.4", + "leaflet-draw": "^1.0.4", + "maplibre-gl": "^5.14.0", + "react": "^19.2.1", + "react-datepicker": "^8.8.0", + "react-dom": "^19.2.1", + "react-icons": "^5.5.0", + "react-leaflet": "^5.0.0", + "react-map-gl": "^8.1.0", + "react-redux": "^9.2.0", + "react-router-dom": "^7.9.4", + "react-select": "^5.10.2", + "react-toastify": "^11.0.5", + "zod": "^4.1.12" + }, + "devDependencies": { + "@eslint/js": "^9.39.1", + "@types/leaflet-draw": "^1.0.13", + "@types/mapbox__mapbox-gl-draw": "^1.4.9", + "@types/node": "^24.6.0", + "@types/react": "^19.1.16", + "@types/react-dom": "^19.1.9", + "@vitejs/plugin-react": "^5.0.4", + "eslint": "^9.39.1", + "eslint-plugin-react-hooks": "^5.2.0", + "eslint-plugin-react-refresh": "^0.4.22", + "globals": "^16.4.0", + "json-server": "^1.0.0-beta.3", + "typescript": "~5.9.3", + "typescript-eslint": "^8.45.0", + "vite": "^7.2.4" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.27.1", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@babel/code-frame/-/code-frame-7.27.1.tgz", + "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.27.1", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.28.5", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@babel/compat-data/-/compat-data-7.28.5.tgz", + "integrity": "sha512-6uFXyCayocRbqhZOB+6XcuZbkMNimwfVGFji8CTZnCzOHVGvDqzvitu1re2AU5LROliz7eQPhB8CpAMvnx9EjA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.28.5", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@babel/core/-/core-7.28.5.tgz", + "integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@babel/generator": "^7.28.5", + "@babel/helper-compilation-targets": "^7.27.2", + "@babel/helper-module-transforms": "^7.28.3", + "@babel/helpers": "^7.28.4", + "@babel/parser": "^7.28.5", + "@babel/template": "^7.27.2", + "@babel/traverse": "^7.28.5", + "@babel/types": "^7.28.5", + "@jridgewell/remapping": "^2.3.5", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/core/node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@babel/generator": { + "version": "7.28.5", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@babel/generator/-/generator-7.28.5.tgz", + "integrity": "sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.28.5", + "@babel/types": "^7.28.5", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.27.2", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz", + "integrity": "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.27.2", + "@babel/helper-validator-option": "^7.27.1", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-globals": { + "version": "7.28.0", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@babel/helper-globals/-/helper-globals-7.28.0.tgz", + "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.27.1", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz", + "integrity": "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==", + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.28.3", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@babel/helper-module-transforms/-/helper-module-transforms-7.28.3.tgz", + "integrity": "sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1", + "@babel/traverse": "^7.28.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.27.1", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@babel/helper-plugin-utils/-/helper-plugin-utils-7.27.1.tgz", + "integrity": "sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.27.1", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.28.5", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", + "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.27.1", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", + "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.28.4", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@babel/helpers/-/helpers-7.28.4.tgz", + "integrity": "sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.27.2", + "@babel/types": "^7.28.4" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.28.5", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@babel/parser/-/parser-7.28.5.tgz", + "integrity": "sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.5" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-self": { + "version": "7.27.1", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.27.1.tgz", + "integrity": "sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-source": { + "version": "7.27.1", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.27.1.tgz", + "integrity": "sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/runtime": { + "version": "7.28.4", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@babel/runtime/-/runtime-7.28.4.tgz", + "integrity": "sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template": { + "version": "7.27.2", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@babel/template/-/template-7.27.2.tgz", + "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@babel/parser": "^7.27.2", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.28.5", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@babel/traverse/-/traverse-7.28.5.tgz", + "integrity": "sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@babel/generator": "^7.28.5", + "@babel/helper-globals": "^7.28.0", + "@babel/parser": "^7.28.5", + "@babel/template": "^7.27.2", + "@babel/types": "^7.28.5", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.28.5", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@babel/types/-/types-7.28.5.tgz", + "integrity": "sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==", + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@emotion/babel-plugin": { + "version": "11.13.5", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@emotion/babel-plugin/-/babel-plugin-11.13.5.tgz", + "integrity": "sha512-pxHCpT2ex+0q+HH91/zsdHkw/lXd468DIN2zvfvLtPKLLMo6gQj7oLObq8PhkrxOZb/gGCq03S3Z7PDhS8pduQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.16.7", + "@babel/runtime": "^7.18.3", + "@emotion/hash": "^0.9.2", + "@emotion/memoize": "^0.9.0", + "@emotion/serialize": "^1.3.3", + "babel-plugin-macros": "^3.1.0", + "convert-source-map": "^1.5.0", + "escape-string-regexp": "^4.0.0", + "find-root": "^1.1.0", + "source-map": "^0.5.7", + "stylis": "4.2.0" + } + }, + "node_modules/@emotion/cache": { + "version": "11.14.0", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@emotion/cache/-/cache-11.14.0.tgz", + "integrity": "sha512-L/B1lc/TViYk4DcpGxtAVbx0ZyiKM5ktoIyafGkH6zg/tj+mA+NE//aPYKG0k8kCHSHVJrpLpcAlOBEXQ3SavA==", + "license": "MIT", + "dependencies": { + "@emotion/memoize": "^0.9.0", + "@emotion/sheet": "^1.4.0", + "@emotion/utils": "^1.4.2", + "@emotion/weak-memoize": "^0.4.0", + "stylis": "4.2.0" + } + }, + "node_modules/@emotion/hash": { + "version": "0.9.2", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@emotion/hash/-/hash-0.9.2.tgz", + "integrity": "sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g==", + "license": "MIT" + }, + "node_modules/@emotion/is-prop-valid": { + "version": "1.4.0", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@emotion/is-prop-valid/-/is-prop-valid-1.4.0.tgz", + "integrity": "sha512-QgD4fyscGcbbKwJmqNvUMSE02OsHUa+lAWKdEUIJKgqe5IwRSKd7+KhibEWdaKwgjLj0DRSHA9biAIqGBk05lw==", + "license": "MIT", + "dependencies": { + "@emotion/memoize": "^0.9.0" + } + }, + "node_modules/@emotion/memoize": { + "version": "0.9.0", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@emotion/memoize/-/memoize-0.9.0.tgz", + "integrity": "sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ==", + "license": "MIT" + }, + "node_modules/@emotion/react": { + "version": "11.14.0", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@emotion/react/-/react-11.14.0.tgz", + "integrity": "sha512-O000MLDBDdk/EohJPFUqvnp4qnHeYkVP5B0xEG0D/L7cOKP9kefu2DXn8dj74cQfsEzUqh+sr1RzFqiL1o+PpA==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.18.3", + "@emotion/babel-plugin": "^11.13.5", + "@emotion/cache": "^11.14.0", + "@emotion/serialize": "^1.3.3", + "@emotion/use-insertion-effect-with-fallbacks": "^1.2.0", + "@emotion/utils": "^1.4.2", + "@emotion/weak-memoize": "^0.4.0", + "hoist-non-react-statics": "^3.3.1" + }, + "peerDependencies": { + "react": ">=16.8.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@emotion/serialize": { + "version": "1.3.3", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@emotion/serialize/-/serialize-1.3.3.tgz", + "integrity": "sha512-EISGqt7sSNWHGI76hC7x1CksiXPahbxEOrC5RjmFRJTqLyEK9/9hZvBbiYn70dw4wuwMKiEMCUlR6ZXTSWQqxA==", + "license": "MIT", + "dependencies": { + "@emotion/hash": "^0.9.2", + "@emotion/memoize": "^0.9.0", + "@emotion/unitless": "^0.10.0", + "@emotion/utils": "^1.4.2", + "csstype": "^3.0.2" + } + }, + "node_modules/@emotion/sheet": { + "version": "1.4.0", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@emotion/sheet/-/sheet-1.4.0.tgz", + "integrity": "sha512-fTBW9/8r2w3dXWYM4HCB1Rdp8NLibOw2+XELH5m5+AkWiL/KqYX6dc0kKYlaYyKjrQ6ds33MCdMPEwgs2z1rqg==", + "license": "MIT" + }, + "node_modules/@emotion/styled": { + "version": "11.14.1", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@emotion/styled/-/styled-11.14.1.tgz", + "integrity": "sha512-qEEJt42DuToa3gurlH4Qqc1kVpNq8wO8cJtDzU46TjlzWjDlsVyevtYCRijVq3SrHsROS+gVQ8Fnea108GnKzw==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.18.3", + "@emotion/babel-plugin": "^11.13.5", + "@emotion/is-prop-valid": "^1.3.0", + "@emotion/serialize": "^1.3.3", + "@emotion/use-insertion-effect-with-fallbacks": "^1.2.0", + "@emotion/utils": "^1.4.2" + }, + "peerDependencies": { + "@emotion/react": "^11.0.0-rc.0", + "react": ">=16.8.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@emotion/unitless": { + "version": "0.10.0", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@emotion/unitless/-/unitless-0.10.0.tgz", + "integrity": "sha512-dFoMUuQA20zvtVTuxZww6OHoJYgrzfKM1t52mVySDJnMSEa08ruEvdYQbhvyu6soU+NeLVd3yKfTfT0NeV6qGg==", + "license": "MIT" + }, + "node_modules/@emotion/use-insertion-effect-with-fallbacks": { + "version": "1.2.0", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.2.0.tgz", + "integrity": "sha512-yJMtVdH59sxi/aVJBpk9FQq+OR8ll5GT8oWd57UpeaKEVGab41JWaCFA7FRLoMLloOZF/c/wsPoe+bfGmRKgDg==", + "license": "MIT", + "peerDependencies": { + "react": ">=16.8.0" + } + }, + "node_modules/@emotion/utils": { + "version": "1.4.2", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@emotion/utils/-/utils-1.4.2.tgz", + "integrity": "sha512-3vLclRofFziIa3J2wDh9jjbkUz9qk5Vi3IZ/FSTKViB0k+ef0fPV7dYrUIugbgupYDx7v9ud/SjrtEP8Y4xLoA==", + "license": "MIT" + }, + "node_modules/@emotion/weak-memoize": { + "version": "0.4.0", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@emotion/weak-memoize/-/weak-memoize-0.4.0.tgz", + "integrity": "sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg==", + "license": "MIT" + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.25.12", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz", + "integrity": "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.25.12", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@esbuild/android-arm/-/android-arm-0.25.12.tgz", + "integrity": "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.25.12", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@esbuild/android-arm64/-/android-arm64-0.25.12.tgz", + "integrity": "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.25.12", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@esbuild/android-x64/-/android-x64-0.25.12.tgz", + "integrity": "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.25.12", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@esbuild/darwin-arm64/-/darwin-arm64-0.25.12.tgz", + "integrity": "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.25.12", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@esbuild/darwin-x64/-/darwin-x64-0.25.12.tgz", + "integrity": "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.25.12", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.12.tgz", + "integrity": "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.25.12", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@esbuild/freebsd-x64/-/freebsd-x64-0.25.12.tgz", + "integrity": "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.25.12", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@esbuild/linux-arm/-/linux-arm-0.25.12.tgz", + "integrity": "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.25.12", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@esbuild/linux-arm64/-/linux-arm64-0.25.12.tgz", + "integrity": "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.25.12", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@esbuild/linux-ia32/-/linux-ia32-0.25.12.tgz", + "integrity": "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.25.12", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@esbuild/linux-loong64/-/linux-loong64-0.25.12.tgz", + "integrity": "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.25.12", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@esbuild/linux-mips64el/-/linux-mips64el-0.25.12.tgz", + "integrity": "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.25.12", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@esbuild/linux-ppc64/-/linux-ppc64-0.25.12.tgz", + "integrity": "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.25.12", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@esbuild/linux-riscv64/-/linux-riscv64-0.25.12.tgz", + "integrity": "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.25.12", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@esbuild/linux-s390x/-/linux-s390x-0.25.12.tgz", + "integrity": "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.25.12", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@esbuild/linux-x64/-/linux-x64-0.25.12.tgz", + "integrity": "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.12", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.12.tgz", + "integrity": "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.25.12", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@esbuild/netbsd-x64/-/netbsd-x64-0.25.12.tgz", + "integrity": "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.25.12", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.12.tgz", + "integrity": "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.25.12", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@esbuild/openbsd-x64/-/openbsd-x64-0.25.12.tgz", + "integrity": "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.25.12", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.12.tgz", + "integrity": "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.25.12", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@esbuild/sunos-x64/-/sunos-x64-0.25.12.tgz", + "integrity": "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.25.12", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@esbuild/win32-arm64/-/win32-arm64-0.25.12.tgz", + "integrity": "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.25.12", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@esbuild/win32-ia32/-/win32-ia32-0.25.12.tgz", + "integrity": "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.25.12", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@esbuild/win32-x64/-/win32-x64-0.25.12.tgz", + "integrity": "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.9.0", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@eslint-community/eslint-utils/-/eslint-utils-4.9.0.tgz", + "integrity": "sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.12.2", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", + "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/config-array": { + "version": "0.21.1", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@eslint/config-array/-/config-array-0.21.1.tgz", + "integrity": "sha512-aw1gNayWpdI/jSYVgzN5pL0cfzU02GT3NBpeT/DXbx1/1x7ZKxFPd9bwrzygx/qiwIQiJ1sw/zD8qY/kRvlGHA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/object-schema": "^2.1.7", + "debug": "^4.3.1", + "minimatch": "^3.1.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/config-helpers": { + "version": "0.4.2", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@eslint/config-helpers/-/config-helpers-0.4.2.tgz", + "integrity": "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.17.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/core": { + "version": "0.17.0", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@eslint/core/-/core-0.17.0.tgz", + "integrity": "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "3.3.1", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@eslint/eslintrc/-/eslintrc-3.3.1.tgz", + "integrity": "sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^10.0.1", + "globals": "^14.0.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "14.0.0", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@eslint/js": { + "version": "9.39.1", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@eslint/js/-/js-9.39.1.tgz", + "integrity": "sha512-S26Stp4zCy88tH94QbBv3XCuzRQiZ9yXofEILmglYTh/Ug/a9/umqvgFtYBAo3Lp0nsI/5/qH1CCrbdK3AP1Tw==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + } + }, + "node_modules/@eslint/object-schema": { + "version": "2.1.7", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@eslint/object-schema/-/object-schema-2.1.7.tgz", + "integrity": "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/plugin-kit": { + "version": "0.4.1", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@eslint/plugin-kit/-/plugin-kit-0.4.1.tgz", + "integrity": "sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.17.0", + "levn": "^0.4.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@floating-ui/core": { + "version": "1.7.3", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@floating-ui/core/-/core-1.7.3.tgz", + "integrity": "sha512-sGnvb5dmrJaKEZ+LDIpguvdX3bDlEllmv4/ClQ9awcmCZrlx5jQyyMWFM5kBI+EyNOCDDiKk8il0zeuX3Zlg/w==", + "license": "MIT", + "dependencies": { + "@floating-ui/utils": "^0.2.10" + } + }, + "node_modules/@floating-ui/dom": { + "version": "1.7.4", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@floating-ui/dom/-/dom-1.7.4.tgz", + "integrity": "sha512-OOchDgh4F2CchOX94cRVqhvy7b3AFb+/rQXyswmzmGakRfkMgoWVjfnLWkRirfLEfuD4ysVW16eXzwt3jHIzKA==", + "license": "MIT", + "dependencies": { + "@floating-ui/core": "^1.7.3", + "@floating-ui/utils": "^0.2.10" + } + }, + "node_modules/@floating-ui/react": { + "version": "0.27.16", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@floating-ui/react/-/react-0.27.16.tgz", + "integrity": "sha512-9O8N4SeG2z++TSM8QA/KTeKFBVCNEz/AGS7gWPJf6KFRzmRWixFRnCnkPHRDwSVZW6QPDO6uT0P2SpWNKCc9/g==", + "license": "MIT", + "dependencies": { + "@floating-ui/react-dom": "^2.1.6", + "@floating-ui/utils": "^0.2.10", + "tabbable": "^6.0.0" + }, + "peerDependencies": { + "react": ">=17.0.0", + "react-dom": ">=17.0.0" + } + }, + "node_modules/@floating-ui/react-dom": { + "version": "2.1.6", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@floating-ui/react-dom/-/react-dom-2.1.6.tgz", + "integrity": "sha512-4JX6rEatQEvlmgU80wZyq9RT96HZJa88q8hp0pBd+LrczeDI4o6uA2M+uvxngVHo4Ihr8uibXxH6+70zhAFrVw==", + "license": "MIT", + "dependencies": { + "@floating-ui/dom": "^1.7.4" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@floating-ui/utils": { + "version": "0.2.10", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@floating-ui/utils/-/utils-0.2.10.tgz", + "integrity": "sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==", + "license": "MIT" + }, + "node_modules/@humanfs/core": { + "version": "0.19.1", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@humanfs/core/-/core-0.19.1.tgz", + "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node": { + "version": "0.16.7", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@humanfs/node/-/node-0.16.7.tgz", + "integrity": "sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/core": "^0.19.1", + "@humanwhocodes/retry": "^0.4.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/retry": { + "version": "0.4.3", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@humanwhocodes/retry/-/retry-0.4.3.tgz", + "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@mapbox/geojson-area": { + "version": "0.2.2", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm/@mapbox/geojson-area/-/geojson-area-0.2.2.tgz", + "integrity": "sha512-bBqqFn1kIbLBfn7Yq1PzzwVkPYQr9lVUeT8Dhd0NL5n76PBuXzOcuLV7GOSbEB1ia8qWxH4COCvFpziEu/yReA==", + "license": "BSD-2-Clause", + "dependencies": { + "wgs84": "0.0.0" + } + }, + "node_modules/@mapbox/geojson-normalize": { + "version": "0.0.1", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm/@mapbox/geojson-normalize/-/geojson-normalize-0.0.1.tgz", + "integrity": "sha512-82V7YHcle8lhgIGqEWwtXYN5cy0QM/OHq3ypGhQTbvHR57DF0vMHMjjVSQKFfVXBe/yWCBZTyOuzvK7DFFnx5Q==", + "license": "ISC", + "bin": { + "geojson-normalize": "geojson-normalize" + } + }, + "node_modules/@mapbox/geojson-rewind": { + "version": "0.5.2", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm/@mapbox/geojson-rewind/-/geojson-rewind-0.5.2.tgz", + "integrity": "sha512-tJaT+RbYGJYStt7wI3cq4Nl4SXxG8W7JDG5DMJu97V25RnbNg3QtQtf+KD+VLjNpWKYsRvXDNmNrBgEETr1ifA==", + "license": "ISC", + "dependencies": { + "get-stream": "^6.0.1", + "minimist": "^1.2.6" + }, + "bin": { + "geojson-rewind": "geojson-rewind" + } + }, + "node_modules/@mapbox/jsonlint-lines-primitives": { + "version": "2.0.2", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm/@mapbox/jsonlint-lines-primitives/-/jsonlint-lines-primitives-2.0.2.tgz", + "integrity": "sha512-rY0o9A5ECsTQRVhv7tL/OyDpGAoUB4tTvLiW1DSzQGq4bvTPhNw1VpSNjDJc5GFZ2XuyOtSWSVN05qOtcD71qQ==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/@mapbox/mapbox-gl-draw": { + "version": "1.5.1", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm/@mapbox/mapbox-gl-draw/-/mapbox-gl-draw-1.5.1.tgz", + "integrity": "sha512-DnR/oarZVoIrVHssAn+mtpuGzYH+ebORoPjow46zTBNPod/HQnvIZGtL6hIb5BVWxxH49RC9D20ipxiO9WDRxA==", + "license": "ISC", + "dependencies": { + "@mapbox/geojson-area": "^0.2.2", + "@mapbox/geojson-normalize": "^0.0.1", + "@mapbox/point-geometry": "^1.1.0", + "@turf/projection": "^7.2.0", + "fast-deep-equal": "^3.1.3", + "nanoid": "^5.0.9" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + } + }, + "node_modules/@mapbox/mapbox-gl-draw/node_modules/nanoid": { + "version": "5.1.6", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm/nanoid/-/nanoid-5.1.6.tgz", + "integrity": "sha512-c7+7RQ+dMB5dPwwCp4ee1/iV/q2P6aK1mTZcfr1BTuVlyW9hJYiMPybJCcnBlQtuSmTIWNeazm/zqNoZSSElBg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.js" + }, + "engines": { + "node": "^18 || >=20" + } + }, + "node_modules/@mapbox/mapbox-gl-supported": { + "version": "3.0.0", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm/@mapbox/mapbox-gl-supported/-/mapbox-gl-supported-3.0.0.tgz", + "integrity": "sha512-2XghOwu16ZwPJLOFVuIOaLbN0iKMn867evzXFyf0P22dqugezfJwLmdanAgU25ITvz1TvOfVP4jsDImlDJzcWg==", + "devOptional": true, + "license": "BSD-3-Clause" + }, + "node_modules/@mapbox/point-geometry": { + "version": "1.1.0", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm/@mapbox/point-geometry/-/point-geometry-1.1.0.tgz", + "integrity": "sha512-YGcBz1cg4ATXDCM/71L9xveh4dynfGmcLDqufR+nQQy3fKwsAZsWd/x4621/6uJaeB9mwOHE6hPeDgXz9uViUQ==", + "license": "ISC" + }, + "node_modules/@mapbox/tiny-sdf": { + "version": "2.0.7", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm/@mapbox/tiny-sdf/-/tiny-sdf-2.0.7.tgz", + "integrity": "sha512-25gQLQMcpivjOSA40g3gO6qgiFPDpWRoMfd+G/GoppPIeP6JDaMMkMrEJnMZhKyyS6iKwVt5YKu02vCUyJM3Ug==", + "license": "BSD-2-Clause" + }, + "node_modules/@mapbox/unitbezier": { + "version": "0.0.1", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm/@mapbox/unitbezier/-/unitbezier-0.0.1.tgz", + "integrity": "sha512-nMkuDXFv60aBr9soUG5q+GvZYL+2KZHVvsqFCzqnkGEf46U2fvmytHaEVc1/YZbiLn8X+eR3QzX1+dwDO1lxlw==", + "license": "BSD-2-Clause" + }, + "node_modules/@mapbox/vector-tile": { + "version": "2.0.4", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm/@mapbox/vector-tile/-/vector-tile-2.0.4.tgz", + "integrity": "sha512-AkOLcbgGTdXScosBWwmmD7cDlvOjkg/DetGva26pIRiZPdeJYjYKarIlb4uxVzi6bwHO6EWH82eZ5Nuv4T5DUg==", + "license": "BSD-3-Clause", + "dependencies": { + "@mapbox/point-geometry": "~1.1.0", + "@types/geojson": "^7946.0.16", + "pbf": "^4.0.1" + } + }, + "node_modules/@mapbox/whoots-js": { + "version": "3.1.0", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm/@mapbox/whoots-js/-/whoots-js-3.1.0.tgz", + "integrity": "sha512-Es6WcD0nO5l+2BOQS4uLfNPYQaNDfbot3X1XUoloz+x0mPDS3eeORZJl06HXjwBG1fOGwCRnzK88LMdxKRrd6Q==", + "license": "ISC", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@maplibre/maplibre-gl-style-spec": { + "version": "24.3.1", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm/@maplibre/maplibre-gl-style-spec/-/maplibre-gl-style-spec-24.3.1.tgz", + "integrity": "sha512-TUM5JD40H2mgtVXl5IwWz03BuQabw8oZQLJTmPpJA0YTYF+B+oZppy5lNMO6bMvHzB+/5mxqW9VLG3wFdeqtOw==", + "license": "ISC", + "dependencies": { + "@mapbox/jsonlint-lines-primitives": "~2.0.2", + "@mapbox/unitbezier": "^0.0.1", + "json-stringify-pretty-compact": "^4.0.0", + "minimist": "^1.2.8", + "quickselect": "^3.0.0", + "rw": "^1.3.3", + "tinyqueue": "^3.0.0" + }, + "bin": { + "gl-style-format": "dist/gl-style-format.mjs", + "gl-style-migrate": "dist/gl-style-migrate.mjs", + "gl-style-validate": "dist/gl-style-validate.mjs" + } + }, + "node_modules/@maplibre/mlt": { + "version": "1.1.2", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm/@maplibre/mlt/-/mlt-1.1.2.tgz", + "integrity": "sha512-SQKdJ909VGROkA6ovJgtHNs9YXV4YXUPS+VaZ50I2Mt951SLlUm2Cv34x5Xwc1HiFlsd3h2Yrs5cn7xzqBmENw==", + "license": "(MIT OR Apache-2.0)", + "dependencies": { + "@mapbox/point-geometry": "^1.1.0" + } + }, + "node_modules/@maplibre/vt-pbf": { + "version": "4.1.0", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm/@maplibre/vt-pbf/-/vt-pbf-4.1.0.tgz", + "integrity": "sha512-9LjFAoWtxdGRns8RK9vG3Fcw/fb3eHMxvAn2jffwn3jnVO1k49VOv6+FEza70rK7WzF8GnBiKa0K39RyfevKUw==", + "license": "MIT", + "dependencies": { + "@mapbox/point-geometry": "^1.1.0", + "@mapbox/vector-tile": "^2.0.4", + "@types/geojson-vt": "3.2.5", + "@types/supercluster": "^7.1.3", + "geojson-vt": "^4.0.2", + "pbf": "^4.0.1", + "supercluster": "^8.0.1" + } + }, + "node_modules/@mui/core-downloads-tracker": { + "version": "7.3.6", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@mui/core-downloads-tracker/-/core-downloads-tracker-7.3.6.tgz", + "integrity": "sha512-QaYtTHlr8kDFN5mE1wbvVARRKH7Fdw1ZuOjBJcFdVpfNfRYKF3QLT4rt+WaB6CKJvpqxRsmEo0kpYinhH5GeHg==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + } + }, + "node_modules/@mui/icons-material": { + "version": "7.3.5", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@mui/icons-material/-/icons-material-7.3.5.tgz", + "integrity": "sha512-LciL1GLMZ+VlzyHAALSVAR22t8IST4LCXmljcUSx2NOutgO2XnxdIp8ilFbeNf9wpo0iUFbAuoQcB7h+HHIf3A==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.28.4" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@mui/material": "^7.3.5", + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/lab": { + "version": "7.0.1-beta.19", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@mui/lab/-/lab-7.0.1-beta.19.tgz", + "integrity": "sha512-Ekxd2mPnr5iKwrMXjN/y2xgpxPX8ithBBcDenjqNdBt/ZQumrmBl0ifVoqAHsL6lxN6DOgRsWTRc4eOdDiB+0Q==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.28.4", + "@mui/system": "^7.3.5", + "@mui/types": "^7.4.8", + "@mui/utils": "^7.3.5", + "clsx": "^2.1.1", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@emotion/react": "^11.5.0", + "@emotion/styled": "^11.3.0", + "@mui/material": "^7.3.5", + "@mui/material-pigment-css": "^7.3.5", + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@emotion/react": { + "optional": true + }, + "@emotion/styled": { + "optional": true + }, + "@mui/material-pigment-css": { + "optional": true + }, + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/material": { + "version": "7.3.6", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@mui/material/-/material-7.3.6.tgz", + "integrity": "sha512-R4DaYF3dgCQCUAkr4wW1w26GHXcf5rCmBRHVBuuvJvaGLmZdD8EjatP80Nz5JCw0KxORAzwftnHzXVnjR8HnFw==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.28.4", + "@mui/core-downloads-tracker": "^7.3.6", + "@mui/system": "^7.3.6", + "@mui/types": "^7.4.9", + "@mui/utils": "^7.3.6", + "@popperjs/core": "^2.11.8", + "@types/react-transition-group": "^4.4.12", + "clsx": "^2.1.1", + "csstype": "^3.1.3", + "prop-types": "^15.8.1", + "react-is": "^19.2.0", + "react-transition-group": "^4.4.5" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@emotion/react": "^11.5.0", + "@emotion/styled": "^11.3.0", + "@mui/material-pigment-css": "^7.3.6", + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@emotion/react": { + "optional": true + }, + "@emotion/styled": { + "optional": true + }, + "@mui/material-pigment-css": { + "optional": true + }, + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/private-theming": { + "version": "7.3.6", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@mui/private-theming/-/private-theming-7.3.6.tgz", + "integrity": "sha512-Ws9wZpqM+FlnbZXaY/7yvyvWQo1+02Tbx50mVdNmzWEi51C51y56KAbaDCYyulOOBL6BJxuaqG8rNNuj7ivVyw==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.28.4", + "@mui/utils": "^7.3.6", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/styled-engine": { + "version": "7.3.6", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@mui/styled-engine/-/styled-engine-7.3.6.tgz", + "integrity": "sha512-+wiYbtvj+zyUkmDB+ysH6zRjuQIJ+CM56w0fEXV+VDNdvOuSywG+/8kpjddvvlfMLsaWdQe5oTuYGBcodmqGzQ==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.28.4", + "@emotion/cache": "^11.14.0", + "@emotion/serialize": "^1.3.3", + "@emotion/sheet": "^1.4.0", + "csstype": "^3.1.3", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@emotion/react": "^11.4.1", + "@emotion/styled": "^11.3.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@emotion/react": { + "optional": true + }, + "@emotion/styled": { + "optional": true + } + } + }, + "node_modules/@mui/system": { + "version": "7.3.6", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@mui/system/-/system-7.3.6.tgz", + "integrity": "sha512-8fehAazkHNP1imMrdD2m2hbA9sl7Ur6jfuNweh5o4l9YPty4iaZzRXqYvBCWQNwFaSHmMEj2KPbyXGp7Bt73Rg==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.28.4", + "@mui/private-theming": "^7.3.6", + "@mui/styled-engine": "^7.3.6", + "@mui/types": "^7.4.9", + "@mui/utils": "^7.3.6", + "clsx": "^2.1.1", + "csstype": "^3.1.3", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@emotion/react": "^11.5.0", + "@emotion/styled": "^11.3.0", + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@emotion/react": { + "optional": true + }, + "@emotion/styled": { + "optional": true + }, + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/types": { + "version": "7.4.9", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@mui/types/-/types-7.4.9.tgz", + "integrity": "sha512-dNO8Z9T2cujkSIaCnWwprfeKmTWh97cnjkgmpFJ2sbfXLx8SMZijCYHOtP/y5nnUb/Rm2omxbDMmtUoSaUtKaw==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.28.4" + }, + "peerDependencies": { + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/utils": { + "version": "7.3.6", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@mui/utils/-/utils-7.3.6.tgz", + "integrity": "sha512-jn+Ba02O6PiFs7nKva8R2aJJ9kJC+3kQ2R0BbKNY3KQQ36Qng98GnPRFTlbwYTdMD6hLEBKaMLUktyg/rTfd2w==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.28.4", + "@mui/types": "^7.4.9", + "@types/prop-types": "^15.7.15", + "clsx": "^2.1.1", + "prop-types": "^15.8.1", + "react-is": "^19.2.0" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/x-date-pickers": { + "version": "8.19.0", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@mui/x-date-pickers/-/x-date-pickers-8.19.0.tgz", + "integrity": "sha512-TQ4FsGUsiGJVs+Ie4q7nHXUmFqZADXL/1hVtZpOKsdr3WQXwpX7C5YmeakZGFR2NZnuv4snFj+WTee3kgyFbyQ==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.28.4", + "@mui/utils": "^7.3.5", + "@mui/x-internals": "8.19.0", + "@types/react-transition-group": "^4.4.12", + "clsx": "^2.1.1", + "prop-types": "^15.8.1", + "react-transition-group": "^4.4.5" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@emotion/react": "^11.9.0", + "@emotion/styled": "^11.8.1", + "@mui/material": "^5.15.14 || ^6.0.0 || ^7.0.0", + "@mui/system": "^5.15.14 || ^6.0.0 || ^7.0.0", + "date-fns": "^2.25.0 || ^3.2.0 || ^4.0.0", + "date-fns-jalali": "^2.13.0-0 || ^3.2.0-0 || ^4.0.0-0", + "dayjs": "^1.10.7", + "luxon": "^3.0.2", + "moment": "^2.29.4", + "moment-hijri": "^2.1.2 || ^3.0.0", + "moment-jalaali": "^0.7.4 || ^0.8.0 || ^0.9.0 || ^0.10.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@emotion/react": { + "optional": true + }, + "@emotion/styled": { + "optional": true + }, + "date-fns": { + "optional": true + }, + "date-fns-jalali": { + "optional": true + }, + "dayjs": { + "optional": true + }, + "luxon": { + "optional": true + }, + "moment": { + "optional": true + }, + "moment-hijri": { + "optional": true + }, + "moment-jalaali": { + "optional": true + } + } + }, + "node_modules/@mui/x-internals": { + "version": "8.19.0", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@mui/x-internals/-/x-internals-8.19.0.tgz", + "integrity": "sha512-mMmiyJAN5fW27srXJjhXhXJa+w2xGO45rwcjws6OQc9rdXGdJqRXhBwJd+OT7J1xwSdFIIUhjZRTz1KAfCSGBg==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.28.4", + "@mui/utils": "^7.3.5", + "reselect": "^5.1.1", + "use-sync-external-store": "^1.6.0" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "react": "^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/@polka/url": { + "version": "1.0.0-next.29", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@polka/url/-/url-1.0.0-next.29.tgz", + "integrity": "sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==", + "dev": true, + "license": "MIT" + }, + "node_modules/@popperjs/core": { + "version": "2.11.8", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@popperjs/core/-/core-2.11.8.tgz", + "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/popperjs" + } + }, + "node_modules/@react-leaflet/core": { + "version": "3.0.0", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@react-leaflet/core/-/core-3.0.0.tgz", + "integrity": "sha512-3EWmekh4Nz+pGcr+xjf0KNyYfC3U2JjnkWsh0zcqaexYqmmB5ZhH37kz41JXGmKzpaMZCnPofBBm64i+YrEvGQ==", + "license": "Hippocratic-2.1", + "peerDependencies": { + "leaflet": "^1.9.0", + "react": "^19.0.0", + "react-dom": "^19.0.0" + } + }, + "node_modules/@reduxjs/toolkit": { + "version": "2.11.0", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@reduxjs/toolkit/-/toolkit-2.11.0.tgz", + "integrity": "sha512-hBjYg0aaRL1O2Z0IqWhnTLytnjDIxekmRxm1snsHjHaKVmIF1HiImWqsq+PuEbn6zdMlkIj9WofK1vR8jjx+Xw==", + "license": "MIT", + "dependencies": { + "@standard-schema/spec": "^1.0.0", + "@standard-schema/utils": "^0.3.0", + "immer": "^11.0.0", + "redux": "^5.0.1", + "redux-thunk": "^3.1.0", + "reselect": "^5.1.0" + }, + "peerDependencies": { + "react": "^16.9.0 || ^17.0.0 || ^18 || ^19", + "react-redux": "^7.2.1 || ^8.1.3 || ^9.0.0" + }, + "peerDependenciesMeta": { + "react": { + "optional": true + }, + "react-redux": { + "optional": true + } + } + }, + "node_modules/@rolldown/pluginutils": { + "version": "1.0.0-beta.47", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.47.tgz", + "integrity": "sha512-8QagwMH3kNCuzD8EWL8R2YPW5e4OrHNSAHRFDdmFqEwEaD/KcNKjVoumo+gP2vW5eKB2UPbM6vTYiGZX0ixLnw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.53.3", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.53.3.tgz", + "integrity": "sha512-mRSi+4cBjrRLoaal2PnqH82Wqyb+d3HsPUN/W+WslCXsZsyHa9ZeQQX/pQsZaVIWDkPcpV6jJ+3KLbTbgnwv8w==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.53.3", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.53.3.tgz", + "integrity": "sha512-CbDGaMpdE9sh7sCmTrTUyllhrg65t6SwhjlMJsLr+J8YjFuPmCEjbBSx4Z/e4SmDyH3aB5hGaJUP2ltV/vcs4w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.53.3", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.53.3.tgz", + "integrity": "sha512-Nr7SlQeqIBpOV6BHHGZgYBuSdanCXuw09hon14MGOLGmXAFYjx1wNvquVPmpZnl0tLjg25dEdr4IQ6GgyToCUA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.53.3", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.53.3.tgz", + "integrity": "sha512-DZ8N4CSNfl965CmPktJ8oBnfYr3F8dTTNBQkRlffnUarJ2ohudQD17sZBa097J8xhQ26AwhHJ5mvUyQW8ddTsQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.53.3", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.53.3.tgz", + "integrity": "sha512-yMTrCrK92aGyi7GuDNtGn2sNW+Gdb4vErx4t3Gv/Tr+1zRb8ax4z8GWVRfr3Jw8zJWvpGHNpss3vVlbF58DZ4w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.53.3", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.53.3.tgz", + "integrity": "sha512-lMfF8X7QhdQzseM6XaX0vbno2m3hlyZFhwcndRMw8fbAGUGL3WFMBdK0hbUBIUYcEcMhVLr1SIamDeuLBnXS+Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.53.3", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.53.3.tgz", + "integrity": "sha512-k9oD15soC/Ln6d2Wv/JOFPzZXIAIFLp6B+i14KhxAfnq76ajt0EhYc5YPeX6W1xJkAdItcVT+JhKl1QZh44/qw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.53.3", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.53.3.tgz", + "integrity": "sha512-vTNlKq+N6CK/8UktsrFuc+/7NlEYVxgaEgRXVUVK258Z5ymho29skzW1sutgYjqNnquGwVUObAaxae8rZ6YMhg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.53.3", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.53.3.tgz", + "integrity": "sha512-RGrFLWgMhSxRs/EWJMIFM1O5Mzuz3Xy3/mnxJp/5cVhZ2XoCAxJnmNsEyeMJtpK+wu0FJFWz+QF4mjCA7AUQ3w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.53.3", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.53.3.tgz", + "integrity": "sha512-kASyvfBEWYPEwe0Qv4nfu6pNkITLTb32p4yTgzFCocHnJLAHs+9LjUu9ONIhvfT/5lv4YS5muBHyuV84epBo/A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.53.3", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.53.3.tgz", + "integrity": "sha512-JiuKcp2teLJwQ7vkJ95EwESWkNRFJD7TQgYmCnrPtlu50b4XvT5MOmurWNrCj3IFdyjBQ5p9vnrX4JM6I8OE7g==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.53.3", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.53.3.tgz", + "integrity": "sha512-EoGSa8nd6d3T7zLuqdojxC20oBfNT8nexBbB/rkxgKj5T5vhpAQKKnD+h3UkoMuTyXkP5jTjK/ccNRmQrPNDuw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.53.3", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.53.3.tgz", + "integrity": "sha512-4s+Wped2IHXHPnAEbIB0YWBv7SDohqxobiiPA1FIWZpX+w9o2i4LezzH/NkFUl8LRci/8udci6cLq+jJQlh+0g==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.53.3", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.53.3.tgz", + "integrity": "sha512-68k2g7+0vs2u9CxDt5ktXTngsxOQkSEV/xBbwlqYcUrAVh6P9EgMZvFsnHy4SEiUl46Xf0IObWVbMvPrr2gw8A==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.53.3", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.53.3.tgz", + "integrity": "sha512-VYsFMpULAz87ZW6BVYw3I6sWesGpsP9OPcyKe8ofdg9LHxSbRMd7zrVrr5xi/3kMZtpWL/wC+UIJWJYVX5uTKg==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.53.3", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.53.3.tgz", + "integrity": "sha512-3EhFi1FU6YL8HTUJZ51imGJWEX//ajQPfqWLI3BQq4TlvHy4X0MOr5q3D2Zof/ka0d5FNdPwZXm3Yyib/UEd+w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.53.3", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.53.3.tgz", + "integrity": "sha512-eoROhjcc6HbZCJr+tvVT8X4fW3/5g/WkGvvmwz/88sDtSJzO7r/blvoBDgISDiCjDRZmHpwud7h+6Q9JxFwq1Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.53.3", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.53.3.tgz", + "integrity": "sha512-OueLAWgrNSPGAdUdIjSWXw+u/02BRTcnfw9PN41D2vq/JSEPnJnVuBgw18VkN8wcd4fjUs+jFHVM4t9+kBSNLw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.53.3", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.53.3.tgz", + "integrity": "sha512-GOFuKpsxR/whszbF/bzydebLiXIHSgsEUp6M0JI8dWvi+fFa1TD6YQa4aSZHtpmh2/uAlj/Dy+nmby3TJ3pkTw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.53.3", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.53.3.tgz", + "integrity": "sha512-iah+THLcBJdpfZ1TstDFbKNznlzoxa8fmnFYK4V67HvmuNYkVdAywJSoteUszvBQ9/HqN2+9AZghbajMsFT+oA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.53.3", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.53.3.tgz", + "integrity": "sha512-J9QDiOIZlZLdcot5NXEepDkstocktoVjkaKUtqzgzpt2yWjGlbYiKyp05rWwk4nypbYUNoFAztEgixoLaSETkg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.53.3", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.53.3.tgz", + "integrity": "sha512-UhTd8u31dXadv0MopwGgNOBpUVROFKWVQgAg5N1ESyCz8AuBcMqm4AuTjrwgQKGDfoFuz02EuMRHQIw/frmYKQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@standard-schema/spec": { + "version": "1.0.0", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@standard-schema/spec/-/spec-1.0.0.tgz", + "integrity": "sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA==", + "license": "MIT" + }, + "node_modules/@standard-schema/utils": { + "version": "0.3.0", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@standard-schema/utils/-/utils-0.3.0.tgz", + "integrity": "sha512-e7Mew686owMaPJVNNLs55PUvgz371nKgwsc4vxE49zsODpJEnxgxRo2y/OKrqueavXgZNMDVj3DdHFlaSAeU8g==", + "license": "MIT" + }, + "node_modules/@tinyhttp/accepts": { + "version": "2.2.3", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@tinyhttp/accepts/-/accepts-2.2.3.tgz", + "integrity": "sha512-9pQN6pJAJOU3McmdJWTcyq7LLFW8Lj5q+DadyKcvp+sxMkEpktKX5sbfJgJuOvjk6+1xWl7pe0YL1US1vaO/1w==", + "dev": true, + "license": "MIT", + "dependencies": { + "mime": "4.0.4", + "negotiator": "^0.6.3" + }, + "engines": { + "node": ">=12.20.0" + }, + "funding": { + "type": "individual", + "url": "https://github.com/tinyhttp/tinyhttp?sponsor=1" + } + }, + "node_modules/@tinyhttp/app": { + "version": "2.5.2", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@tinyhttp/app/-/app-2.5.2.tgz", + "integrity": "sha512-DcB3Y8GQppLQlO2VxRYF7LzTEAoZb+VRQXuIsErcu2fNaM1xdx6NQZDso5rlZUiaeg6KYYRfU34N4XkZbv6jSA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@tinyhttp/cookie": "2.1.1", + "@tinyhttp/proxy-addr": "2.2.1", + "@tinyhttp/req": "2.2.5", + "@tinyhttp/res": "2.2.5", + "@tinyhttp/router": "2.2.3", + "header-range-parser": "1.1.3", + "regexparam": "^2.0.2" + }, + "engines": { + "node": ">=14.21.3" + }, + "funding": { + "type": "individual", + "url": "https://github.com/tinyhttp/tinyhttp?sponsor=1" + } + }, + "node_modules/@tinyhttp/content-disposition": { + "version": "2.2.2", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@tinyhttp/content-disposition/-/content-disposition-2.2.2.tgz", + "integrity": "sha512-crXw1txzrS36huQOyQGYFvhTeLeG0Si1xu+/l6kXUVYpE0TjFjEZRqTbuadQLfKGZ0jaI+jJoRyqaWwxOSHW2g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.20.0" + }, + "funding": { + "type": "individual", + "url": "https://github.com/tinyhttp/tinyhttp?sponsor=1" + } + }, + "node_modules/@tinyhttp/content-type": { + "version": "0.1.4", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@tinyhttp/content-type/-/content-type-0.1.4.tgz", + "integrity": "sha512-dl6f3SHIJPYbhsW1oXdrqOmLSQF/Ctlv3JnNfXAE22kIP7FosqJHxkz/qj2gv465prG8ODKH5KEyhBkvwrueKQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.4" + } + }, + "node_modules/@tinyhttp/cookie": { + "version": "2.1.1", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@tinyhttp/cookie/-/cookie-2.1.1.tgz", + "integrity": "sha512-h/kL9jY0e0Dvad+/QU3efKZww0aTvZJslaHj3JTPmIPC9Oan9+kYqmh3M6L5JUQRuTJYFK2nzgL2iJtH2S+6dA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.20.0" + }, + "funding": { + "type": "individual", + "url": "https://github.com/tinyhttp/tinyhttp?sponsor=1" + } + }, + "node_modules/@tinyhttp/cookie-signature": { + "version": "2.1.1", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@tinyhttp/cookie-signature/-/cookie-signature-2.1.1.tgz", + "integrity": "sha512-VDsSMY5OJfQJIAtUgeQYhqMPSZptehFSfvEEtxr+4nldPA8IImlp3QVcOVuK985g4AFR4Hl1sCbWCXoqBnVWnw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.20.0" + } + }, + "node_modules/@tinyhttp/cors": { + "version": "2.0.1", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@tinyhttp/cors/-/cors-2.0.1.tgz", + "integrity": "sha512-qrmo6WJuaiCzKWagv2yA/kw6hIISfF/hOqPWwmI6w0o8apeTMmRN3DoCFvQ/wNVuWVdU5J4KU7OX8aaSOEq51A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@tinyhttp/vary": "^0.1.3" + }, + "engines": { + "node": ">=12.20 || 14.x || >=16" + } + }, + "node_modules/@tinyhttp/encode-url": { + "version": "2.1.1", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@tinyhttp/encode-url/-/encode-url-2.1.1.tgz", + "integrity": "sha512-AhY+JqdZ56qV77tzrBm0qThXORbsVjs/IOPgGCS7x/wWnsa/Bx30zDUU/jPAUcSzNOzt860x9fhdGpzdqbUeUw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.20.0" + } + }, + "node_modules/@tinyhttp/etag": { + "version": "2.1.2", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@tinyhttp/etag/-/etag-2.1.2.tgz", + "integrity": "sha512-j80fPKimGqdmMh6962y+BtQsnYPVCzZfJw0HXjyH70VaJBHLKGF+iYhcKqzI3yef6QBNa8DKIPsbEYpuwApXTw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.20.0" + } + }, + "node_modules/@tinyhttp/forwarded": { + "version": "2.1.2", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@tinyhttp/forwarded/-/forwarded-2.1.2.tgz", + "integrity": "sha512-9H/eulJ68ElY/+zYpTpNhZ7vxGV+cnwaR6+oQSm7bVgZMyuQfgROW/qvZuhmgDTIxnGMXst+Ba4ij6w6Krcs3w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.20.0" + } + }, + "node_modules/@tinyhttp/logger": { + "version": "2.1.0", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@tinyhttp/logger/-/logger-2.1.0.tgz", + "integrity": "sha512-Ma1fJ9CwUbn9r61/4HW6+nflsVoslpOnCrfQ6UeZq7GGIgwLzofms3HoSVG7M+AyRMJpxlfcDdbH5oFVroDMKA==", + "dev": true, + "license": "MIT", + "dependencies": { + "colorette": "^2.0.20", + "dayjs": "^1.11.13", + "http-status-emojis": "^2.2.0" + }, + "engines": { + "node": ">=14.18 || >=16.20" + } + }, + "node_modules/@tinyhttp/proxy-addr": { + "version": "2.2.1", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@tinyhttp/proxy-addr/-/proxy-addr-2.2.1.tgz", + "integrity": "sha512-BicqMqVI91hHq2BQmnqJUh0FQUnx7DncwSGgu2ghlh+JZG2rHK2ZN/rXkfhrx1rrUw6hnd0L36O8GPMh01+dDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@tinyhttp/forwarded": "2.1.2", + "ipaddr.js": "^2.2.0" + }, + "engines": { + "node": ">=12.20.0" + } + }, + "node_modules/@tinyhttp/req": { + "version": "2.2.5", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@tinyhttp/req/-/req-2.2.5.tgz", + "integrity": "sha512-trfsXwtmsNjMcGKcLJ+45h912kLRqBQCQD06ams3Tq0kf4gHLxjHjoYOC1Z9yGjOn81XllRx8wqvnvr+Kbe3gw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@tinyhttp/accepts": "2.2.3", + "@tinyhttp/type-is": "2.2.4", + "@tinyhttp/url": "2.1.1", + "header-range-parser": "^1.1.3" + }, + "engines": { + "node": ">=12.20.0" + } + }, + "node_modules/@tinyhttp/res": { + "version": "2.2.5", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@tinyhttp/res/-/res-2.2.5.tgz", + "integrity": "sha512-yBsqjWygpuKAVz4moWlP4hqzwiDDqfrn2mA0wviJAcgvGiyOErtlQwXY7aj3aPiCpURvxvEFO//Gdy6yV+xEpA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@tinyhttp/content-disposition": "2.2.2", + "@tinyhttp/cookie": "2.1.1", + "@tinyhttp/cookie-signature": "2.1.1", + "@tinyhttp/encode-url": "2.1.1", + "@tinyhttp/req": "2.2.5", + "@tinyhttp/send": "2.2.3", + "@tinyhttp/vary": "^0.1.3", + "es-escape-html": "^0.1.1", + "mime": "4.0.4" + }, + "engines": { + "node": ">=12.20.0" + } + }, + "node_modules/@tinyhttp/router": { + "version": "2.2.3", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@tinyhttp/router/-/router-2.2.3.tgz", + "integrity": "sha512-O0MQqWV3Vpg/uXsMYg19XsIgOhwjyhTYWh51Qng7bxqXixxx2PEvZWnFjP7c84K7kU/nUX41KpkEBTLnznk9/Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.20.0" + } + }, + "node_modules/@tinyhttp/send": { + "version": "2.2.3", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@tinyhttp/send/-/send-2.2.3.tgz", + "integrity": "sha512-o4cVHHGQ8WjVBS8UT0EE/2WnjoybrfXikHwsRoNlG1pfrC/Sd01u1N4Te8cOd/9aNGLr4mGxWb5qTm2RRtEi7g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@tinyhttp/content-type": "^0.1.4", + "@tinyhttp/etag": "2.1.2", + "mime": "4.0.4" + }, + "engines": { + "node": ">=12.20.0" + } + }, + "node_modules/@tinyhttp/type-is": { + "version": "2.2.4", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@tinyhttp/type-is/-/type-is-2.2.4.tgz", + "integrity": "sha512-7F328NheridwjIfefBB2j1PEcKKABpADgv7aCJaE8x8EON77ZFrAkI3Rir7pGjopV7V9MBmW88xUQigBEX2rmQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@tinyhttp/content-type": "^0.1.4", + "mime": "4.0.4" + }, + "engines": { + "node": ">=12.20.0" + } + }, + "node_modules/@tinyhttp/url": { + "version": "2.1.1", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@tinyhttp/url/-/url-2.1.1.tgz", + "integrity": "sha512-POJeq2GQ5jI7Zrdmj22JqOijB5/GeX+LEX7DUdml1hUnGbJOTWDx7zf2b5cCERj7RoXL67zTgyzVblBJC+NJWg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.20.0" + } + }, + "node_modules/@tinyhttp/vary": { + "version": "0.1.3", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@tinyhttp/vary/-/vary-0.1.3.tgz", + "integrity": "sha512-SoL83sQXAGiHN1jm2VwLUWQSQeDAAl1ywOm6T0b0Cg1CZhVsjoiZadmjhxF6FHCCY7OHHVaLnTgSMxTPIDLxMg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.20" + } + }, + "node_modules/@turf/clone": { + "version": "7.3.1", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@turf/clone/-/clone-7.3.1.tgz", + "integrity": "sha512-r7xDOfw9ohA7PhZW+8X9RMsO4szB4YqkhEROaELJyLtQ1bo8VNFtndpZdE6YHQpD7Pjlvlb6i99q8w1QLisEPg==", + "license": "MIT", + "dependencies": { + "@turf/helpers": "7.3.1", + "@types/geojson": "^7946.0.10", + "tslib": "^2.8.1" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/helpers": { + "version": "7.3.1", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@turf/helpers/-/helpers-7.3.1.tgz", + "integrity": "sha512-zkL34JVhi5XhsuMEO0MUTIIFEJ8yiW1InMu4hu/oRqamlY4mMoZql0viEmH6Dafh/p+zOl8OYvMJ3Vm3rFshgg==", + "license": "MIT", + "dependencies": { + "@types/geojson": "^7946.0.10", + "tslib": "^2.8.1" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/meta": { + "version": "7.3.1", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@turf/meta/-/meta-7.3.1.tgz", + "integrity": "sha512-NWsfOE5RVtWpLQNkfOF/RrYvLRPwwruxhZUV0UFIzHqfiRJ50aO9Y6uLY4bwCUe2TumLJQSR4yaoA72Rmr2mnQ==", + "license": "MIT", + "dependencies": { + "@turf/helpers": "7.3.1", + "@types/geojson": "^7946.0.10" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/projection": { + "version": "7.3.1", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@turf/projection/-/projection-7.3.1.tgz", + "integrity": "sha512-nDM3LG2j37B1tCpF4xL4rUBrQJcG585IRyDIxL2QEvP1LLv6dcm4fodw70HcGAj05Ux8bJr7IOXQXnobOJrlRA==", + "license": "MIT", + "dependencies": { + "@turf/clone": "7.3.1", + "@turf/helpers": "7.3.1", + "@turf/meta": "7.3.1", + "@types/geojson": "^7946.0.10", + "tslib": "^2.8.1" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@types/babel__core": { + "version": "7.20.5", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@types/babel__core/-/babel__core-7.20.5.tgz", + "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.27.0", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@types/babel__generator/-/babel__generator-7.27.0.tgz", + "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.4", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@types/babel__template/-/babel__template-7.4.4.tgz", + "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.28.0", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@types/babel__traverse/-/babel__traverse-7.28.0.tgz", + "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.2" + } + }, + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/geojson": { + "version": "7946.0.16", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@types/geojson/-/geojson-7946.0.16.tgz", + "integrity": "sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg==", + "license": "MIT" + }, + "node_modules/@types/geojson-vt": { + "version": "3.2.5", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm/@types/geojson-vt/-/geojson-vt-3.2.5.tgz", + "integrity": "sha512-qDO7wqtprzlpe8FfQ//ClPV9xiuoh2nkIgiouIptON9w5jvD/fA4szvP9GBlDVdJ5dldAl0kX/sy3URbWwLx0g==", + "license": "MIT", + "dependencies": { + "@types/geojson": "*" + } + }, + "node_modules/@types/hoist-non-react-statics": { + "version": "3.3.7", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.7.tgz", + "integrity": "sha512-PQTyIulDkIDro8P+IHbKCsw7U2xxBYflVzW/FgWdCAePD9xGSidgA76/GeJ6lBKoblyhf9pBY763gbrN+1dI8g==", + "license": "MIT", + "dependencies": { + "hoist-non-react-statics": "^3.3.0" + }, + "peerDependencies": { + "@types/react": "*" + } + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/leaflet": { + "version": "1.9.21", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@types/leaflet/-/leaflet-1.9.21.tgz", + "integrity": "sha512-TbAd9DaPGSnzp6QvtYngntMZgcRk+igFELwR2N99XZn7RXUdKgsXMR+28bUO0rPsWp8MIu/f47luLIQuSLYv/w==", + "license": "MIT", + "dependencies": { + "@types/geojson": "*" + } + }, + "node_modules/@types/leaflet-draw": { + "version": "1.0.13", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@types/leaflet-draw/-/leaflet-draw-1.0.13.tgz", + "integrity": "sha512-YU82kilOaU+wPNbqKCCDfHH3hqepN6XilrBwG/mSeZ/z4ewumaRCOah44s3FMxSu/Aa0SVa3PPJvhIZDUA09mw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/leaflet": "^1.9" + } + }, + "node_modules/@types/mapbox__mapbox-gl-draw": { + "version": "1.4.9", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@types/mapbox__mapbox-gl-draw/-/mapbox__mapbox-gl-draw-1.4.9.tgz", + "integrity": "sha512-8OtRdlSFbF/NDKg3CYQZPbI41JUwRPHIOB1f3fc3AG0Wb7CecSuuUG5EG+IsCmTHyzF6cyKpcjR/jcv62U3w6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/geojson": "*", + "mapbox-gl": "*" + } + }, + "node_modules/@types/mapbox__point-geometry": { + "version": "0.1.4", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@types/mapbox__point-geometry/-/mapbox__point-geometry-0.1.4.tgz", + "integrity": "sha512-mUWlSxAmYLfwnRBmgYV86tgYmMIICX4kza8YnE/eIlywGe2XoOxlpVnXWwir92xRLjwyarqwpu2EJKD2pk0IUA==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "24.10.1", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@types/node/-/node-24.10.1.tgz", + "integrity": "sha512-GNWcUTRBgIRJD5zj+Tq0fKOJ5XZajIiBroOF0yvj2bSU1WvNdYS/dn9UxwsujGW4JX06dnHyjV2y9rRaybH0iQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~7.16.0" + } + }, + "node_modules/@types/parse-json": { + "version": "4.0.2", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@types/parse-json/-/parse-json-4.0.2.tgz", + "integrity": "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==", + "license": "MIT" + }, + "node_modules/@types/pbf": { + "version": "3.0.5", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@types/pbf/-/pbf-3.0.5.tgz", + "integrity": "sha512-j3pOPiEcWZ34R6a6mN07mUkM4o4Lwf6hPNt8eilOeZhTFbxFXmKhvXl9Y28jotFPaI1bpPDJsbCprUoNke6OrA==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/@types/prop-types": { + "version": "15.7.15", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@types/prop-types/-/prop-types-15.7.15.tgz", + "integrity": "sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==", + "license": "MIT" + }, + "node_modules/@types/react": { + "version": "19.2.7", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@types/react/-/react-19.2.7.tgz", + "integrity": "sha512-MWtvHrGZLFttgeEj28VXHxpmwYbor/ATPYbBfSFZEIRK0ecCFLl2Qo55z52Hss+UV9CRN7trSeq1zbgx7YDWWg==", + "license": "MIT", + "dependencies": { + "csstype": "^3.2.2" + } + }, + "node_modules/@types/react-dom": { + "version": "19.2.3", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@types/react-dom/-/react-dom-19.2.3.tgz", + "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@types/react": "^19.2.0" + } + }, + "node_modules/@types/react-redux": { + "version": "7.1.34", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@types/react-redux/-/react-redux-7.1.34.tgz", + "integrity": "sha512-GdFaVjEbYv4Fthm2ZLvj1VSCedV7TqE5y1kNwnjSdBOTXuRSgowux6J8TAct15T3CKBr63UMk+2CO7ilRhyrAQ==", + "license": "MIT", + "dependencies": { + "@types/hoist-non-react-statics": "^3.3.0", + "@types/react": "*", + "hoist-non-react-statics": "^3.3.0", + "redux": "^4.0.0" + } + }, + "node_modules/@types/react-redux/node_modules/redux": { + "version": "4.2.1", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/redux/-/redux-4.2.1.tgz", + "integrity": "sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.9.2" + } + }, + "node_modules/@types/react-transition-group": { + "version": "4.4.12", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@types/react-transition-group/-/react-transition-group-4.4.12.tgz", + "integrity": "sha512-8TV6R3h2j7a91c+1DXdJi3Syo69zzIZbz7Lg5tORM5LEJG7X/E6a1V3drRyBRZq7/utz7A+c4OgYLiLcYGHG6w==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*" + } + }, + "node_modules/@types/supercluster": { + "version": "7.1.3", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm/@types/supercluster/-/supercluster-7.1.3.tgz", + "integrity": "sha512-Z0pOY34GDFl3Q6hUFYf3HkTwKEE02e7QgtJppBt+beEAxnyOpJua+voGFvxINBHa06GwLFFym7gRPY2SiKIfIA==", + "license": "MIT", + "dependencies": { + "@types/geojson": "*" + } + }, + "node_modules/@types/use-sync-external-store": { + "version": "0.0.6", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@types/use-sync-external-store/-/use-sync-external-store-0.0.6.tgz", + "integrity": "sha512-zFDAD+tlpf2r4asuHEj0XH6pY6i0g5NeAHPn+15wk3BV6JA69eERFXC1gyGThDkVa1zCyKr5jox1+2LbV/AMLg==", + "license": "MIT" + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.48.0", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.48.0.tgz", + "integrity": "sha512-XxXP5tL1txl13YFtrECECQYeZjBZad4fyd3cFV4a19LkAY/bIp9fev3US4S5fDVV2JaYFiKAZ/GRTOLer+mbyQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.10.0", + "@typescript-eslint/scope-manager": "8.48.0", + "@typescript-eslint/type-utils": "8.48.0", + "@typescript-eslint/utils": "8.48.0", + "@typescript-eslint/visitor-keys": "8.48.0", + "graphemer": "^1.4.0", + "ignore": "^7.0.0", + "natural-compare": "^1.4.0", + "ts-api-utils": "^2.1.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^8.48.0", + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": { + "version": "7.0.5", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/ignore/-/ignore-7.0.5.tgz", + "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "8.48.0", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@typescript-eslint/parser/-/parser-8.48.0.tgz", + "integrity": "sha512-jCzKdm/QK0Kg4V4IK/oMlRZlY+QOcdjv89U2NgKHZk1CYTj82/RVSx1mV/0gqCVMJ/DA+Zf/S4NBWNF8GQ+eqQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/scope-manager": "8.48.0", + "@typescript-eslint/types": "8.48.0", + "@typescript-eslint/typescript-estree": "8.48.0", + "@typescript-eslint/visitor-keys": "8.48.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/project-service": { + "version": "8.48.0", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@typescript-eslint/project-service/-/project-service-8.48.0.tgz", + "integrity": "sha512-Ne4CTZyRh1BecBf84siv42wv5vQvVmgtk8AuiEffKTUo3DrBaGYZueJSxxBZ8fjk/N3DrgChH4TOdIOwOwiqqw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/tsconfig-utils": "^8.48.0", + "@typescript-eslint/types": "^8.48.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "8.48.0", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@typescript-eslint/scope-manager/-/scope-manager-8.48.0.tgz", + "integrity": "sha512-uGSSsbrtJrLduti0Q1Q9+BF1/iFKaxGoQwjWOIVNJv0o6omrdyR8ct37m4xIl5Zzpkp69Kkmvom7QFTtue89YQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.48.0", + "@typescript-eslint/visitor-keys": "8.48.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/tsconfig-utils": { + "version": "8.48.0", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.48.0.tgz", + "integrity": "sha512-WNebjBdFdyu10sR1M4OXTt2OkMd5KWIL+LLfeH9KhgP+jzfDV/LI3eXzwJ1s9+Yc0Kzo2fQCdY/OpdusCMmh6w==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "8.48.0", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@typescript-eslint/type-utils/-/type-utils-8.48.0.tgz", + "integrity": "sha512-zbeVaVqeXhhab6QNEKfK96Xyc7UQuoFWERhEnj3mLVnUWrQnv15cJNseUni7f3g557gm0e46LZ6IJ4NJVOgOpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.48.0", + "@typescript-eslint/typescript-estree": "8.48.0", + "@typescript-eslint/utils": "8.48.0", + "debug": "^4.3.4", + "ts-api-utils": "^2.1.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/types": { + "version": "8.48.0", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@typescript-eslint/types/-/types-8.48.0.tgz", + "integrity": "sha512-cQMcGQQH7kwKoVswD1xdOytxQR60MWKM1di26xSUtxehaDs/32Zpqsu5WJlXTtTTqyAVK8R7hvsUnIXRS+bjvA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "8.48.0", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@typescript-eslint/typescript-estree/-/typescript-estree-8.48.0.tgz", + "integrity": "sha512-ljHab1CSO4rGrQIAyizUS6UGHHCiAYhbfcIZ1zVJr5nMryxlXMVWS3duFPSKvSUbFPwkXMFk1k0EMIjub4sRRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/project-service": "8.48.0", + "@typescript-eslint/tsconfig-utils": "8.48.0", + "@typescript-eslint/types": "8.48.0", + "@typescript-eslint/visitor-keys": "8.48.0", + "debug": "^4.3.4", + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "tinyglobby": "^0.2.15", + "ts-api-utils": "^2.1.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { + "version": "2.0.2", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { + "version": "7.7.3", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "8.48.0", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@typescript-eslint/utils/-/utils-8.48.0.tgz", + "integrity": "sha512-yTJO1XuGxCsSfIVt1+1UrLHtue8xz16V8apzPYI06W0HbEbEWHxHXgZaAgavIkoh+GeV6hKKd5jm0sS6OYxWXQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.7.0", + "@typescript-eslint/scope-manager": "8.48.0", + "@typescript-eslint/types": "8.48.0", + "@typescript-eslint/typescript-estree": "8.48.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "8.48.0", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@typescript-eslint/visitor-keys/-/visitor-keys-8.48.0.tgz", + "integrity": "sha512-T0XJMaRPOH3+LBbAfzR2jalckP1MSG/L9eUtY0DEzUyVaXJ/t6zN0nR7co5kz0Jko/nkSYCBRkz1djvjajVTTg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.48.0", + "eslint-visitor-keys": "^4.2.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@vis.gl/react-mapbox": { + "version": "8.1.0", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@vis.gl/react-mapbox/-/react-mapbox-8.1.0.tgz", + "integrity": "sha512-FwvH822oxEjWYOr+pP2L8hpv+7cZB2UsQbHHHT0ryrkvvqzmTgt7qHDhamv0EobKw86e1I+B4ojENdJ5G5BkyQ==", + "license": "MIT", + "peerDependencies": { + "mapbox-gl": ">=3.5.0", + "react": ">=16.3.0", + "react-dom": ">=16.3.0" + }, + "peerDependenciesMeta": { + "mapbox-gl": { + "optional": true + } + } + }, + "node_modules/@vis.gl/react-maplibre": { + "version": "8.1.0", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@vis.gl/react-maplibre/-/react-maplibre-8.1.0.tgz", + "integrity": "sha512-PkAK/gp3mUfhCLhUuc+4gc3PN9zCtVGxTF2hB6R5R5yYUw+hdg84OZ770U5MU4tPMTCG6fbduExuIW6RRKN6qQ==", + "license": "MIT", + "dependencies": { + "@maplibre/maplibre-gl-style-spec": "^19.2.1" + }, + "peerDependencies": { + "maplibre-gl": ">=4.0.0", + "react": ">=16.3.0", + "react-dom": ">=16.3.0" + }, + "peerDependenciesMeta": { + "maplibre-gl": { + "optional": true + } + } + }, + "node_modules/@vis.gl/react-maplibre/node_modules/@maplibre/maplibre-gl-style-spec": { + "version": "19.3.3", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@maplibre/maplibre-gl-style-spec/-/maplibre-gl-style-spec-19.3.3.tgz", + "integrity": "sha512-cOZZOVhDSulgK0meTsTkmNXb1ahVvmTmWmfx9gRBwc6hq98wS9JP35ESIoNq3xqEan+UN+gn8187Z6E4NKhLsw==", + "license": "ISC", + "dependencies": { + "@mapbox/jsonlint-lines-primitives": "~2.0.2", + "@mapbox/unitbezier": "^0.0.1", + "json-stringify-pretty-compact": "^3.0.0", + "minimist": "^1.2.8", + "rw": "^1.3.3", + "sort-object": "^3.0.3" + }, + "bin": { + "gl-style-format": "dist/gl-style-format.mjs", + "gl-style-migrate": "dist/gl-style-migrate.mjs", + "gl-style-validate": "dist/gl-style-validate.mjs" + } + }, + "node_modules/@vis.gl/react-maplibre/node_modules/json-stringify-pretty-compact": { + "version": "3.0.0", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/json-stringify-pretty-compact/-/json-stringify-pretty-compact-3.0.0.tgz", + "integrity": "sha512-Rc2suX5meI0S3bfdZuA7JMFBGkJ875ApfVyq2WHELjBiiG22My/l7/8zPpH/CfFVQHuVLd8NLR0nv6vi0BYYKA==", + "license": "MIT" + }, + "node_modules/@vitejs/plugin-react": { + "version": "5.1.1", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/@vitejs/plugin-react/-/plugin-react-5.1.1.tgz", + "integrity": "sha512-WQfkSw0QbQ5aJ2CHYw23ZGkqnRwqKHD/KYsMeTkZzPT4Jcf0DcBxBtwMJxnu6E7oxw5+JC6ZAiePgh28uJ1HBA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.28.5", + "@babel/plugin-transform-react-jsx-self": "^7.27.1", + "@babel/plugin-transform-react-jsx-source": "^7.27.1", + "@rolldown/pluginutils": "1.0.0-beta.47", + "@types/babel__core": "^7.20.5", + "react-refresh": "^0.18.0" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "peerDependencies": { + "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" + } + }, + "node_modules/acorn": { + "version": "8.15.0", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/acorn/-/acorn-8.15.0.tgz", + "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/arr-union": { + "version": "3.1.0", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/arr-union/-/arr-union-3.1.0.tgz", + "integrity": "sha512-sKpyeERZ02v1FeCZT8lrfJq5u6goHCtpTAzPwJYe7c8SPFOboNjNg1vz2L4VTn9T4PQxEx13TbXLmYUcS6Ug7Q==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/assign-symbols": { + "version": "1.0.0", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/assign-symbols/-/assign-symbols-1.0.0.tgz", + "integrity": "sha512-Q+JC7Whu8HhmTdBph/Tq59IoRtoy6KAm5zzPv00WdujX82lbAL8K7WVjne7vdCsAmbF4AYaDOPyO3k0kl8qIrw==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "license": "MIT" + }, + "node_modules/axios": { + "version": "1.13.2", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/axios/-/axios-1.13.2.tgz", + "integrity": "sha512-VPk9ebNqPcy5lRGuSlKx752IlDatOjT9paPlm8A7yOuW2Fbvp4X3JznJtT4f0GzGLLiWE9W8onz51SqLYwzGaA==", + "license": "MIT", + "dependencies": { + "follow-redirects": "^1.15.6", + "form-data": "^4.0.4", + "proxy-from-env": "^1.1.0" + } + }, + "node_modules/babel-plugin-macros": { + "version": "3.1.0", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz", + "integrity": "sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.12.5", + "cosmiconfig": "^7.0.0", + "resolve": "^1.19.0" + }, + "engines": { + "node": ">=10", + "npm": ">=6" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/baseline-browser-mapping": { + "version": "2.8.31", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/baseline-browser-mapping/-/baseline-browser-mapping-2.8.31.tgz", + "integrity": "sha512-a28v2eWrrRWPpJSzxc+mKwm0ZtVx/G8SepdQZDArnXYU/XS+IF6mp8aB/4E+hH1tyGCoDo3KlUCdlSxGDsRkAw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.js" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/browserslist": { + "version": "4.28.0", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/browserslist/-/browserslist-4.28.0.tgz", + "integrity": "sha512-tbydkR/CxfMwelN0vwdP/pLkDwyAASZ+VfWm4EOwlB6SWhx1sYnWLqo8N5j0rAzPfzfRaxt0mM/4wPU/Su84RQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "baseline-browser-mapping": "^2.8.25", + "caniuse-lite": "^1.0.30001754", + "electron-to-chromium": "^1.5.249", + "node-releases": "^2.0.27", + "update-browserslist-db": "^1.1.4" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/bytewise": { + "version": "1.1.0", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/bytewise/-/bytewise-1.1.0.tgz", + "integrity": "sha512-rHuuseJ9iQ0na6UDhnrRVDh8YnWVlU6xM3VH6q/+yHDeUH2zIhUzP+2/h3LIrhLDBtTqzWpE3p3tP/boefskKQ==", + "license": "MIT", + "dependencies": { + "bytewise-core": "^1.2.2", + "typewise": "^1.0.3" + } + }, + "node_modules/bytewise-core": { + "version": "1.2.3", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/bytewise-core/-/bytewise-core-1.2.3.tgz", + "integrity": "sha512-nZD//kc78OOxeYtRlVk8/zXqTB4gf/nlguL1ggWA8FuchMyOxcyHR4QPQZMUmA7czC+YnaBrPUCubqAWe50DaA==", + "license": "MIT", + "dependencies": { + "typewise-core": "^1.2" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001757", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/caniuse-lite/-/caniuse-lite-1.0.30001757.tgz", + "integrity": "sha512-r0nnL/I28Zi/yjk1el6ilj27tKcdjLsNqAOZr0yVjWPrSQyHgKI2INaEWw21bAQSv2LXRt1XuCS/GomNpWOxsQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/cheap-ruler": { + "version": "4.0.0", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/cheap-ruler/-/cheap-ruler-4.0.0.tgz", + "integrity": "sha512-0BJa8f4t141BYKQyn9NSQt1PguFQXMXwZiA5shfoaBYHAb2fFk2RAX+tiWMoQU+Agtzt3mdt0JtuyshAXqZ+Vw==", + "devOptional": true, + "license": "ISC" + }, + "node_modules/chokidar": { + "version": "4.0.3", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "readdirp": "^4.0.1" + }, + "engines": { + "node": ">= 14.16.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/colorette": { + "version": "2.0.20", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", + "dev": true, + "license": "MIT" + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, + "license": "MIT" + }, + "node_modules/convert-source-map": { + "version": "1.9.0", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", + "license": "MIT" + }, + "node_modules/cookie": { + "version": "1.1.0", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/cookie/-/cookie-1.1.0.tgz", + "integrity": "sha512-vXiThu1/rlos7EGu8TuNZQEg2e9TvhH9dmS4T4ZVzB7Ao1agEZ6EG3sn5n+hZRYUgduISd1HpngFzAZiDGm5vQ==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/cosmiconfig": { + "version": "7.1.0", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/cosmiconfig/-/cosmiconfig-7.1.0.tgz", + "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", + "license": "MIT", + "dependencies": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.2.1", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.10.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/cosmiconfig/node_modules/yaml": { + "version": "1.10.2", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "license": "ISC", + "engines": { + "node": ">= 6" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/csscolorparser": { + "version": "1.0.3", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/csscolorparser/-/csscolorparser-1.0.3.tgz", + "integrity": "sha512-umPSgYwZkdFoUrH5hIq5kf0wPSXiro51nPw0j2K/c83KflkPSTBGMz6NJvMB+07VlL0y7VPo6QJcDjcgKTTm3w==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/csstype": { + "version": "3.2.3", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/csstype/-/csstype-3.2.3.tgz", + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", + "license": "MIT" + }, + "node_modules/date-fns": { + "version": "4.1.0", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/date-fns/-/date-fns-4.1.0.tgz", + "integrity": "sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/kossnocorp" + } + }, + "node_modules/dayjs": { + "version": "1.11.19", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/dayjs/-/dayjs-1.11.19.tgz", + "integrity": "sha512-t5EcLVS6QPBNqM2z8fakk/NKel+Xzshgt8FFKAn+qwlD1pzZWxh0nVCrvFK7ZDb6XucZeF9z8C7CBWTRIVApAw==", + "license": "MIT" + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/dom-helpers": { + "version": "5.2.1", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/dom-helpers/-/dom-helpers-5.2.1.tgz", + "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.8.7", + "csstype": "^3.0.2" + } + }, + "node_modules/dot-prop": { + "version": "9.0.0", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/dot-prop/-/dot-prop-9.0.0.tgz", + "integrity": "sha512-1gxPBJpI/pcjQhKgIU91II6Wkay+dLcN3M6rf2uwP8hRur3HtQXjVrdAK3sjC0piaEuxzMwjXChcETiJl47lAQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "type-fest": "^4.18.2" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/dotenv": { + "version": "17.2.3", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/dotenv/-/dotenv-17.2.3.tgz", + "integrity": "sha512-JVUnt+DUIzu87TABbhPmNfVdBDt18BLOWjMUFJMSi/Qqg7NTYtabbvSNJGOJ7afbRuv9D/lngizHtP7QyLQ+9w==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/earcut": { + "version": "3.0.2", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm/earcut/-/earcut-3.0.2.tgz", + "integrity": "sha512-X7hshQbLyMJ/3RPhyObLARM2sNxxmRALLKx1+NVFFnQ9gKzmCrxm9+uLIAdBcvc8FNLpctqlQ2V6AE92Ol9UDQ==", + "license": "ISC" + }, + "node_modules/electron-to-chromium": { + "version": "1.5.260", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/electron-to-chromium/-/electron-to-chromium-1.5.260.tgz", + "integrity": "sha512-ov8rBoOBhVawpzdre+Cmz4FB+y66Eqrk6Gwqd8NGxuhv99GQ8XqMAr351KEkOt7gukXWDg6gJWEMKgL2RLMPtA==", + "dev": true, + "license": "ISC" + }, + "node_modules/error-ex": { + "version": "1.3.4", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/error-ex/-/error-ex-1.3.4.tgz", + "integrity": "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==", + "license": "MIT", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-escape-html": { + "version": "0.1.1", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/es-escape-html/-/es-escape-html-0.1.1.tgz", + "integrity": "sha512-yUx1o+8RsG7UlszmYPtks+dm6Lho2m8lgHMOsLJQsFI0R8XwUJwiMhM1M4E/S8QLeGyf6MkDV/pWgjQ0tdTSyQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.x" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/esbuild": { + "version": "0.25.12", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/esbuild/-/esbuild-0.25.12.tgz", + "integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.25.12", + "@esbuild/android-arm": "0.25.12", + "@esbuild/android-arm64": "0.25.12", + "@esbuild/android-x64": "0.25.12", + "@esbuild/darwin-arm64": "0.25.12", + "@esbuild/darwin-x64": "0.25.12", + "@esbuild/freebsd-arm64": "0.25.12", + "@esbuild/freebsd-x64": "0.25.12", + "@esbuild/linux-arm": "0.25.12", + "@esbuild/linux-arm64": "0.25.12", + "@esbuild/linux-ia32": "0.25.12", + "@esbuild/linux-loong64": "0.25.12", + "@esbuild/linux-mips64el": "0.25.12", + "@esbuild/linux-ppc64": "0.25.12", + "@esbuild/linux-riscv64": "0.25.12", + "@esbuild/linux-s390x": "0.25.12", + "@esbuild/linux-x64": "0.25.12", + "@esbuild/netbsd-arm64": "0.25.12", + "@esbuild/netbsd-x64": "0.25.12", + "@esbuild/openbsd-arm64": "0.25.12", + "@esbuild/openbsd-x64": "0.25.12", + "@esbuild/openharmony-arm64": "0.25.12", + "@esbuild/sunos-x64": "0.25.12", + "@esbuild/win32-arm64": "0.25.12", + "@esbuild/win32-ia32": "0.25.12", + "@esbuild/win32-x64": "0.25.12" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "9.39.1", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/eslint/-/eslint-9.39.1.tgz", + "integrity": "sha512-BhHmn2yNOFA9H9JmmIVKJmd288g9hrVRDkdoIgRCRuSySRUHH7r/DI6aAXW9T1WwUuY3DFgrcaqB+deURBLR5g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.8.0", + "@eslint-community/regexpp": "^4.12.1", + "@eslint/config-array": "^0.21.1", + "@eslint/config-helpers": "^0.4.2", + "@eslint/core": "^0.17.0", + "@eslint/eslintrc": "^3.3.1", + "@eslint/js": "9.39.1", + "@eslint/plugin-kit": "^0.4.1", + "@humanfs/node": "^0.16.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.4.2", + "@types/estree": "^1.0.6", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.6", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^8.4.0", + "eslint-visitor-keys": "^4.2.1", + "espree": "^10.4.0", + "esquery": "^1.5.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } + } + }, + "node_modules/eslint-plugin-react-hooks": { + "version": "5.2.0", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-5.2.0.tgz", + "integrity": "sha512-+f15FfK64YQwZdJNELETdn5ibXEUQmW1DZL6KXhNnc2heoy/sg9VJJeT7n8TlMWouzWqSWavFkIhHyIbIAEapg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0" + } + }, + "node_modules/eslint-plugin-react-refresh": { + "version": "0.4.24", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.4.24.tgz", + "integrity": "sha512-nLHIW7TEq3aLrEYWpVaJ1dRgFR+wLDPN8e8FpYAql/bMV2oBEfC37K0gLEGgv9fy66juNShSMV8OkTqzltcG/w==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "eslint": ">=8.40" + } + }, + "node_modules/eslint-scope": { + "version": "8.4.0", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/eslint-scope/-/eslint-scope-8.4.0.tgz", + "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "4.2.1", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/espree": { + "version": "10.4.0", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/espree/-/espree-10.4.0.tgz", + "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.15.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.2.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.6.0", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/esquery/-/esquery-1.6.0.tgz", + "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eta": { + "version": "3.5.0", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/eta/-/eta-3.5.0.tgz", + "integrity": "sha512-e3x3FBvGzeCIHhF+zhK8FZA2vC5uFn6b4HJjegUbIWrDb4mJ7JjTGMJY9VGIbRVpmSwHopNiaJibhjIr+HfLug==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + }, + "funding": { + "url": "https://github.com/eta-dev/eta?sponsor=1" + } + }, + "node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", + "license": "MIT", + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "license": "MIT" + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true, + "license": "MIT" + }, + "node_modules/file-entry-cache": { + "version": "8.0.0", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/find-root": { + "version": "1.1.0", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/find-root/-/find-root-1.1.0.tgz", + "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==", + "license": "MIT" + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "4.0.1", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.4" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/flatted": { + "version": "3.3.3", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/flatted/-/flatted-3.3.3.tgz", + "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", + "dev": true, + "license": "ISC" + }, + "node_modules/follow-redirects": { + "version": "1.15.11", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/follow-redirects/-/follow-redirects-1.15.11.tgz", + "integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "license": "MIT", + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/form-data": { + "version": "4.0.5", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/form-data/-/form-data-4.0.5.tgz", + "integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==", + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.2", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/geojson-vt": { + "version": "4.0.2", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm/geojson-vt/-/geojson-vt-4.0.2.tgz", + "integrity": "sha512-AV9ROqlNqoZEIJGfm1ncNjEXfkz2hdFlZf0qkVfmkwdKa8vj7H16YUOT81rJw1rdFhyEDlN2Tds91p/glzbl5A==", + "license": "ISC" + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-value": { + "version": "2.0.6", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm/get-value/-/get-value-2.0.6.tgz", + "integrity": "sha512-Ln0UQDlxH1BapMu3GPtf7CuYNwRZf2gwCuPqbyG6pB8WfmFpzqcy4xtAaAMUhnNqjMKTiCPZG2oMT3YSx8U2NA==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gl-matrix": { + "version": "3.4.4", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm/gl-matrix/-/gl-matrix-3.4.4.tgz", + "integrity": "sha512-latSnyDNt/8zYUB6VIJ6PCh2jBjJX6gnDsoCZ7LyW7GkqrD51EWwa9qCoGixj8YqBtETQK/xY7OmpTF8xz1DdQ==", + "license": "MIT" + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/globals": { + "version": "16.5.0", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/globals/-/globals-16.5.0.tgz", + "integrity": "sha512-c/c15i26VrJ4IRt5Z89DnIzCGDn9EcebibhAOjw5ibqEHsE1wLUgkPn9RDmNcUKyU87GeaL633nyJ+pplFR2ZQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true, + "license": "MIT" + }, + "node_modules/grid-index": { + "version": "1.1.0", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/grid-index/-/grid-index-1.1.0.tgz", + "integrity": "sha512-HZRwumpOGUrHyxO5bqKZL0B0GlUpwtCAzZ42sgxUPniu33R1LSFH5yrIcBCHjkctCAh3mtWKcKd9J4vDDdeVHA==", + "devOptional": true, + "license": "ISC" + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/header-range-parser": { + "version": "1.1.3", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/header-range-parser/-/header-range-parser-1.1.3.tgz", + "integrity": "sha512-B9zCFt3jH8g09LR1vHL4pcAn8yMEtlSlOUdQemzHMRKMImNIhhszdeosYFfNW0WXKQtXIlWB+O4owHJKvEJYaA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.22.0" + } + }, + "node_modules/hoist-non-react-statics": { + "version": "3.3.2", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", + "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", + "license": "BSD-3-Clause", + "dependencies": { + "react-is": "^16.7.0" + } + }, + "node_modules/hoist-non-react-statics/node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "license": "MIT" + }, + "node_modules/http-status-emojis": { + "version": "2.2.0", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/http-status-emojis/-/http-status-emojis-2.2.0.tgz", + "integrity": "sha512-ompKtgwpx8ff0hsbpIB7oE4ax1LXoHmftsHHStMELX56ivG3GhofTX8ZHWlUaFKfGjcGjw6G3rPk7dJRXMmbbg==", + "dev": true, + "license": "MIT" + }, + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/immer": { + "version": "11.0.0", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/immer/-/immer-11.0.0.tgz", + "integrity": "sha512-XtRG4SINt4dpqlnJvs70O2j6hH7H0X8fUzFsjMn1rwnETaxwp83HLNimXBjZ78MrKl3/d3/pkzDH0o0Lkxm37Q==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/immer" + } + }, + "node_modules/import-fresh": { + "version": "3.3.1", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inflection": { + "version": "3.0.2", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/inflection/-/inflection-3.0.2.tgz", + "integrity": "sha512-+Bg3+kg+J6JUWn8J6bzFmOWkTQ6L/NHfDRSYU+EVvuKHDxUDHAXgqixHfVlzuBQaPOTac8hn43aPhMNk6rMe3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/ipaddr.js": { + "version": "2.2.0", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/ipaddr.js/-/ipaddr.js-2.2.0.tgz", + "integrity": "sha512-Ag3wB2o37wslZS19hZqorUnrnzSkpOVy+IiiDEiTqNubEYpYuHWIf6K4psgN2ZWKExS4xhVCrRVfb/wfW8fWJA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "license": "MIT" + }, + "node_modules/is-core-module": { + "version": "2.16.1", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/is-core-module/-/is-core-module-2.16.1.tgz", + "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", + "license": "MIT", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extendable": { + "version": "0.1.1", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "license": "MIT", + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/isobject": { + "version": "3.0.1", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "4.1.1", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/js-yaml/-/js-yaml-4.1.1.tgz", + "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "license": "MIT" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-server": { + "version": "1.0.0-beta.3", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/json-server/-/json-server-1.0.0-beta.3.tgz", + "integrity": "sha512-DwE69Ep5ccwIJZBUIWEENC30Yj8bwr4Ax9W9VoIWAYnB8Sj4ReptscO8/DRHv/nXwVlmb3Bk73Ls86+VZdYkkA==", + "dev": true, + "license": "SEE LICENSE IN ./LICENSE", + "dependencies": { + "@tinyhttp/app": "^2.4.0", + "@tinyhttp/cors": "^2.0.1", + "@tinyhttp/logger": "^2.0.0", + "chalk": "^5.3.0", + "chokidar": "^4.0.1", + "dot-prop": "^9.0.0", + "eta": "^3.5.0", + "inflection": "^3.0.0", + "json5": "^2.2.3", + "lowdb": "^7.0.1", + "milliparsec": "^4.0.0", + "sirv": "^2.0.4", + "sort-on": "^6.1.0" + }, + "bin": { + "json-server": "lib/bin.js" + }, + "engines": { + "node": ">=18.3" + } + }, + "node_modules/json-server/node_modules/chalk": { + "version": "5.6.2", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/chalk/-/chalk-5.6.2.tgz", + "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stringify-pretty-compact": { + "version": "4.0.0", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm/json-stringify-pretty-compact/-/json-stringify-pretty-compact-4.0.0.tgz", + "integrity": "sha512-3CNZ2DnrpByG9Nqj6Xo8vqbjT4F6N+tb4Gb28ESAZjYZ5yqvmc56J+/kuIwkaAMOyblTQhUW7PxMkUb8Q36N3Q==", + "license": "MIT" + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/kdbush": { + "version": "4.0.2", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm/kdbush/-/kdbush-4.0.2.tgz", + "integrity": "sha512-WbCVYJ27Sz8zi9Q7Q0xHC+05iwkm3Znipc2XTlrnJbsHMYktW4hPhXUE8Ys1engBrvffoSCqbil1JQAa7clRpA==", + "license": "ISC" + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/leaflet": { + "version": "1.9.4", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/leaflet/-/leaflet-1.9.4.tgz", + "integrity": "sha512-nxS1ynzJOmOlHp+iL3FyWqK89GtNL8U8rvlMOsQdTTssxZwCXh8N2NB3GDQOL+YR3XnWyZAxwQixURb+FA74PA==", + "license": "BSD-2-Clause" + }, + "node_modules/leaflet-draw": { + "version": "1.0.4", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/leaflet-draw/-/leaflet-draw-1.0.4.tgz", + "integrity": "sha512-rsQ6saQO5ST5Aj6XRFylr5zvarWgzWnrg46zQ1MEOEIHsppdC/8hnN8qMoFvACsPvTioAuysya/TVtog15tyAQ==", + "license": "MIT" + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "license": "MIT" + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "license": "MIT", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/lowdb": { + "version": "7.0.1", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/lowdb/-/lowdb-7.0.1.tgz", + "integrity": "sha512-neJAj8GwF0e8EpycYIDFqEPcx9Qz4GUho20jWFR7YiFeXzF1YMLdxB36PypcTSPMA+4+LvgyMacYhlr18Zlymw==", + "dev": true, + "license": "MIT", + "dependencies": { + "steno": "^4.0.2" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/typicode" + } + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/mapbox-gl": { + "version": "3.17.0", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm/mapbox-gl/-/mapbox-gl-3.17.0.tgz", + "integrity": "sha512-nCrDKRlr5di6xUksUDslNWwxroJ5yv1hT8pyVFtcpWJOOKsYQxF/wOFTMie8oxMnXeFkrz1Tl1TwA1XN1yX0KA==", + "devOptional": true, + "license": "SEE LICENSE IN LICENSE.txt", + "workspaces": [ + "src/style-spec", + "test/build/vite", + "test/build/webpack", + "test/build/typings" + ], + "dependencies": { + "@mapbox/jsonlint-lines-primitives": "^2.0.2", + "@mapbox/mapbox-gl-supported": "^3.0.0", + "@mapbox/point-geometry": "^1.1.0", + "@mapbox/tiny-sdf": "^2.0.6", + "@mapbox/unitbezier": "^0.0.1", + "@mapbox/vector-tile": "^2.0.4", + "@mapbox/whoots-js": "^3.1.0", + "@types/geojson": "^7946.0.16", + "@types/geojson-vt": "^3.2.5", + "@types/mapbox__point-geometry": "^0.1.4", + "@types/pbf": "^3.0.5", + "@types/supercluster": "^7.1.3", + "cheap-ruler": "^4.0.0", + "csscolorparser": "~1.0.3", + "earcut": "^3.0.1", + "geojson-vt": "^4.0.2", + "gl-matrix": "^3.4.4", + "grid-index": "^1.1.0", + "kdbush": "^4.0.2", + "martinez-polygon-clipping": "^0.7.4", + "murmurhash-js": "^1.0.0", + "pbf": "^4.0.1", + "potpack": "^2.0.0", + "quickselect": "^3.0.0", + "supercluster": "^8.0.1", + "tinyqueue": "^3.0.0" + } + }, + "node_modules/maplibre-gl": { + "version": "5.14.0", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/maplibre-gl/-/maplibre-gl-5.14.0.tgz", + "integrity": "sha512-O2ok6N/bQ9NA9nJ22r/PRQQYkUe9JwfDMjBPkQ+8OwsVH4TpA5skIAM2wc0k+rni5lVbAVONVyBvgi1rF2vEPA==", + "license": "BSD-3-Clause", + "dependencies": { + "@mapbox/geojson-rewind": "^0.5.2", + "@mapbox/jsonlint-lines-primitives": "^2.0.2", + "@mapbox/point-geometry": "^1.1.0", + "@mapbox/tiny-sdf": "^2.0.7", + "@mapbox/unitbezier": "^0.0.1", + "@mapbox/vector-tile": "^2.0.4", + "@mapbox/whoots-js": "^3.1.0", + "@maplibre/maplibre-gl-style-spec": "^24.3.1", + "@maplibre/mlt": "^1.1.2", + "@maplibre/vt-pbf": "^4.1.0", + "@types/geojson": "^7946.0.16", + "@types/geojson-vt": "3.2.5", + "@types/supercluster": "^7.1.3", + "earcut": "^3.0.2", + "geojson-vt": "^4.0.2", + "gl-matrix": "^3.4.4", + "kdbush": "^4.0.2", + "murmurhash-js": "^1.0.0", + "pbf": "^4.0.1", + "potpack": "^2.1.0", + "quickselect": "^3.0.0", + "supercluster": "^8.0.1", + "tinyqueue": "^3.0.0" + }, + "engines": { + "node": ">=16.14.0", + "npm": ">=8.1.0" + }, + "funding": { + "url": "https://github.com/maplibre/maplibre-gl-js?sponsor=1" + } + }, + "node_modules/martinez-polygon-clipping": { + "version": "0.7.4", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm/martinez-polygon-clipping/-/martinez-polygon-clipping-0.7.4.tgz", + "integrity": "sha512-jBEwrKtA0jTagUZj2bnmb4Yg2s4KnJGRePStgI7bAVjtcipKiF39R4LZ2V/UT61jMYWrTcBhPazexeqd6JAVtw==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "robust-predicates": "^2.0.4", + "splaytree": "^0.1.4", + "tinyqueue": "^1.2.0" + } + }, + "node_modules/martinez-polygon-clipping/node_modules/tinyqueue": { + "version": "1.2.3", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm/tinyqueue/-/tinyqueue-1.2.3.tgz", + "integrity": "sha512-Qz9RgWuO9l8lT+Y9xvbzhPT2efIUIFd69N7eF7tJ9lnQl0iLj1M7peK7IoUGZL9DJHw9XftqLreccfxcQgYLxA==", + "devOptional": true, + "license": "ISC" + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/memoize-one": { + "version": "6.0.0", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/memoize-one/-/memoize-one-6.0.0.tgz", + "integrity": "sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==", + "license": "MIT" + }, + "node_modules/milliparsec": { + "version": "4.0.0", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/milliparsec/-/milliparsec-4.0.0.tgz", + "integrity": "sha512-/wk9d4Z6/9ZvoEH/6BI4TrTCgmkpZPuSRN/6fI9aUHOfXdNTuj/VhLS7d+NqG26bi6L9YmGXutVYvWC8zQ0qtA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20" + } + }, + "node_modules/mime": { + "version": "4.0.4", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/mime/-/mime-4.0.4.tgz", + "integrity": "sha512-v8yqInVjhXyqP6+Kw4fV3ZzeMRqEW6FotRsKXjRS5VMTNIuXsdRoAvklpoRgSqXm6o9VNH4/C0mgedko9DdLsQ==", + "dev": true, + "funding": [ + "https://github.com/sponsors/broofa" + ], + "license": "MIT", + "bin": { + "mime": "bin/cli.js" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/mrmime": { + "version": "2.0.1", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/mrmime/-/mrmime-2.0.1.tgz", + "integrity": "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/murmurhash-js": { + "version": "1.0.0", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm/murmurhash-js/-/murmurhash-js-1.0.0.tgz", + "integrity": "sha512-TvmkNhkv8yct0SVBSy+o8wYzXjE4Zz3PCesbfs8HiCXXdcTuocApFv11UWlNFWKYsP2okqrhb7JNlSm9InBhIw==", + "license": "MIT" + }, + "node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true, + "license": "MIT" + }, + "node_modules/negotiator": { + "version": "0.6.4", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/negotiator/-/negotiator-0.6.4.tgz", + "integrity": "sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/node-releases": { + "version": "2.0.27", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/node-releases/-/node-releases-2.0.27.tgz", + "integrity": "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "license": "MIT" + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/pbf": { + "version": "4.0.1", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm/pbf/-/pbf-4.0.1.tgz", + "integrity": "sha512-SuLdBvS42z33m8ejRbInMapQe8n0D3vN/Xd5fmWM3tufNgRQFBpaW2YVJxQZV4iPNqb0vEFvssMEo5w9c6BTIA==", + "license": "BSD-3-Clause", + "dependencies": { + "resolve-protobuf-schema": "^2.1.0" + }, + "bin": { + "pbf": "bin/pbf" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "license": "ISC" + }, + "node_modules/postcss": { + "version": "8.5.6", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/postcss/-/postcss-8.5.6.tgz", + "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/potpack": { + "version": "2.1.0", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm/potpack/-/potpack-2.1.0.tgz", + "integrity": "sha512-pcaShQc1Shq0y+E7GqJqvZj8DTthWV1KeHGdi0Z6IAin2Oi3JnLCOfwnCo84qc+HAp52wT9nK9H7FAJp5a44GQ==", + "license": "ISC" + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prop-types": { + "version": "15.8.1", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, + "node_modules/prop-types/node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "license": "MIT" + }, + "node_modules/protocol-buffers-schema": { + "version": "3.6.0", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm/protocol-buffers-schema/-/protocol-buffers-schema-3.6.0.tgz", + "integrity": "sha512-TdDRD+/QNdrCGCE7v8340QyuXd4kIWIgapsE2+n/SaGiSSbomYl4TjHlvIoCWRpE7wFt02EpB35VVA2ImcBVqw==", + "license": "MIT" + }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "license": "MIT" + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/quickselect": { + "version": "3.0.0", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm/quickselect/-/quickselect-3.0.0.tgz", + "integrity": "sha512-XdjUArbK4Bm5fLLvlm5KpTFOiOThgfWWI4axAZDWg4E/0mKdZyI9tNEfds27qCi1ze/vwTR16kvmmGhRra3c2g==", + "license": "ISC" + }, + "node_modules/react": { + "version": "19.2.1", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/react/-/react-19.2.1.tgz", + "integrity": "sha512-DGrYcCWK7tvYMnWh79yrPHt+vdx9tY+1gPZa7nJQtO/p8bLTDaHp4dzwEhQB7pZ4Xe3ok4XKuEPrVuc+wlpkmw==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-datepicker": { + "version": "8.10.0", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/react-datepicker/-/react-datepicker-8.10.0.tgz", + "integrity": "sha512-JIXuA+g+qP3c4MVJpx24o7n1gnv3WV/8A/D6964HucY1FlSEc30+ITPNUfbKZXYHl5rruCtxYCwi2lzn7gaz7g==", + "license": "MIT", + "dependencies": { + "@floating-ui/react": "^0.27.15", + "clsx": "^2.1.1", + "date-fns": "^4.1.0" + }, + "peerDependencies": { + "react": "^16.9.0 || ^17 || ^18 || ^19 || ^19.0.0-rc", + "react-dom": "^16.9.0 || ^17 || ^18 || ^19 || ^19.0.0-rc" + } + }, + "node_modules/react-dom": { + "version": "19.2.1", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/react-dom/-/react-dom-19.2.1.tgz", + "integrity": "sha512-ibrK8llX2a4eOskq1mXKu/TGZj9qzomO+sNfO98M6d9zIPOEhlBkMkBUBLd1vgS0gQsLDBzA+8jJBVXDnfHmJg==", + "license": "MIT", + "dependencies": { + "scheduler": "^0.27.0" + }, + "peerDependencies": { + "react": "^19.2.1" + } + }, + "node_modules/react-icons": { + "version": "5.5.0", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/react-icons/-/react-icons-5.5.0.tgz", + "integrity": "sha512-MEFcXdkP3dLo8uumGI5xN3lDFNsRtrjbOEKDLD7yv76v4wpnEq2Lt2qeHaQOr34I/wPN3s3+N08WkQ+CW37Xiw==", + "license": "MIT", + "peerDependencies": { + "react": "*" + } + }, + "node_modules/react-is": { + "version": "19.2.0", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/react-is/-/react-is-19.2.0.tgz", + "integrity": "sha512-x3Ax3kNSMIIkyVYhWPyO09bu0uttcAIoecO/um/rKGQ4EltYWVYtyiGkS/3xMynrbVQdS69Jhlv8FXUEZehlzA==", + "license": "MIT" + }, + "node_modules/react-leaflet": { + "version": "5.0.0", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/react-leaflet/-/react-leaflet-5.0.0.tgz", + "integrity": "sha512-CWbTpr5vcHw5bt9i4zSlPEVQdTVcML390TjeDG0cK59z1ylexpqC6M1PJFjV8jD7CF+ACBFsLIDs6DRMoLEofw==", + "license": "Hippocratic-2.1", + "dependencies": { + "@react-leaflet/core": "^3.0.0" + }, + "peerDependencies": { + "leaflet": "^1.9.0", + "react": "^19.0.0", + "react-dom": "^19.0.0" + } + }, + "node_modules/react-map-gl": { + "version": "8.1.0", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/react-map-gl/-/react-map-gl-8.1.0.tgz", + "integrity": "sha512-vDx/QXR3Tb+8/ap/z6gdMjJQ8ZEyaZf6+uMSPz7jhWF5VZeIsKsGfPvwHVPPwGF43Ryn+YR4bd09uEFNR5OPdg==", + "license": "MIT", + "dependencies": { + "@vis.gl/react-mapbox": "8.1.0", + "@vis.gl/react-maplibre": "8.1.0" + }, + "peerDependencies": { + "mapbox-gl": ">=1.13.0", + "maplibre-gl": ">=1.13.0", + "react": ">=16.3.0", + "react-dom": ">=16.3.0" + }, + "peerDependenciesMeta": { + "mapbox-gl": { + "optional": true + }, + "maplibre-gl": { + "optional": true + } + } + }, + "node_modules/react-redux": { + "version": "9.2.0", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/react-redux/-/react-redux-9.2.0.tgz", + "integrity": "sha512-ROY9fvHhwOD9ySfrF0wmvu//bKCQ6AeZZq1nJNtbDC+kk5DuSuNX/n6YWYF/SYy7bSba4D4FSz8DJeKY/S/r+g==", + "license": "MIT", + "dependencies": { + "@types/use-sync-external-store": "^0.0.6", + "use-sync-external-store": "^1.4.0" + }, + "peerDependencies": { + "@types/react": "^18.2.25 || ^19", + "react": "^18.0 || ^19", + "redux": "^5.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "redux": { + "optional": true + } + } + }, + "node_modules/react-refresh": { + "version": "0.18.0", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/react-refresh/-/react-refresh-0.18.0.tgz", + "integrity": "sha512-QgT5//D3jfjJb6Gsjxv0Slpj23ip+HtOpnNgnb2S5zU3CB26G/IDPGoy4RJB42wzFE46DRsstbW6tKHoKbhAxw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-router": { + "version": "7.9.6", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/react-router/-/react-router-7.9.6.tgz", + "integrity": "sha512-Y1tUp8clYRXpfPITyuifmSoE2vncSME18uVLgaqyxh9H35JWpIfzHo+9y3Fzh5odk/jxPW29IgLgzcdwxGqyNA==", + "license": "MIT", + "dependencies": { + "cookie": "^1.0.1", + "set-cookie-parser": "^2.6.0" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "react": ">=18", + "react-dom": ">=18" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + } + } + }, + "node_modules/react-router-dom": { + "version": "7.9.6", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/react-router-dom/-/react-router-dom-7.9.6.tgz", + "integrity": "sha512-2MkC2XSXq6HjGcihnx1s0DBWQETI4mlis4Ux7YTLvP67xnGxCvq+BcCQSO81qQHVUTM1V53tl4iVVaY5sReCOA==", + "license": "MIT", + "dependencies": { + "react-router": "7.9.6" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "react": ">=18", + "react-dom": ">=18" + } + }, + "node_modules/react-select": { + "version": "5.10.2", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/react-select/-/react-select-5.10.2.tgz", + "integrity": "sha512-Z33nHdEFWq9tfnfVXaiM12rbJmk+QjFEztWLtmXqQhz6Al4UZZ9xc0wiatmGtUOCCnHN0WizL3tCMYRENX4rVQ==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.12.0", + "@emotion/cache": "^11.4.0", + "@emotion/react": "^11.8.1", + "@floating-ui/dom": "^1.0.1", + "@types/react-transition-group": "^4.4.0", + "memoize-one": "^6.0.0", + "prop-types": "^15.6.0", + "react-transition-group": "^4.3.0", + "use-isomorphic-layout-effect": "^1.2.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/react-toastify": { + "version": "11.0.5", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/react-toastify/-/react-toastify-11.0.5.tgz", + "integrity": "sha512-EpqHBGvnSTtHYhCPLxML05NLY2ZX0JURbAdNYa6BUkk+amz4wbKBQvoKQAB0ardvSarUBuY4Q4s1sluAzZwkmA==", + "license": "MIT", + "dependencies": { + "clsx": "^2.1.1" + }, + "peerDependencies": { + "react": "^18 || ^19", + "react-dom": "^18 || ^19" + } + }, + "node_modules/react-transition-group": { + "version": "4.4.5", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/react-transition-group/-/react-transition-group-4.4.5.tgz", + "integrity": "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==", + "license": "BSD-3-Clause", + "dependencies": { + "@babel/runtime": "^7.5.5", + "dom-helpers": "^5.0.1", + "loose-envify": "^1.4.0", + "prop-types": "^15.6.2" + }, + "peerDependencies": { + "react": ">=16.6.0", + "react-dom": ">=16.6.0" + } + }, + "node_modules/readdirp": { + "version": "4.1.2", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/readdirp/-/readdirp-4.1.2.tgz", + "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14.18.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/redux": { + "version": "5.0.1", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/redux/-/redux-5.0.1.tgz", + "integrity": "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==", + "license": "MIT" + }, + "node_modules/redux-thunk": { + "version": "3.1.0", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/redux-thunk/-/redux-thunk-3.1.0.tgz", + "integrity": "sha512-NW2r5T6ksUKXCabzhL9z+h206HQw/NJkcLm1GPImRQ8IzfXwRGqjVhKJGauHirT0DAuyy6hjdnMZaRoAcy0Klw==", + "license": "MIT", + "peerDependencies": { + "redux": "^5.0.0" + } + }, + "node_modules/regexparam": { + "version": "2.0.2", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/regexparam/-/regexparam-2.0.2.tgz", + "integrity": "sha512-A1PeDEYMrkLrfyOwv2jwihXbo9qxdGD3atBYQA9JJgreAx8/7rC6IUkWOw2NQlOxLp2wL0ifQbh1HuidDfYA6w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/reselect": { + "version": "5.1.1", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/reselect/-/reselect-5.1.1.tgz", + "integrity": "sha512-K/BG6eIky/SBpzfHZv/dd+9JBFiS4SWV7FIujVyJRux6e45+73RaUHXLmIR1f7WOMaQ0U1km6qwklRQxpJJY0w==", + "license": "MIT" + }, + "node_modules/resolve": { + "version": "1.22.11", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/resolve/-/resolve-1.22.11.tgz", + "integrity": "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==", + "license": "MIT", + "dependencies": { + "is-core-module": "^2.16.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/resolve-protobuf-schema": { + "version": "2.1.0", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm/resolve-protobuf-schema/-/resolve-protobuf-schema-2.1.0.tgz", + "integrity": "sha512-kI5ffTiZWmJaS/huM8wZfEMer1eRd7oJQhDuxeCLe3t7N7mX3z94CN0xPxBQxFYQTSNz9T0i+v6inKqSdK8xrQ==", + "license": "MIT", + "dependencies": { + "protocol-buffers-schema": "^3.3.1" + } + }, + "node_modules/robust-predicates": { + "version": "2.0.4", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm/robust-predicates/-/robust-predicates-2.0.4.tgz", + "integrity": "sha512-l4NwboJM74Ilm4VKfbAtFeGq7aEjWL+5kVFcmgFA2MrdnQWx9iE/tUGvxY5HyMI7o/WpSIUFLbC5fbeaHgSCYg==", + "devOptional": true, + "license": "Unlicense" + }, + "node_modules/rollup": { + "version": "4.53.3", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/rollup/-/rollup-4.53.3.tgz", + "integrity": "sha512-w8GmOxZfBmKknvdXU1sdM9NHcoQejwF/4mNgj2JuEEdRaHwwF12K7e9eXn1nLZ07ad+du76mkVsyeb2rKGllsA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.8" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.53.3", + "@rollup/rollup-android-arm64": "4.53.3", + "@rollup/rollup-darwin-arm64": "4.53.3", + "@rollup/rollup-darwin-x64": "4.53.3", + "@rollup/rollup-freebsd-arm64": "4.53.3", + "@rollup/rollup-freebsd-x64": "4.53.3", + "@rollup/rollup-linux-arm-gnueabihf": "4.53.3", + "@rollup/rollup-linux-arm-musleabihf": "4.53.3", + "@rollup/rollup-linux-arm64-gnu": "4.53.3", + "@rollup/rollup-linux-arm64-musl": "4.53.3", + "@rollup/rollup-linux-loong64-gnu": "4.53.3", + "@rollup/rollup-linux-ppc64-gnu": "4.53.3", + "@rollup/rollup-linux-riscv64-gnu": "4.53.3", + "@rollup/rollup-linux-riscv64-musl": "4.53.3", + "@rollup/rollup-linux-s390x-gnu": "4.53.3", + "@rollup/rollup-linux-x64-gnu": "4.53.3", + "@rollup/rollup-linux-x64-musl": "4.53.3", + "@rollup/rollup-openharmony-arm64": "4.53.3", + "@rollup/rollup-win32-arm64-msvc": "4.53.3", + "@rollup/rollup-win32-ia32-msvc": "4.53.3", + "@rollup/rollup-win32-x64-gnu": "4.53.3", + "@rollup/rollup-win32-x64-msvc": "4.53.3", + "fsevents": "~2.3.2" + } + }, + "node_modules/rw": { + "version": "1.3.3", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm/rw/-/rw-1.3.3.tgz", + "integrity": "sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==", + "license": "BSD-3-Clause" + }, + "node_modules/scheduler": { + "version": "0.27.0", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/scheduler/-/scheduler-0.27.0.tgz", + "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==", + "license": "MIT" + }, + "node_modules/semver": { + "version": "6.3.1", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/set-cookie-parser": { + "version": "2.7.2", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/set-cookie-parser/-/set-cookie-parser-2.7.2.tgz", + "integrity": "sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw==", + "license": "MIT" + }, + "node_modules/set-value": { + "version": "2.0.1", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/set-value/-/set-value-2.0.1.tgz", + "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", + "license": "MIT", + "dependencies": { + "extend-shallow": "^2.0.1", + "is-extendable": "^0.1.1", + "is-plain-object": "^2.0.3", + "split-string": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/sirv": { + "version": "2.0.4", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/sirv/-/sirv-2.0.4.tgz", + "integrity": "sha512-94Bdh3cC2PKrbgSOUqTiGPWVZeSiXfKOVZNJniWoqrWrRkB1CJzBU3NEbiTsPcYy1lDsANA/THzS+9WBiy5nfQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@polka/url": "^1.0.0-next.24", + "mrmime": "^2.0.0", + "totalist": "^3.0.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/sort-asc": { + "version": "0.2.0", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/sort-asc/-/sort-asc-0.2.0.tgz", + "integrity": "sha512-umMGhjPeHAI6YjABoSTrFp2zaBtXBej1a0yKkuMUyjjqu6FJsTF+JYwCswWDg+zJfk/5npWUUbd33HH/WLzpaA==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sort-desc": { + "version": "0.2.0", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/sort-desc/-/sort-desc-0.2.0.tgz", + "integrity": "sha512-NqZqyvL4VPW+RAxxXnB8gvE1kyikh8+pR+T+CXLksVRN9eiQqkQlPwqWYU0mF9Jm7UnctShlxLyAt1CaBOTL1w==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sort-object": { + "version": "3.0.3", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/sort-object/-/sort-object-3.0.3.tgz", + "integrity": "sha512-nK7WOY8jik6zaG9CRwZTaD5O7ETWDLZYMM12pqY8htll+7dYeqGfEUPcUBHOpSJg2vJOrvFIY2Dl5cX2ih1hAQ==", + "license": "MIT", + "dependencies": { + "bytewise": "^1.1.0", + "get-value": "^2.0.2", + "is-extendable": "^0.1.1", + "sort-asc": "^0.2.0", + "sort-desc": "^0.2.0", + "union-value": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sort-on": { + "version": "6.1.1", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/sort-on/-/sort-on-6.1.1.tgz", + "integrity": "sha512-PB8pVvXAoRBijBCvuKJnmo06D8mSnQlLij0abfB2VdOpfFm29sPGYD4ft2prUPo1AZXTnkn3pP48AppRWyMkrw==", + "dev": true, + "license": "MIT", + "dependencies": { + "dot-prop": "^9.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/splaytree": { + "version": "0.1.4", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/splaytree/-/splaytree-0.1.4.tgz", + "integrity": "sha512-D50hKrjZgBzqD3FT2Ek53f2dcDLAQT8SSGrzj3vidNH5ISRgceeGVJ2dQIthKOuayqFXfFjXheHNo4bbt9LhRQ==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/split-string": { + "version": "3.1.0", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/split-string/-/split-string-3.1.0.tgz", + "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", + "license": "MIT", + "dependencies": { + "extend-shallow": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/split-string/node_modules/extend-shallow": { + "version": "3.0.2", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", + "license": "MIT", + "dependencies": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/split-string/node_modules/is-extendable": { + "version": "1.0.1", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "license": "MIT", + "dependencies": { + "is-plain-object": "^2.0.4" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/steno": { + "version": "4.0.2", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/steno/-/steno-4.0.2.tgz", + "integrity": "sha512-yhPIQXjrlt1xv7dyPQg2P17URmXbuM5pdGkpiMB3RenprfiBlvK415Lctfe0eshk90oA7/tNq7WEiMK8RSP39A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/typicode" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/stylis": { + "version": "4.2.0", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/stylis/-/stylis-4.2.0.tgz", + "integrity": "sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==", + "license": "MIT" + }, + "node_modules/supercluster": { + "version": "8.0.1", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm/supercluster/-/supercluster-8.0.1.tgz", + "integrity": "sha512-IiOea5kJ9iqzD2t7QJq/cREyLHTtSmUT6gQsweojg9WH2sYJqZK9SswTu6jrscO6D1G5v5vYZ9ru/eq85lXeZQ==", + "license": "ISC", + "dependencies": { + "kdbush": "^4.0.2" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/tabbable": { + "version": "6.3.0", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/tabbable/-/tabbable-6.3.0.tgz", + "integrity": "sha512-EIHvdY5bPLuWForiR/AN2Bxngzpuwn1is4asboytXtpTgsArc+WmSJKVLlhdh71u7jFcryDqB2A8lQvj78MkyQ==", + "license": "MIT" + }, + "node_modules/tinyglobby": { + "version": "0.2.15", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/tinyglobby/-/tinyglobby-0.2.15.tgz", + "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.3" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tinyglobby/node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/tinyglobby/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/tinyqueue": { + "version": "3.0.0", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm/tinyqueue/-/tinyqueue-3.0.0.tgz", + "integrity": "sha512-gRa9gwYU3ECmQYv3lslts5hxuIa90veaEcxDYuu3QGOIAEM2mOZkVHp48ANJuu1CURtRdHKUBY5Lm1tHV+sD4g==", + "license": "ISC" + }, + "node_modules/totalist": { + "version": "3.0.1", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/totalist/-/totalist-3.0.1.tgz", + "integrity": "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/ts-api-utils": { + "version": "2.1.0", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/ts-api-utils/-/ts-api-utils-2.1.0.tgz", + "integrity": "sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.12" + }, + "peerDependencies": { + "typescript": ">=4.8.4" + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-fest": { + "version": "4.41.0", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/type-fest/-/type-fest-4.41.0.tgz", + "integrity": "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/typescript-eslint": { + "version": "8.48.0", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/typescript-eslint/-/typescript-eslint-8.48.0.tgz", + "integrity": "sha512-fcKOvQD9GUn3Xw63EgiDqhvWJ5jsyZUaekl3KVpGsDJnN46WJTe3jWxtQP9lMZm1LJNkFLlTaWAxK2vUQR+cqw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/eslint-plugin": "8.48.0", + "@typescript-eslint/parser": "8.48.0", + "@typescript-eslint/typescript-estree": "8.48.0", + "@typescript-eslint/utils": "8.48.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/typewise": { + "version": "1.0.3", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/typewise/-/typewise-1.0.3.tgz", + "integrity": "sha512-aXofE06xGhaQSPzt8hlTY+/YWQhm9P0jYUp1f2XtmW/3Bk0qzXcyFWAtPoo2uTGQj1ZwbDuSyuxicq+aDo8lCQ==", + "license": "MIT", + "dependencies": { + "typewise-core": "^1.2.0" + } + }, + "node_modules/typewise-core": { + "version": "1.2.0", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/typewise-core/-/typewise-core-1.2.0.tgz", + "integrity": "sha512-2SCC/WLzj2SbUwzFOzqMCkz5amXLlxtJqDKTICqg30x+2DZxcfZN2MvQZmGfXWKNWaKK9pBPsvkcwv8bF/gxKg==", + "license": "MIT" + }, + "node_modules/undici-types": { + "version": "7.16.0", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/undici-types/-/undici-types-7.16.0.tgz", + "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", + "dev": true, + "license": "MIT" + }, + "node_modules/union-value": { + "version": "1.0.1", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/union-value/-/union-value-1.0.1.tgz", + "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", + "license": "MIT", + "dependencies": { + "arr-union": "^3.1.0", + "get-value": "^2.0.6", + "is-extendable": "^0.1.1", + "set-value": "^2.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.1.4", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/update-browserslist-db/-/update-browserslist-db-1.1.4.tgz", + "integrity": "sha512-q0SPT4xyU84saUX+tomz1WLkxUbuaJnR1xWt17M7fJtEJigJeWUNGUqrauFXsHnqev9y9JTRGwk13tFBuKby4A==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/use-isomorphic-layout-effect": { + "version": "1.2.1", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.2.1.tgz", + "integrity": "sha512-tpZZ+EX0gaghDAiFR37hj5MgY6ZN55kLiPkJsKxBMZ6GZdOSPJXiOzPM984oPYZ5AnehYx5WQp1+ME8I/P/pRA==", + "license": "MIT", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/use-sync-external-store": { + "version": "1.6.0", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz", + "integrity": "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==", + "license": "MIT", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/vite": { + "version": "7.2.4", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/vite/-/vite-7.2.4.tgz", + "integrity": "sha512-NL8jTlbo0Tn4dUEXEsUg8KeyG/Lkmc4Fnzb8JXN/Ykm9G4HNImjtABMJgkQoVjOBN/j2WAwDTRytdqJbZsah7w==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.25.0", + "fdir": "^6.5.0", + "picomatch": "^4.0.3", + "postcss": "^8.5.6", + "rollup": "^4.43.0", + "tinyglobby": "^0.2.15" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^20.19.0 || >=22.12.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", + "lightningcss": "^1.21.0", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/vite/node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/vite/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/wgs84": { + "version": "0.0.0", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/wgs84/-/wgs84-0.0.0.tgz", + "integrity": "sha512-ANHlY4Rb5kHw40D0NJ6moaVfOCMrp9Gpd1R/AIQYg2ko4/jzcJ+TVXYYF6kXJqQwITvEZP4yEthjM7U6rYlljQ==", + "license": "BSD-2-Clause" + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true, + "license": "ISC" + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/zod": { + "version": "4.1.13", + "resolved": "https://infyartifactory.jfrog.io/artifactory/api/npm/npm-remote/zod/-/zod-4.1.13.tgz", + "integrity": "sha512-AvvthqfqrAhNH9dnfmrfKzX5upOdjUVJYFqNSlkmGf64gRaTzlPwz99IHYnVs28qYAybvAlBV+H7pn0saFY4Ig==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + } + } +} diff --git a/frontend/mobile-ui/package.json b/frontend/mobile-ui/package.json new file mode 100644 index 0000000..433057a --- /dev/null +++ b/frontend/mobile-ui/package.json @@ -0,0 +1,63 @@ +{ + "name": "egov-digit", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "tsc -b && vite build", + "lint": "eslint .", + "preview": "vite preview" + }, + "dependencies": { + "@emotion/react": "^11.14.0", + "@emotion/styled": "^11.14.1", + "@mapbox/mapbox-gl-draw": "^1.5.1", + "@mui/icons-material": "^7.3.5", + "@mui/lab": "^7.0.1-beta.18", + "@mui/material": "^7.3.6", + "@mui/x-date-pickers": "^8.16.0", + "@reduxjs/toolkit": "^2.10.1", + "@types/leaflet": "^1.9.21", + "@types/react-redux": "^7.1.34", + "axios": "^1.12.2", + "clsx": "^2.1.1", + "date-fns": "^4.1.0", + "dayjs": "^1.11.19", + "dotenv": "^17.2.3", + "leaflet": "^1.9.4", + "leaflet-draw": "^1.0.4", + "maplibre-gl": "^5.14.0", + "react": "^19.2.1", + "react-datepicker": "^8.8.0", + "react-dom": "^19.2.1", + "react-icons": "^5.5.0", + "react-leaflet": "^5.0.0", + "react-map-gl": "^8.1.0", + "react-redux": "^9.2.0", + "react-router-dom": "^7.9.4", + "react-select": "^5.10.2", + "react-toastify": "^11.0.5", + "zod": "^4.1.12" + }, + "devDependencies": { + "@eslint/js": "^9.39.1", + "@types/leaflet-draw": "^1.0.13", + "@types/mapbox__mapbox-gl-draw": "^1.4.9", + "@types/node": "^24.6.0", + "@types/react": "^19.1.16", + "@types/react-dom": "^19.1.9", + "@vitejs/plugin-react": "^5.0.4", + "eslint": "^9.39.1", + "eslint-plugin-react-hooks": "^5.2.0", + "eslint-plugin-react-refresh": "^0.4.22", + "globals": "^16.4.0", + "json-server": "^1.0.0-beta.3", + "typescript": "~5.9.3", + "typescript-eslint": "^8.45.0", + "vite": "^7.2.4" + }, + "overrides": { + "js-yaml": "^4.1.1" + } +} diff --git a/frontend/mobile-ui/public/favicon.svg b/frontend/mobile-ui/public/favicon.svg new file mode 100644 index 0000000..90c8a16 --- /dev/null +++ b/frontend/mobile-ui/public/favicon.svg @@ -0,0 +1,4 @@ + + + D + diff --git a/frontend/mobile-ui/public/manifest.json b/frontend/mobile-ui/public/manifest.json new file mode 100644 index 0000000..9cede25 --- /dev/null +++ b/frontend/mobile-ui/public/manifest.json @@ -0,0 +1,29 @@ +{ + "name": "Property Form Mobile App", + "short_name": "PropertyForm", + "description": "Mobile application for property form management", + "start_url": "/", + "display": "standalone", + "theme_color": "#d2691e", + "background_color": "#f9f1f0", + "orientation": "portrait-primary", + "scope": "/", + "categories": ["business", "productivity"], + "icons": [ + { + "src": "/vite.svg", + "sizes": "any", + "type": "image/svg+xml", + "purpose": "any maskable" + } + ], + "prefer_related_applications": false, + "screenshots": [ + { + "src": "/screenshot-mobile.png", + "sizes": "390x844", + "type": "image/png", + "form_factor": "narrow" + } + ] +} \ No newline at end of file diff --git a/frontend/mobile-ui/public/vite.svg b/frontend/mobile-ui/public/vite.svg new file mode 100644 index 0000000..e7b8dfb --- /dev/null +++ b/frontend/mobile-ui/public/vite.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/mobile-ui/src/App.css b/frontend/mobile-ui/src/App.css new file mode 100644 index 0000000..ad40863 --- /dev/null +++ b/frontend/mobile-ui/src/App.css @@ -0,0 +1,17 @@ + + +#root { + width: 100%; + min-height: 100vh; + margin: 0; + padding: 0; + /* Remove text-align: center and min-width: 25% */ +} + +/* Add this to ensure forms display properly */ +.App { + width: 100%; + min-height: 100vh; + margin: 0; + padding: 0; +} \ No newline at end of file diff --git a/frontend/mobile-ui/src/App.tsx b/frontend/mobile-ui/src/App.tsx new file mode 100644 index 0000000..4bfe416 --- /dev/null +++ b/frontend/mobile-ui/src/App.tsx @@ -0,0 +1,35 @@ +// Main entry point for the React app +import React from 'react'; +import { Navigate, Route, BrowserRouter as Router, Routes } from 'react-router-dom'; +import './styles/globals.css'; +import Providers from './Providers'; +import 'react-toastify/dist/ReactToastify.css'; + +import CitizenRoutes from './app/routes/CitizenRoutes'; +import AgentRoutes from './app/routes/AgentRoutes'; +import { FormRoutes } from './app/routes/FormRoutes'; +import CommonRoutes from './app/routes/CommonRoutes'; + +// App component sets up global providers and all main routes +const App: React.FC = () => { + return ( + + {/* Set up React Router for all app routes */} + + + {/* Redirect root to landing page */} + } /> + {/* Citizen user routes */} + } /> + {/* Property form routes */} + } /> + {/* Agent user routes */} + } /> + {/* Common routes for all users (fallback) */} + } /> + + + + ); +}; +export default App; diff --git a/frontend/mobile-ui/src/Providers.tsx b/frontend/mobile-ui/src/Providers.tsx new file mode 100644 index 0000000..a7c0bfe --- /dev/null +++ b/frontend/mobile-ui/src/Providers.tsx @@ -0,0 +1,41 @@ +// Global providers wrapper for all React context and localization +import React from 'react'; +import { LanguageProvider } from './context/LanguageContext'; +import { SignUpFormProvider } from './context/SignUpFormContext'; +import { PropertyApplicationsProvider } from './context/PropertyApplicationsContext'; +import { PropertyFormProvider } from './context/PropertyFormContext'; +import { FormModeProvider } from './context/FormModeContext'; +import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'; +import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider'; +import { LocalizationProvider as LangProvider } from './services/Citizen/Localization/LocalizationContext'; +import { useAuth } from './context/AuthProvider'; + +// Props for Providers component (children to render) +interface ProvidersProps { + children: React.ReactNode; +} + +// Providers component wraps the app with all required context providers +// Includes language, form, property, and localization providers +const Providers: React.FC = ({ children }) => { + // Get user role from Auth context (used for localization) + const { role } = useAuth(); + return ( + + + + + + {/* MUI date localization and app language localization */} + + {children} + + + + + + + ); +}; + +export default Providers; diff --git a/frontend/mobile-ui/src/app/assets/Agent/Apple_Maps.svg b/frontend/mobile-ui/src/app/assets/Agent/Apple_Maps.svg new file mode 100644 index 0000000..9175450 --- /dev/null +++ b/frontend/mobile-ui/src/app/assets/Agent/Apple_Maps.svg @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/mobile-ui/src/app/assets/Agent/PropertyMarker.svg b/frontend/mobile-ui/src/app/assets/Agent/PropertyMarker.svg new file mode 100644 index 0000000..3c656cb --- /dev/null +++ b/frontend/mobile-ui/src/app/assets/Agent/PropertyMarker.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/mobile-ui/src/app/assets/Agent/Rectangle_100.svg b/frontend/mobile-ui/src/app/assets/Agent/Rectangle_100.svg new file mode 100644 index 0000000..d31f765 --- /dev/null +++ b/frontend/mobile-ui/src/app/assets/Agent/Rectangle_100.svg @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/mobile-ui/src/app/assets/Agent/account_circle.svg b/frontend/mobile-ui/src/app/assets/Agent/account_circle.svg new file mode 100644 index 0000000..9dec96e --- /dev/null +++ b/frontend/mobile-ui/src/app/assets/Agent/account_circle.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/frontend/mobile-ui/src/app/assets/Agent/add_a_photo.svg b/frontend/mobile-ui/src/app/assets/Agent/add_a_photo.svg new file mode 100644 index 0000000..8b294df --- /dev/null +++ b/frontend/mobile-ui/src/app/assets/Agent/add_a_photo.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/mobile-ui/src/app/assets/Agent/camera.svg b/frontend/mobile-ui/src/app/assets/Agent/camera.svg new file mode 100644 index 0000000..e0fd14a --- /dev/null +++ b/frontend/mobile-ui/src/app/assets/Agent/camera.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/frontend/mobile-ui/src/app/assets/Agent/date_range.svg b/frontend/mobile-ui/src/app/assets/Agent/date_range.svg new file mode 100644 index 0000000..728bd68 --- /dev/null +++ b/frontend/mobile-ui/src/app/assets/Agent/date_range.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/frontend/mobile-ui/src/app/assets/Agent/delete.svg b/frontend/mobile-ui/src/app/assets/Agent/delete.svg new file mode 100644 index 0000000..a24559c --- /dev/null +++ b/frontend/mobile-ui/src/app/assets/Agent/delete.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/frontend/mobile-ui/src/app/assets/Agent/edit_square.svg b/frontend/mobile-ui/src/app/assets/Agent/edit_square.svg new file mode 100644 index 0000000..8199b7a --- /dev/null +++ b/frontend/mobile-ui/src/app/assets/Agent/edit_square.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/frontend/mobile-ui/src/app/assets/Agent/info-icon.svg b/frontend/mobile-ui/src/app/assets/Agent/info-icon.svg new file mode 100644 index 0000000..a002a27 --- /dev/null +++ b/frontend/mobile-ui/src/app/assets/Agent/info-icon.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/mobile-ui/src/app/assets/Agent/info_outline.svg b/frontend/mobile-ui/src/app/assets/Agent/info_outline.svg new file mode 100644 index 0000000..d58a76a --- /dev/null +++ b/frontend/mobile-ui/src/app/assets/Agent/info_outline.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/frontend/mobile-ui/src/app/assets/Agent/notification_icon.svg b/frontend/mobile-ui/src/app/assets/Agent/notification_icon.svg new file mode 100644 index 0000000..04dae71 --- /dev/null +++ b/frontend/mobile-ui/src/app/assets/Agent/notification_icon.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/frontend/mobile-ui/src/app/assets/Agent/notifications.svg b/frontend/mobile-ui/src/app/assets/Agent/notifications.svg new file mode 100644 index 0000000..90f16d7 --- /dev/null +++ b/frontend/mobile-ui/src/app/assets/Agent/notifications.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/frontend/mobile-ui/src/app/assets/Agent/open_street_maps.svg b/frontend/mobile-ui/src/app/assets/Agent/open_street_maps.svg new file mode 100644 index 0000000..84de19f --- /dev/null +++ b/frontend/mobile-ui/src/app/assets/Agent/open_street_maps.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/frontend/mobile-ui/src/app/assets/Agent/undo.svg b/frontend/mobile-ui/src/app/assets/Agent/undo.svg new file mode 100644 index 0000000..8e3b437 --- /dev/null +++ b/frontend/mobile-ui/src/app/assets/Agent/undo.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/frontend/mobile-ui/src/app/assets/Citizen/home_page/property_pointer_dark.svg b/frontend/mobile-ui/src/app/assets/Citizen/home_page/property_pointer_dark.svg new file mode 100644 index 0000000..7d0889f --- /dev/null +++ b/frontend/mobile-ui/src/app/assets/Citizen/home_page/property_pointer_dark.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/frontend/mobile-ui/src/app/assets/Citizen/home_page/property_pointer_light.svg b/frontend/mobile-ui/src/app/assets/Citizen/home_page/property_pointer_light.svg new file mode 100644 index 0000000..4f4bde4 --- /dev/null +++ b/frontend/mobile-ui/src/app/assets/Citizen/home_page/property_pointer_light.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/frontend/mobile-ui/src/app/assets/Citizen/home_page/translate_indic.svg b/frontend/mobile-ui/src/app/assets/Citizen/home_page/translate_indic.svg new file mode 100644 index 0000000..29820c4 --- /dev/null +++ b/frontend/mobile-ui/src/app/assets/Citizen/home_page/translate_indic.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/frontend/mobile-ui/src/app/assets/Citizen/mycity_page/locateProperty.svg b/frontend/mobile-ui/src/app/assets/Citizen/mycity_page/locateProperty.svg new file mode 100644 index 0000000..7d44e3e --- /dev/null +++ b/frontend/mobile-ui/src/app/assets/Citizen/mycity_page/locateProperty.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/mobile-ui/src/app/assets/Citizen/property_page/activity_zone.svg b/frontend/mobile-ui/src/app/assets/Citizen/property_page/activity_zone.svg new file mode 100644 index 0000000..f2ca255 --- /dev/null +++ b/frontend/mobile-ui/src/app/assets/Citizen/property_page/activity_zone.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/mobile-ui/src/app/assets/Citizen/property_page/location.svg b/frontend/mobile-ui/src/app/assets/Citizen/property_page/location.svg new file mode 100644 index 0000000..7d64903 --- /dev/null +++ b/frontend/mobile-ui/src/app/assets/Citizen/property_page/location.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/frontend/mobile-ui/src/app/assets/Citizen/under_construction/tenor.gif b/frontend/mobile-ui/src/app/assets/Citizen/under_construction/tenor.gif new file mode 100644 index 0000000..2a15c0e Binary files /dev/null and b/frontend/mobile-ui/src/app/assets/Citizen/under_construction/tenor.gif differ diff --git a/frontend/mobile-ui/src/app/assets/PropertyMarker.svg b/frontend/mobile-ui/src/app/assets/PropertyMarker.svg new file mode 100644 index 0000000..c2ead8f --- /dev/null +++ b/frontend/mobile-ui/src/app/assets/PropertyMarker.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/mobile-ui/src/app/assets/activity_zone.svg b/frontend/mobile-ui/src/app/assets/activity_zone.svg new file mode 100644 index 0000000..8de0fd2 --- /dev/null +++ b/frontend/mobile-ui/src/app/assets/activity_zone.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/frontend/mobile-ui/src/app/assets/edit_square.svg b/frontend/mobile-ui/src/app/assets/edit_square.svg new file mode 100644 index 0000000..7e1dd2f --- /dev/null +++ b/frontend/mobile-ui/src/app/assets/edit_square.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/frontend/mobile-ui/src/app/assets/propertyTaxLogo.svg b/frontend/mobile-ui/src/app/assets/propertyTaxLogo.svg new file mode 100644 index 0000000..1555055 --- /dev/null +++ b/frontend/mobile-ui/src/app/assets/propertyTaxLogo.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/frontend/mobile-ui/src/app/components/BottomBar.tsx b/frontend/mobile-ui/src/app/components/BottomBar.tsx new file mode 100644 index 0000000..6ac1537 --- /dev/null +++ b/frontend/mobile-ui/src/app/components/BottomBar.tsx @@ -0,0 +1,108 @@ +// BottomBar is a shared navigation component for the Citizen interface. +// It provides a fixed bottom navigation bar with quick access to Home, Utilities, Properties, and My City. +// The component uses localization and dynamic icons to reflect the current route and language. +// Used in both mobile and desktop views for consistent navigation. + +import { useLocation, useNavigate } from 'react-router-dom'; +import HomeIcon from '@mui/icons-material/HomeOutlined'; +import HomeIconFilled from '@mui/icons-material/Home'; +import OfflineBoltIcon from '@mui/icons-material/OfflineBolt'; +import OfflineBoltOutlinedIcon from '@mui/icons-material/OfflineBoltOutlined'; +import ApartmentOutlinedIcon from '@mui/icons-material/ApartmentOutlined'; +import ApartmentIcon from '@mui/icons-material/Apartment'; +import CottageOutlinedIcon from '@mui/icons-material/CottageOutlined'; +import CottageIcon from '@mui/icons-material/Cottage'; +import { BottomNavigation, BottomNavigationAction, Paper } from '@mui/material'; +import { useAppSelector } from '../../redux/Hooks'; +import { getMessagesFromSession, useLocalization } from '../../services/Citizen/Localization/LocalizationContext'; +import LoadingPage from './Loader'; + + +export function BottomBar() { + // Get the current language for citizen from Redux store + const lang = useAppSelector((state) => state.lang.citizenLang); + // Get localization loading state + const { loading } = useLocalization(); + // Get localized messages for the citizen module + const messages = getMessagesFromSession("CITIZEN")!; + + // Show loader while localization messages are loading + if (loading) { + return ; + } + + // Navigation configuration for the bottom bar (desired order) + const navConfig = [ + { + label: messages['citizen.commons'][lang]['home-btn'], + icon: , + iconFilled: , + path: '/citizen', + }, + { + label: messages['citizen.commons'][lang]['my-city-btn'], + icon: , + iconFilled: , + path: '/under-construction', + }, + { + label: messages['citizen.commons'][lang]['properties-btn'], + icon: , + iconFilled: , + path: '/citizen/properties', + }, + { + label: messages['citizen.commons'][lang]['utility-btn'], + icon: , + iconFilled: , + path: '/under-construction', + }, + ]; + + const location = useLocation(); + const navigate = useNavigate(); + + // Find the current nav index by matching the most specific path first + const matchIndex = [...navConfig] + .map((cfg, idx) => ({ idx, len: cfg.path.length, match: location.pathname.startsWith(cfg.path) })) + .filter(x => x.match) + .sort((a, b) => b.len - a.len)[0]?.idx ?? 0; + + return ( + + navigate(navConfig[newValue].path)} + > + {navConfig.map((cfg, idx) => ( + + ))} + + + ); +} \ No newline at end of file diff --git a/frontend/mobile-ui/src/app/components/Header.tsx b/frontend/mobile-ui/src/app/components/Header.tsx new file mode 100644 index 0000000..ece792a --- /dev/null +++ b/frontend/mobile-ui/src/app/components/Header.tsx @@ -0,0 +1,53 @@ + +// Header is a reusable, styled top bar component for displaying a page or section title. +// It accepts a main header, an optional sub-header, and an optional icon. +// Used across both Agent and Citizen screens to provide consistent page headings. +import { Box, Typography } from "@mui/material"; +import type { FC } from "react"; +import type { HeaderProps } from "../models/Header.model"; + + +const Header: FC = ({ + header, // Main title text to display + subHeader, // Optional subtitle or description + icon, // Optional icon to display left of the title +}) => { + return ( + // Outer Box: fixed at the top, styled background, full width + + {/* Inner Box: aligns icon and text horizontally */} + + {icon} + + {/* Main header text */} + + {header} + + {/* Sub-header/description text */} + + {subHeader} + + + + + ); +}; + + +export default Header; \ No newline at end of file diff --git a/frontend/mobile-ui/src/app/components/Loader.tsx b/frontend/mobile-ui/src/app/components/Loader.tsx new file mode 100644 index 0000000..eb80a82 --- /dev/null +++ b/frontend/mobile-ui/src/app/components/Loader.tsx @@ -0,0 +1,66 @@ +import React from 'react'; +import { Box, styled, keyframes, Typography } from '@mui/material'; + +// Keyframes for the wave animation +const wave = keyframes` + 0%, 100% { + transform: translateY(0); + } + 50% { + transform: translateY(-20px); + } +`; + +// Styled component for each dot +const Dot = styled(Box)(({ theme }) => ({ + width: '16px', + height: '16px', + borderRadius: '50%', + backgroundColor: theme.palette.primary.main, + animation: `${wave} 1.2s ease-in-out infinite`, + '&:nth-of-type(2)': { + animationDelay: '0.2s', + }, + '&:nth-of-type(3)': { + animationDelay: '0.4s', + }, +})); + +// Container for the dots +const LoaderContainer = styled(Box)({ + display: 'flex', + flexDirection: 'column', + justifyContent: 'center', + alignItems: 'center', + gap: '24px', + height: '100vh', + backgroundColor: '#f5f5f5', +}); + +interface LoadingPageProps { + message?: string; +} + +const LoadingPage: React.FC = ({ message = 'Double-checking everything for youโ€ฆ' }) => { + return ( + + + + + + + + {message} + + + ); +}; + +export default LoadingPage; \ No newline at end of file diff --git a/frontend/mobile-ui/src/app/components/NavBar.tsx b/frontend/mobile-ui/src/app/components/NavBar.tsx new file mode 100644 index 0000000..e3cb51c --- /dev/null +++ b/frontend/mobile-ui/src/app/components/NavBar.tsx @@ -0,0 +1,68 @@ + +// NavBar is a reusable top navigation bar component specifically for the Citizen interface. +// It provides quick access to navigation actions: going back to the previous page and returning to the citizen home screen. +// The component uses localization for button labels and adapts to the current language. +// Used across multiple Citizen screens for consistent navigation and user experience. +import { Box } from '@mui/material'; +import type { FC } from 'react'; +import ArrowBackIosNewIcon from '@mui/icons-material/ArrowBackIosNew'; +import HomeOutlinedIcon from '@mui/icons-material/HomeOutlined'; +import { useNavigate } from 'react-router-dom'; +import { useAppSelector } from '../../redux/Hooks'; +import { + getMessagesFromSession, + useLocalization, +} from '../../services/Citizen/Localization/LocalizationContext'; +import NavButton from './NavButton'; +import LoadingPage from './Loader'; + + +const NavBar: FC = () => { + const navigate = useNavigate(); // React Router navigation hook + const lang = useAppSelector((state) => state.lang.citizenLang); // Get current citizen language + const { loading } = useLocalization(); // Localization loading state + const messages = getMessagesFromSession('CITIZEN')!; // Localized messages for citizen module + + // Show loader while localization messages are loading + if (loading) { + return ; + } + + return ( + // Outer Box: fixed at the top, styled background, horizontal layout + + {/* Previous button: navigates to previous page */} + } + message={messages['citizen.commons'][lang]['prev-btn']} + onClick={() => navigate(-1)} + /> + {/* Home button: navigates to citizen home page */} + } + message={messages['citizen.commons'][lang]['home-btn']} + onClick={() => navigate('/citizen', { replace: true })} + /> + + ); +}; + +export default NavBar; diff --git a/frontend/mobile-ui/src/app/components/NavButton.tsx b/frontend/mobile-ui/src/app/components/NavButton.tsx new file mode 100644 index 0000000..8b01500 --- /dev/null +++ b/frontend/mobile-ui/src/app/components/NavButton.tsx @@ -0,0 +1,41 @@ +// NavButton is a reusable button component for navigation actions. +// It displays an icon and a label, and triggers a callback when clicked. +// Used in navigation bars and other places where a styled navigation button is needed (e.g., Previous, Home). +// Accepts icon, message, and onClick handler as props. +import { Box, Typography } from "@mui/material"; +import type { FC } from "react"; +import type { NavButtonProps } from "../models/NavButton.model"; + + +const NavButton: FC = ({ icon, message, onClick }) => { + return ( + // Outer Box: styled container for icon and label + + {/* Icon displayed on the left */} + {icon} + {/* Navigation label/message */} + + {message} + + + ); +} + +export default NavButton; \ No newline at end of file diff --git a/frontend/mobile-ui/src/app/components/NavHeader.tsx b/frontend/mobile-ui/src/app/components/NavHeader.tsx new file mode 100644 index 0000000..ed7fef7 --- /dev/null +++ b/frontend/mobile-ui/src/app/components/NavHeader.tsx @@ -0,0 +1,78 @@ + +// NavHeader is a reusable top header component for both Citizen and Agent interfaces. +// It displays a fixed header bar with a styled 'Previous' button, localized label, and icon. +// The label and localization are determined by the role prop (CITIZEN or AGENT). +// Used for consistent navigation and UI across screens that require a back/previous action. +import { type FC } from 'react'; +import { Box, Typography, Button } from '@mui/material'; +import ChevronLeftIcon from '@mui/icons-material/ChevronLeft'; +import { useNavigate } from 'react-router-dom'; +import { getAppLocale } from '../../services/Profile/ProfileService'; +import { getMessagesFromSession } from '../../services/Citizen/Localization/LocalizationContext'; + + +const NavHeader: FC<{role : string}> = ({role}) => { + // Get current language from profile service + const lang = getAppLocale(); + // Get localized messages for the given role (CITIZEN or AGENT) + const messages = getMessagesFromSession(role === "CITIZEN" ? "CITIZEN" : "AGENT")!; + // React Router navigation hook + const navigate = useNavigate(); + + return ( + // Outer Box: fixed header bar, styled background + + {/* Previous button: navigates to previous page, styled as per design */} + + + ); +}; + +export default NavHeader; diff --git a/frontend/mobile-ui/src/app/components/NotFoundPage.tsx b/frontend/mobile-ui/src/app/components/NotFoundPage.tsx new file mode 100644 index 0000000..a563099 --- /dev/null +++ b/frontend/mobile-ui/src/app/components/NotFoundPage.tsx @@ -0,0 +1,105 @@ + +// NotFoundPage component displays a 404 error page for undefined routes +import React from "react"; +import { Box, Button, Container, Typography } from "@mui/material"; +import { useNavigate } from "react-router-dom"; + + +const NotFoundPage: React.FC = () => { + // Hook to programmatically navigate to other routes + const navigate = useNavigate(); + + return ( + // Outer Box for full viewport height and centering + + {/* Container to limit max width for content */} + + {/* Centered content box with vertical padding */} + + {/* Circular border with 404 text */} + + + 404 + + + + {/* Main heading for not found */} + + Page not found + + + {/* Description message */} + + The page you are looking for doesn't exist or may have been + moved. Please check the URL or return to the Property Tax Portal. + + + {/* Button to navigate back to the portal home */} + + + + + ); +}; + +// Export the NotFoundPage component as default +export default NotFoundPage; \ No newline at end of file diff --git a/frontend/mobile-ui/src/app/components/NotificationCard.tsx b/frontend/mobile-ui/src/app/components/NotificationCard.tsx new file mode 100644 index 0000000..fe4e425 --- /dev/null +++ b/frontend/mobile-ui/src/app/components/NotificationCard.tsx @@ -0,0 +1,233 @@ +// NotificationSettings is a reusable settings card for notification preferences. +// It displays notification categories (different for Citizen and Agent) and allows users to select delivery methods (SMS, WhatsApp, Email). +// The component uses localization for all labels and adapts to the current language and role. +// Used in profile/settings screens for both Citizen and Agent interfaces. +import React, { useState } from 'react'; +import { + Box, + Typography, + Switch, + FormControlLabel, + Paper, + Checkbox, +} from '@mui/material'; +import NotificationsNoneIcon from '@mui/icons-material/NotificationsNone'; +import { getAppLocale } from '../../services/Profile/ProfileService'; +import { getMessagesFromSession } from '../../services/Citizen/Localization/LocalizationContext'; +import { COLORS } from '../models/Colors.const'; + +export const NotificationSettings: React.FC<{ isCitizenProfile: boolean }> = ({ + isCitizenProfile, +}) => { + // State to track which delivery methods are selected + const [deliveryMethods, setDeliveryMethods] = useState({ + sms: false, + whatsapp: false, + email: false, + }); + + // Get current language and localized messages for the role + const lang = getAppLocale(); + const messages = getMessagesFromSession(isCitizenProfile ? 'CITIZEN' : 'AGENT')!; + + // Handler to update delivery method selection + const handleCheckboxChange = (event: React.ChangeEvent) => { + const { name, checked } = event.target; + setDeliveryMethods((prev) => ({ + ...prev, + [name]: checked, + })); + if (checked) { + console.log(`${name} checkbox checked`); + } + }; + + const notificationCategories = isCitizenProfile + ? [ + { + key: 'bill-reminders', + title: messages['profile'][lang]['bill-reminders'], + desc: messages['profile'][lang]['bill-reminders-desc'], + }, + { + key: 'license-expiry', + title: messages['profile'][lang]['license-expiry'], + desc: messages['profile'][lang]['license-expiry-desc'], + }, + { + key: 'service-updates', + title: messages['profile'][lang]['service-updates'], + desc: messages['profile'][lang]['service-updates-desc'], + }, + { + key: 'community-news', + title: messages['profile'][lang]['community-news'], + desc: messages['profile'][lang]['community-news-desc'], + }, + ] + : [ + { + key: 'application-updates', + title: 'application-updates', + desc: 'application-updates-desc', + }, + { + key: 'appointment-scheduling', + title: 'appointment-scheduling', + desc: 'appointment-scheduling-desc', + }, + ]; + + // Initialize toggles state with all categories enabled + const [toggles, setToggles] = useState( + Object.fromEntries(notificationCategories.map((cat) => [cat.key, true])) + ); + + const handleToggleChange = + (key: string) => (event: React.ChangeEvent) => { + setToggles((prev) => ({ + ...prev, + [key]: event.target.checked, + })); + }; + return ( + // Paper provides a styled card container for notification settings + + {/* Header with icon and title */} + + + + {/* Notification Settings */} + {messages['profile'][lang]['notification-settings']} + + + {/* Notification categories (different for Citizen and Agent) */} + + {notificationCategories.map((item) => ( + // Each notification category with title, description, and toggle switch + + + + {item.title} + + + {item.desc} + + + + + ))} + + + {/* Delivery methods section with checkboxes for SMS, WhatsApp, Email */} + + + {/* Delivery Methods */} + {messages['profile'][lang]['delivery-methods']} + + + {/* SMS Notifications checkbox */} + + } + label={ + + {/* SMS Notifications */} + {messages['profile'][lang]['sms-notifications']} + + } + /> + {/* WhatsApp Notifications checkbox */} + + } + label={ + + {/* Whatsapp Notifications */} + {messages['profile'][lang]['whatsapp-notifications']} + + } + /> + {/* Email Notifications checkbox */} + + } + label={ + + {/* Email Notifications */} + {messages['profile'][lang]['email-notifications']} + + } + /> + + + + ); +}; + +export default NotificationSettings; diff --git a/frontend/mobile-ui/src/app/components/Popup/AlertPopup.tsx b/frontend/mobile-ui/src/app/components/Popup/AlertPopup.tsx new file mode 100644 index 0000000..58ef6c8 --- /dev/null +++ b/frontend/mobile-ui/src/app/components/Popup/AlertPopup.tsx @@ -0,0 +1,16 @@ + +// AlertPopup is a wrapper for the Popup component, used to display alert messages +import type { PopupProps } from "../../models/Popup.model"; +import Popup from "./Popup"; + + +// Functional component for alert popups +export const AlertPopup = ({ title, message, type, open, onClose }: PopupProps) => ( + +); \ No newline at end of file diff --git a/frontend/mobile-ui/src/app/components/Popup/InformationPopup.tsx b/frontend/mobile-ui/src/app/components/Popup/InformationPopup.tsx new file mode 100644 index 0000000..376e1db --- /dev/null +++ b/frontend/mobile-ui/src/app/components/Popup/InformationPopup.tsx @@ -0,0 +1,16 @@ + +// InformationPopup is a wrapper for the Popup component, used to display informational messages +import type { PopupProps } from "../../models/Popup.model"; +import Popup from "./Popup"; + + +// Functional component for information popups +export const InformationPopup = ({ title, message, type, open, onClose }: PopupProps) => ( + +); \ No newline at end of file diff --git a/frontend/mobile-ui/src/app/components/Popup/NotificationPopup.tsx b/frontend/mobile-ui/src/app/components/Popup/NotificationPopup.tsx new file mode 100644 index 0000000..6fff4cb --- /dev/null +++ b/frontend/mobile-ui/src/app/components/Popup/NotificationPopup.tsx @@ -0,0 +1,43 @@ +// NotificationPopup component: renders different popup types based on 'type' prop +import type { PopupProps } from "../../models/Popup.model"; +import { AlertPopup } from "./AlertPopup"; +import { InformationPopup } from "./InformationPopup"; +import { SuccessPopup } from "./SuccessPopup"; +import { WarningPopup } from "./WarningPopup"; + +// Renders the appropriate popup component based on the 'type' prop +// Supported types: 'alert', 'information', 'warning', 'success' (default) +export const NotificationPopup = ({ title, message, type, open, onClose }: PopupProps) => ( + // If type is 'alert', render AlertPopup + type === 'alert' ? + // If type is 'information', render InformationPopup + : type === 'information' ? + // If type is 'warning', render WarningPopup + : type === 'warning' ? + // Default: render SuccessPopup + : +); \ No newline at end of file diff --git a/frontend/mobile-ui/src/app/components/Popup/Popup.tsx b/frontend/mobile-ui/src/app/components/Popup/Popup.tsx new file mode 100644 index 0000000..6ed9f4a --- /dev/null +++ b/frontend/mobile-ui/src/app/components/Popup/Popup.tsx @@ -0,0 +1,149 @@ + +// Popup component displays a modal notification with icon, title, and message +import React, { useEffect, useState } from 'react'; +import { + Modal, + Backdrop, + Fade, + Box, + Typography, +} from '@mui/material'; +import WarningAmberIcon from '@mui/icons-material/WarningAmber'; +import InfoIcon from '@mui/icons-material/Info'; +import ErrorIcon from '@mui/icons-material/Error'; +import CircleNotificationsOutlinedIcon from '@mui/icons-material/CircleNotificationsOutlined'; +import type { PopupProps } from '../../models/Popup.model'; + + +// Maps popup type to corresponding icon +const iconMap: Record = { + alert: , + information: , + warning: , + success: , +}; + + +// Maps popup type to accent color and background +const stylesMap: Record = { + alert: { borderColor: '#0057BD', bg: '#FFFFFF' }, + information: { borderColor: '#CB9C00', bg: '#FFFFFF' }, + warning: { borderColor: '#A30222', bg: '#FFFFFF' }, + success: { borderColor: '#00703C', bg: '#FFFFFF' }, +}; + + +// Popup functional component +export const Popup: React.FC = ({ + type = 'information', // Type of popup (alert, information, warning, success) + title, + message, + open, + duration = 3000, // Duration in ms before auto-close +}) => { + // Internal visibility state for animation and auto-close + const [visible, setVisible] = useState(open); + + // Sync visibility with open prop + useEffect(() => { + setVisible(open); + }, [open]); + + // Auto-close after duration if visible + useEffect(() => { + if (!visible) return; + if (duration > 0) { + const timer = window.setTimeout(() => { + setVisible(false); + }, duration); + return () => clearTimeout(timer); + } + }, [visible, duration]); + + // Get accent color for left border + const accentColor = stylesMap[type]?.borderColor ?? '#ccc'; + + // Render MUI Modal with Fade transition and custom styling + return ( + { + setVisible(false); + }} + closeAfterTransition + slots={{ backdrop: Backdrop }} + slotProps={{ + backdrop: { + timeout: 200, + sx: { backgroundColor: 'transparent' }, + }, + }} + aria-labelledby="popup-title" + aria-describedby="popup-message" + sx={{ + display: 'flex', + alignItems: 'flex-start', + justifyContent: 'center', + pointerEvents: 'none', + zIndex: (theme) => theme.zIndex.modal + 100, + }} + > + + + {/* Icon for the popup type */} + {iconMap[type]} + + {/* Content: title and message */} + + {title && ( + + {title} + + )} + {message && ( + + {message} + + )} + + + + + ); +}; + +// Export the Popup component as default +export default Popup; \ No newline at end of file diff --git a/frontend/mobile-ui/src/app/components/Popup/SuccessPopup.tsx b/frontend/mobile-ui/src/app/components/Popup/SuccessPopup.tsx new file mode 100644 index 0000000..516800f --- /dev/null +++ b/frontend/mobile-ui/src/app/components/Popup/SuccessPopup.tsx @@ -0,0 +1,16 @@ + +// SuccessPopup is a wrapper for the Popup component, used to display success messages +import type { PopupProps } from "../../models/Popup.model"; +import Popup from "./Popup"; + + +// Functional component for success popups +export const SuccessPopup = ({ title, message, type, open, onClose }: PopupProps) => ( + +); \ No newline at end of file diff --git a/frontend/mobile-ui/src/app/components/Popup/WarningPopup.tsx b/frontend/mobile-ui/src/app/components/Popup/WarningPopup.tsx new file mode 100644 index 0000000..dd5615c --- /dev/null +++ b/frontend/mobile-ui/src/app/components/Popup/WarningPopup.tsx @@ -0,0 +1,16 @@ + +// WarningPopup is a wrapper for the Popup component, used to display warning messages +import type { PopupProps } from "../../models/Popup.model"; +import Popup from "./Popup"; + + +// Functional component for warning popups +export const WarningPopup = ({ title, message, type, open, onClose }: PopupProps) => ( + +); \ No newline at end of file diff --git a/frontend/mobile-ui/src/app/components/ProfileCard.tsx b/frontend/mobile-ui/src/app/components/ProfileCard.tsx new file mode 100644 index 0000000..47f632b --- /dev/null +++ b/frontend/mobile-ui/src/app/components/ProfileCard.tsx @@ -0,0 +1,284 @@ +// ProfileCard is a reusable card component for displaying user profile information. +// It adapts its layout and fields based on whether the user is a Citizen or Agent. +// Shows personal details, verification status, contact info, address/jurisdiction, and summary stats. +// Used in profile screens for both Citizen and Agent interfaces. +import React, { useEffect, useMemo, useState } from 'react'; +import { Box, Typography, IconButton, Paper } from '@mui/material'; +import edit_square from '../../assets/icons/edit_square.svg'; +import CheckCircleOutlineIcon from '@mui/icons-material/CheckCircleOutline'; +import AccountCircleOutlinedIcon from '@mui/icons-material/AccountCircleOutlined'; +import { getUserFromSession } from '../../context/AuthProvider'; +import { getAppLocale } from '../../services/Profile/ProfileService'; +import { getMessagesFromSession } from '../../services/Citizen/Localization/LocalizationContext'; +import { COLORS } from '../models/Colors.const'; +import authService from '../../services/AuthService'; +import type { Address, UserProfile } from '../models/UserProfile.mode'; + +export const ProfileCard: React.FC<{ + isCitizenProfile: boolean; + noOfProperties: number; + noActiveLicenses: number; +}> = ({ isCitizenProfile, noOfProperties, noActiveLicenses }) => { + const [userProfile, setUserProfile] = useState(null); + + // Get user from session (memoized) + const sessionUser = useMemo(() => getUserFromSession(), []); + // Determine role (Agent or Citizen) + const role = authService.isAgent() ? 'AGENT' : 'CITIZEN'; + + // Get current language and localized messages + const lang = getAppLocale(); + const messages = getMessagesFromSession(role)!; + + // Localized labels for profile fields + const personalDetailsLabel = messages['profile'][lang]['personal-details']; + const personPhone = messages['profile'][lang]['phone-number']; + const personAddress = messages['profile'][lang]['residential-address']; + const personJurisdiction = messages['profile'][lang]['jurisdiction']; + const personProperties = messages['profile'][lang]['properties']; + const personLicenses = messages['profile'][lang]['licenses']; + const personMemberSince = messages['profile'][lang]['member-since']; + + // Load user profile from session storage on mount or when profile type changes + useEffect(() => { + const userString = sessionStorage.getItem('user'); + const user = userString ? JSON.parse(userString) : null; + setUserProfile(user); + }, [isCitizenProfile, sessionUser]); + + // Determine which profile data to display + const displayProfile = userProfile || (sessionUser as UserProfile) || {}; + + // Helper to get profile values with fallback + const getProfileValue = ( + profileKey: keyof NonNullable, + fallbackKey?: keyof UserProfile + ) => { + if (displayProfile.profile?.[profileKey]) { + return displayProfile.profile[profileKey]; + } + if (fallbackKey && displayProfile[fallbackKey]) { + return displayProfile[fallbackKey]; + } + return undefined; + }; + + // Extract main profile fields + const firstName = getProfileValue('firstName', 'firstName') as string; + const lastName = getProfileValue('lastName', 'lastName') as string; + const fullName = + (getProfileValue('fullName', 'fullName') as string) || + `${firstName || ''} ${lastName || ''}`.trim(); + const phoneNumber = getProfileValue('phoneNumber', 'phoneNumber') as string; + const aadharNo = getProfileValue('adhaarNo') as number | undefined; + const email = displayProfile.email; + const address = displayProfile.profile?.address || displayProfile.address; + const ward = displayProfile.ward; + + // Helper to format address for display + const formatAddress = (address: Address | undefined): string => { + if (!address) return 'Plot 567, 27th Main Road, HSR Layout'; + const parts = [ + address.addressLine1, + address.addressLine2, + address.city, + address.state, + address.pinCode, + ].filter(Boolean); + return parts.length > 0 ? parts.join(', ') : 'Address not provided'; + }; + + // Format member since date + const formatMemberSince = (dateString: string | undefined): string => { + if (!dateString) return 'N/A'; + + const date = new Date(dateString); + const options: Intl.DateTimeFormatOptions = { year: 'numeric', month: 'short' }; + return date.toLocaleDateString('en-US', options); + }; + + const memberSince = formatMemberSince(displayProfile.createdDate); + return ( + // Paper provides a styled card container for profile info + + {/* Header row with label and edit button */} + + + {personalDetailsLabel} + + + Edit + + + + {/* Main profile info row with avatar, name, verification status, and phone */} + + + + + {fullName || 'Name not available'} + + + + {isCitizenProfile ? ( + + {messages['profile'][lang]['verified-owner']} + + ) : ( + + {messages['profile'][lang]['verified-agent']} + + )} + + + {/* Masked phone number for citizen profile */} + {isCitizenProfile && ( + + {aadharNo + ? `${aadharNo.toString().slice(0, 4)} **** ***${aadharNo + .toString() + .slice(-1)}` + : ''} + + )} + + + + {/* Contact info and address/jurisdiction section */} + + + {messages['profile'][lang]['email-address']}: + + + {email || 'Email not available'} + + + + {personPhone}: + + + {phoneNumber || 'Phone not available'} + + + {/* Citizen: show address, Agent: show jurisdiction */} + {isCitizenProfile && ( + <> + + {personAddress}: + + + {formatAddress(address)} + + + )} + + {!isCitizenProfile && ( + + + {personJurisdiction}: + + {(ward || ['Ward Nos. 24 && 38 of BBMP', 'Ward Nos. 46 of BBMP']).map( + (item: string, index: number) => ( + + {item} + + ) + )} + + )} + + + {/* Citizen: show summary stats (properties, licenses, member since) */} + {isCitizenProfile && ( + + + + {noOfProperties} + + + {personProperties} + + + + + {noActiveLicenses} + + + {personLicenses} + + + + + {personMemberSince} + + + {memberSince} + + + + )} + + ); +}; + +export default ProfileCard; diff --git a/frontend/mobile-ui/src/app/components/SupportCard.tsx b/frontend/mobile-ui/src/app/components/SupportCard.tsx new file mode 100644 index 0000000..bcdb35c --- /dev/null +++ b/frontend/mobile-ui/src/app/components/SupportCard.tsx @@ -0,0 +1,112 @@ + +// SupportHelp is a reusable card component for displaying support and help options. +// It lists multiple support channels (helpdesk, email, portal) with icons, descriptions, and a contact button. +// Uses localization for all labels and adapts to the current language. +// Used in profile/settings screens for Citizen interface to provide quick access to support resources. +import React from "react"; +import { Box, Typography, Button, Paper } from "@mui/material"; +import HelpOutlineIcon from "@mui/icons-material/HelpOutline"; +import MailOutlineIcon from "@mui/icons-material/MailOutline"; +import ChatBubbleOutlineIcon from "@mui/icons-material/ChatBubbleOutline"; +import LiveHelpOutlinedIcon from "@mui/icons-material/LiveHelpOutlined"; +import { useAppSelector } from "../../redux/Hooks"; +import { getMessagesFromSession } from "../../services/Citizen/Localization/LocalizationContext"; +import { COLORS } from "../models/Colors.const"; + + + + +export const SupportHelp: React.FC = () => { + // Get current language and localized messages for Citizen + const lang = useAppSelector(state => state.lang.citizenLang); + const messages = getMessagesFromSession("CITIZEN")!; + + // List of support/help items to display + const supportItems = [ + { + icon: , + title: messages["profile"][lang]["bbmp-helpdesk"], + desc: messages["profile"][lang]["get-help-with-municipal-services"], + }, + { + icon: , + title: messages["profile"][lang]["email-support"], + desc: `${messages["profile"][lang]["write-to-us"]} support@bbmp.gov.in`, + }, + { + icon: , + title: messages["profile"][lang]["citizen-services-portal"], + desc: messages["profile"][lang]["browse-services-and-faqs"], + }, + ]; + + return( + // Paper provides a styled card container for support/help options + + {/* Header with icon and title */} + + + + {/* Support & Help */} + {messages["profile"][lang]["support-help"]} + + + {/* List of support/help items with icon, title, description, and contact button */} + {supportItems.map((item) => ( + + + {item.icon} + + + {item.title} + + + {item.desc} + + + + + + ))} + + ); +} + +export default SupportHelp; \ No newline at end of file diff --git a/frontend/mobile-ui/src/app/components/common/ConfirmationDialog.tsx b/frontend/mobile-ui/src/app/components/common/ConfirmationDialog.tsx new file mode 100644 index 0000000..1855223 --- /dev/null +++ b/frontend/mobile-ui/src/app/components/common/ConfirmationDialog.tsx @@ -0,0 +1,88 @@ + +// ConfirmationDialog component displays a modal dialog for confirming or rejecting an action +import React from 'react'; +import { + Dialog, + DialogContent, + Typography, + Button, + IconButton, + Box, +} from '@mui/material'; +import CloseIcon from '@mui/icons-material/Close'; +import { + confirmDialogPaperStyle, + confirmTitleStyle, + confirmDescStyle, + confirmNoteStyle, + confirmButtonBar, + rejectBtn, + confirmBtn, + closeButtonStyle, +} from '../../../styles/addRequestStyles/ConfirmationDialog'; + + +// Props for ConfirmationDialog +type ConfirmationDialogProps = { + open: boolean; // Whether the dialog is open + onReject: () => void; // Handler for reject action + onConfirm: () => void; // Handler for confirm action + onClose?: () => void; // Optional handler for closing the dialog +}; + + +// Functional component for the confirmation dialog +const ConfirmationDialog: React.FC = ({ + open, + onReject, + onConfirm, + onClose, +}) => ( + + {/* Close button at the top right */} + + + + + {/* Dialog title */} + Confirm Comment + {/* Confirmation message */} + + Are you sure you want to Confirm this request? + + {/* Note about irreversibility */} + + This action is irreversible. + + {/* Action buttons: Reject and Confirm */} + + + + + + +); + +// Export the ConfirmationDialog component as default +export default ConfirmationDialog; \ No newline at end of file diff --git a/frontend/mobile-ui/src/app/components/common/RequestDialog.tsx b/frontend/mobile-ui/src/app/components/common/RequestDialog.tsx new file mode 100644 index 0000000..3d9dd00 --- /dev/null +++ b/frontend/mobile-ui/src/app/components/common/RequestDialog.tsx @@ -0,0 +1,153 @@ + +// RequestDialog component allows users to submit a comment and optionally upload a file +import React, { useState } from 'react'; +import { + Dialog, + DialogTitle, + DialogContent, + DialogActions, + TextField, + Button, + Box, + IconButton, + Typography, +} from '@mui/material'; +import { Close as CloseIcon, CloudUpload as UploadIcon } from '@mui/icons-material'; +import { + requestDialogPaperStyle, + requestDialogTitleStyle, + requestDialogContentStyle, + requestTextFieldStyle, + fileUploadBoxStyle, + uploadIconStyle, + uploadTextStyle, + requestDialogActionsStyle, + cancelBtnStyle, + submitBtnStyle, + closeIconButtonStyle, +} from '../../../styles/addRequestStyles/requestDialog'; + + +// Props for RequestDialog +interface RequestDialogProps { + open: boolean; // Whether the dialog is open + onClose: () => void; // Handler to close the dialog + onSubmit: (comment: string, file?: File) => void; // Handler for submitting the comment and file +} + + +// Functional component for the request dialog +const RequestDialog: React.FC = ({ + open, + onClose, + onSubmit, +}) => { + // State for the comment input + const [comment, setComment] = useState(''); + // State for the selected file + const [selectedFile, setSelectedFile] = useState(undefined); + + // Handle submit button click + const handleSubmit = () => { + if (comment.trim()) { + onSubmit(comment, selectedFile); // Call parent handler + setComment(''); // Reset comment + setSelectedFile(undefined); // Reset file + } + }; + + // Handle file input change + const handleFileChange = (event: React.ChangeEvent) => { + const file = event.target.files?.[0]; + setSelectedFile(file); + }; + + // Handle dialog close (reset state) + const handleClose = () => { + setComment(''); + setSelectedFile(undefined); + onClose(); + }; + + return ( + + {/* Dialog title with close button */} + + + Add Comment + + + + + + + {/* Dialog content: comment input and file upload */} + + {/* Multiline text field for comment */} + setComment(e.target.value)} + sx={requestTextFieldStyle} + /> + + {/* File upload box (clickable) */} + document.getElementById('file-input')?.click()} + > + + + + {selectedFile + ? `Selected: ${selectedFile.name}` + : 'Click to upload a document (optional)'} + + + + + {/* Dialog actions: Cancel and Submit buttons */} + + + + + + ); +}; + +// Export the RequestDialog component as default +export default RequestDialog; \ No newline at end of file diff --git a/frontend/mobile-ui/src/app/features/Agent/api/agentApiSlice.ts b/frontend/mobile-ui/src/app/features/Agent/api/agentApiSlice.ts new file mode 100644 index 0000000..af418ca --- /dev/null +++ b/frontend/mobile-ui/src/app/features/Agent/api/agentApiSlice.ts @@ -0,0 +1,38 @@ + +// agentApiSlice sets up the base API configuration for Agent-related requests using Redux Toolkit Query. +// It handles authentication by attaching a valid token to each request header via AuthService. +// The base URL points to the backend service for agent operations. +// Endpoints for agent features should be defined in feature-specific slices that extend this base. +// Used for all network requests made by Agent screens/components. + +import authService from '../../../../services/AuthService'; + +import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react' + +// Define a service using a base URL and expected endpoints + +export const agentApiSlice = createApi({ + reducerPath: 'agentApi', // Unique key for agent API slice in Redux store + baseQuery: fetchBaseQuery({ + baseUrl: import.meta.env.VITE_ENUMERATION_HOST, // Backend base URL for agent operations + + // Prepare headers for every request (add auth token, content type) + prepareHeaders: async (headers, { getState: _getState }) => { + // Use AuthService to get a valid token (handles refresh automatically) + const token = await authService.getValidToken(); + if (token) { + headers.set('authorization', `Bearer ${token}`) + } + headers.set('content-type', 'application/json') + return headers + }, + }), + // Global tags for cache invalidation (can be extended) + // tagTypes: ALL_TAG_TYPES, + // Define endpoints in feature-specific API slices that extend this base + endpoints: () => ({}), +}) + + +export default agentApiSlice; + \ No newline at end of file diff --git a/frontend/mobile-ui/src/app/features/Agent/api/fetchProperty.hooks.ts b/frontend/mobile-ui/src/app/features/Agent/api/fetchProperty.hooks.ts new file mode 100644 index 0000000..8d1528c --- /dev/null +++ b/frontend/mobile-ui/src/app/features/Agent/api/fetchProperty.hooks.ts @@ -0,0 +1,64 @@ + +/** + * fetchPropertyDetails is an async utility for fetching and mapping property details for Agent screens. + * It retrieves property data by ID, transforms the response into the required form structure, + * and updates the form state. Handles errors by showing a popup. + * + * @param propID - Property ID to fetch + * @param getPropertyById - API function to fetch property by ID + * @param updateForm - Callback to update form state with mapped data + * @param showErrorPopup - Callback to show error popup on failure + */ +export const fetchPropertyDetails = async ( + propID: string, + applicationId: string, + getApplicationById: any, + getOwnerByPropertyId: any, + updateForm: (data: any) => void, + showErrorPopup: (message: string) => void +) => { + try { + const applicationData = await getApplicationById(applicationId).unwrap(); + const ownersData = await getOwnerByPropertyId(propID).unwrap(); + console.log(ownersData); + + updateForm({ + id: propID, + categoryOfOwnership: applicationData.data.Property.OwnershipType || '', + propertyType: applicationData.data.Property.PropertyType || '', + apartmentName: applicationData.data.Property.ComplexName || '', + propertyNo: applicationData.data.Property.PropertyNo || '', + propertyAddress: (applicationData.data.Property.Address as any) || undefined, + locationData: applicationData.data.Property.GISData + ? { + gisDataId: applicationData.data.Property.GISData.ID, + address: applicationData.data.Property.Address?.Locality || '', + coordinates: { + lat: applicationData.data.Property.GISData.Latitude || 0, + lng: applicationData.data.Property.GISData.Longitude || 0, + }, + drawnShapes: + applicationData.data.Property.GISData.Coordinates?.length > 0 + ? [ + { + type: 'polygon', + coordinates: applicationData.data.Property.GISData?.Coordinates.map( + (coord: any) => [coord.Longitude, coord.Latitude] + ), + }, + ] + : [], + } + : undefined, + owners: ownersData.data || [], + isgrDetails: (applicationData.data.Property.IGRS as any) || undefined, + assessmentDetails: (applicationData.data.Property.AssessmentDetails as any) || undefined, + importantNotes: applicationData.data.ImportantNote || '', + }); + + } catch (error) { + // Handle errors and show error popup + console.error('Error fetching property details:', error); + showErrorPopup('Failed to load property details'); + } +}; \ No newline at end of file diff --git a/frontend/mobile-ui/src/app/features/Agent/api/homePageApi.ts b/frontend/mobile-ui/src/app/features/Agent/api/homePageApi.ts new file mode 100644 index 0000000..b0ad7bc --- /dev/null +++ b/frontend/mobile-ui/src/app/features/Agent/api/homePageApi.ts @@ -0,0 +1,34 @@ + +// homePageApi defines API endpoints for fetching property lists for the Agent home page. +// It provides queries for both non-draft (active/finished) and draft properties assigned to the agent. +// Uses agentApiSlice for base API configuration and authentication. +// Returns RTK Query hooks for use in Agent screens/components. + +import apiSlice from '../../../../redux/apiSlice'; +import { TAG_TYPES } from '../../../../redux/tagTypes'; +import type { HomePageResponse } from '../models/HomePageData.model'; + +export const allPropertiesApi = apiSlice.injectEndpoints({ + endpoints: (builder) => ({ + // Fetch non-draft (active/finished) properties assigned to the agent + getAllProperties: builder.query({ + query: ({agentId}) => ({ + url: `v1/applications/search?assignedAgent=${agentId}&isDraft=false&status=ASSIGNED`, + method: 'GET', + }), + providesTags: [TAG_TYPES.APPLICATION, TAG_TYPES.PROPERTY], + }), + // Fetch draft properties assigned to the agent + getDraftProperties: builder.query({ + query: ({agentId}) => ({ + url: `v1/applications/search?assesseeID=${agentId}&isDraft=true`, + method: 'GET', + }), + providesTags: [TAG_TYPES.APPLICATION, TAG_TYPES.PROPERTY], + }), + }), +}); + + +// RTK Query hooks for use in Agent home page components +export const { useGetAllPropertiesQuery, useGetDraftPropertiesQuery } = allPropertiesApi; \ No newline at end of file diff --git a/frontend/mobile-ui/src/app/features/Agent/api/propertyData.hooks.ts b/frontend/mobile-ui/src/app/features/Agent/api/propertyData.hooks.ts new file mode 100644 index 0000000..5c249df --- /dev/null +++ b/frontend/mobile-ui/src/app/features/Agent/api/propertyData.hooks.ts @@ -0,0 +1,127 @@ + +// Custom hook for managing property data submission and updates for Agent workflows. +// Integrates form context and RTK Query mutations for property basics, GIS data, and coordinates. +// Used in Agent property creation/edit screens to handle async data operations. + +import { usePropertyForm } from "../../../../context/PropertyFormContext"; +import { useSubmitCoordinateBatchMutation, useSubmitGISDataMutation, useUpdateCoordinatesMutation, useUpdateGISDataMutation } from "../../../../redux/apis/gisApi"; +import { useSubmitPropertyBasicsMutation, useUpdatePropertyMutation } from "../../../../redux/apis/propertyApi"; + + +// usePropertyData provides async functions to save property basics, GIS data, and coordinates. +// It uses form data from context and exposes three main operations: +// - savePropertyBasics: create or update property basic info +// - saveGISData: create or update GIS data for a property +// - saveCoordinates: create or update coordinate batch for drawn shapes +export const usePropertyData = () => { + const { formData } = usePropertyForm(); + // RTK Query mutations for property and GIS operations + const [submitPropertyBasics] = useSubmitPropertyBasicsMutation(); + const [submitGISData] = useSubmitGISDataMutation(); + const [submitCoordinateBatch] = useSubmitCoordinateBatchMutation(); + const [updateProperty] = useUpdatePropertyMutation(); + const [updateGISData] = useUpdateGISDataMutation(); + const [updateCoordinates] = useUpdateCoordinatesMutation(); + + + // Save or update property basic information + // If propertyID is provided, updates existing property; otherwise, creates new property + const savePropertyBasics = async (propertyID?: string) => { + if (propertyID) { + const result = await updateProperty({ + propertyId: propertyID, + ownershipType: formData.categoryOfOwnership, + propertyType: formData.propertyType, + complexName: formData.apartmentName, + address: formData.propertyAddress!, + propertyNo: formData.propertyNo || '', + }).unwrap(); + // Return updated property ID and number + + return { propertyID, propertyNo: result.data?.PropertyNo }; + } else { + const result = await submitPropertyBasics({ + ownershipType: formData.categoryOfOwnership, + propertyType: formData.propertyType, + complexName: formData.apartmentName, + }).unwrap(); + // Return new property ID and number + + return { propertyID: result.data.ID, propertyNo: result.data.PropertyNo }; + } + }; + + + // Save or update GIS data for a property + // If gisDataId is provided, updates existing GIS data; otherwise, creates new GIS data + const saveGISData = async (propertyID: string, gisDataId?: string) => { + const { coordinates } = formData.locationData!; + + if (gisDataId) { + await updateGISData({ + gisDataId, + propertyId: propertyID, + source: 'GPS', + type: 'POLYGON', + }).unwrap(); + return gisDataId; + } else { + const result = await submitGISData({ + propertyId: propertyID, + latitude: coordinates?.lat!, + longitude: coordinates?.lng!, + source: 'GPS', + type: 'POLYGON', + }).unwrap(); + return result.data.ID; + } + }; + + + // Save or update coordinates for drawn polygon shapes + // If isUpdate is true, updates existing coordinates; otherwise, creates new batch + const saveCoordinates = async (gisDataId: string, isUpdate: boolean) => { + // Filter drawn shapes to get polygons only + const polygonShapes = formData.locationData?.drawnShapes?.filter( + (shape) => shape.type === 'polygon' + ) || []; + + if (polygonShapes.length === 0) return; + // Map polygon coordinates to batch format for API + const coordinateBatch = polygonShapes.flatMap((shape) => { + if (!shape.coordinates || !Array.isArray(shape.coordinates)) return []; + return (shape.coordinates as number[][]).map((coord) => { + // Coordinates are stored as [lng, lat] in drawnShapes (see LocationMapWithDrawing.finishShape) + const [initialLng, initialLat] = coord; + let lat = initialLat; + let lng = initialLng; + if (typeof lat !== 'number' || typeof lng !== 'number') { + // If shape coordinate format is unexpected, try to salvage by swapping + const [a, b] = coord as any[]; + if (typeof a === 'number' && typeof b === 'number') { + if (Math.abs(a) > 90 && Math.abs(b) <= 90) { + lat = b; + lng = a; + } else { + lat = b; + lng = a; + } + } + } + return { latitude: lat, longitude: lng, gisDataId }; + }); + }); + + if (coordinateBatch.length > 0) { + if (isUpdate) { + await updateCoordinates({ gisDataId, coordinates: coordinateBatch }).unwrap(); + } else { + await submitCoordinateBatch(coordinateBatch).unwrap(); + } + } + }; + + + // Expose async save functions for use in Agent property screens + return { savePropertyBasics, saveGISData, saveCoordinates }; +}; \ No newline at end of file diff --git a/frontend/mobile-ui/src/app/features/Agent/api/reviewPageApi.ts b/frontend/mobile-ui/src/app/features/Agent/api/reviewPageApi.ts new file mode 100644 index 0000000..71e8f9c --- /dev/null +++ b/frontend/mobile-ui/src/app/features/Agent/api/reviewPageApi.ts @@ -0,0 +1,24 @@ + +// reviewPageApi defines API endpoints for fetching property applications assigned to an agent for review. +// Uses agentApiSlice for base API configuration and authentication. +// Returns RTK Query hook for use in Agent review screens/components. + +import { agentApiSlice } from './agentApiSlice'; +import type { ApplicationsResponse } from '../models/ReviewPage.model'; + + +// Injects the getApplications endpoint for fetching applications with status AUDIT_VERIFIED assigned to the agent +export const applicationsApi = agentApiSlice.injectEndpoints({ + endpoints: (builder) => ({ + getApplications: builder.query({ + query: ({ AssignedAgent }) => ({ + url: `/v1/applications/search?AssignedAgent=${AssignedAgent}&status=AUDIT_VERIFIED`, + method: 'GET', + }), + }), + }), +}); + + +// RTK Query hook for use in Agent review page components +export const { useGetApplicationsQuery } = applicationsApi; \ No newline at end of file diff --git a/frontend/mobile-ui/src/app/features/Agent/api/searchPropertyApi.ts b/frontend/mobile-ui/src/app/features/Agent/api/searchPropertyApi.ts new file mode 100644 index 0000000..3ee9593 --- /dev/null +++ b/frontend/mobile-ui/src/app/features/Agent/api/searchPropertyApi.ts @@ -0,0 +1,25 @@ + +// API slice for searching properties assigned to an agent +import { agentApiSlice } from './agentApiSlice'; +import type { SearchPropertyResponse } from '../models/SearchPropertyData.model'; + + +// Injects endpoints into the agentApiSlice for property search +export const searchPropertyApi = agentApiSlice.injectEndpoints({ + endpoints: (builder) => ({ + // Query to get properties assigned to a specific agent + getProperties: builder.query({ + query: ({ assignedAgent }) => ({ + url: `/v1/applications/search?assignedAgent=${assignedAgent}`, + method: 'GET', + headers: { + 'X-Tenant-ID': 'pb.amritsar', // Tenant ID header for API + }, + }), + }), + }), +}); + + +// Export hooks for using the getProperties query +export const { useGetPropertiesQuery, useLazyGetPropertiesQuery } = searchPropertyApi; \ No newline at end of file diff --git a/frontend/mobile-ui/src/app/features/Agent/components/BottomNavigation.tsx b/frontend/mobile-ui/src/app/features/Agent/components/BottomNavigation.tsx new file mode 100644 index 0000000..3faddb2 --- /dev/null +++ b/frontend/mobile-ui/src/app/features/Agent/components/BottomNavigation.tsx @@ -0,0 +1,108 @@ +// BottomNavigation renders the bottom tab bar for Agent screens. +// Displays navigation tabs for Home, Inbox, Notifications, and Search. +// Highlights the active tab and handles tab changes via props. +// Uses MUI icons and localized tab labels. + +import React from 'react'; +import '../../../../styles/BottomNavigation.css'; +import SearchOutlinedIcon from '@mui/icons-material/SearchOutlined'; +import SearchIcon from '@mui/icons-material/Search'; +import DraftsOutlinedIcon from '@mui/icons-material/DraftsOutlined'; +import DraftsIcon from '@mui/icons-material/Drafts'; +import HomeOutlinedIcon from '@mui/icons-material/HomeOutlined'; +import HomeIcon from '@mui/icons-material/Home'; +import NotificationsNoneOutlinedIcon from '@mui/icons-material/NotificationsNoneOutlined'; +import NotificationsIcon from '@mui/icons-material/Notifications'; + +import { useAppLocalization } from '../../../../services/AgentLocalisation/localisation-search-property'; + + +// NavigationTab type defines available tabs +type NavigationTab = 'home' | 'inbox' | 'notifications' | 'search'; + + +// Props for BottomNavigation: +// - activeTab: currently selected tab +// - onTabChange: callback for tab change +interface BottomNavigationProps { + activeTab: NavigationTab; + onTabChange: (tab: NavigationTab) => void; +} + + +const BottomNavigation: React.FC = ({ + activeTab, + onTabChange +}) => { + // Get localized tab labels + const { homeNavText, inboxNavText, NotificationsNavText, searchNavText } = useAppLocalization(); + + // Handle tab click and notify parent + const handleTabClick = (tabId: NavigationTab) => { + onTabChange(tabId); + }; + + // Define navigation items with icons and labels + const navItems = [ + { + id: 'home' as NavigationTab, + label: homeNavText, + icon: activeTab === 'home' ? ( + + ) : ( + + ) + }, + { + id: 'inbox' as NavigationTab, + label: inboxNavText, + icon: activeTab === 'inbox' ? ( + + ) : ( + + ) + }, + { + id: 'notifications' as NavigationTab, + label: NotificationsNavText, + icon: activeTab === 'notifications' ? ( + + ) : ( + + ) + }, + { + id: 'search' as NavigationTab, + label: searchNavText, + icon: activeTab === 'search' ? ( + + ) : ( + + ) + } + ]; + + // Render bottom navigation bar with tab buttons + return ( +
+ {navItems.map((item) => ( + + ))} +
+ ); +}; + + +// Export BottomNavigation for use in Agent screens +export default BottomNavigation; \ No newline at end of file diff --git a/frontend/mobile-ui/src/app/features/Agent/components/ChromeTabs.tsx b/frontend/mobile-ui/src/app/features/Agent/components/ChromeTabs.tsx new file mode 100644 index 0000000..bb4f264 --- /dev/null +++ b/frontend/mobile-ui/src/app/features/Agent/components/ChromeTabs.tsx @@ -0,0 +1,109 @@ + +// ChromeTabs renders a tab switcher styled like Chrome browser tabs for Agent screens. +// Displays two tabs (Map and Landuse) with localized labels. +// Highlights the selected tab and notifies parent on tab change. +// Uses MUI styled components for custom appearance. + +import React from 'react'; +import { Box, Button, styled } from '@mui/material'; +import { useHomePageLocalization } from '../../../../services/AgentLocalisation/localisation-homepage'; + + +// Props for ChromeTabs: +// - selected: index of currently selected tab (0 or 1) +// - onTabChange: callback for tab change +// - height: optional tab height (default 50) +interface ChromeTabsProps { + selected: number; + onTabChange: (idx: number) => void; + height?: number; +} + + +const ChromeTabs: React.FC = ({ + selected, + onTabChange, + height = 50 +}) => { + // Get localized tab labels + const { mapTabText, landuseTabText } = useHomePageLocalization(); + + // Render two styled tab buttons for Map and Landuse + return ( + + onTabChange(0)} + style={{ + borderTopLeftRadius: 18, + borderTopRightRadius: 0, + }} + > + {mapTabText} + + onTabChange(1)} + style={{ + borderTopLeftRadius: 0, + borderTopRightRadius: 18, + }} + > + {landuseTabText} + + + ); +}; + + +// Container for tab buttons, styled for Chrome-like appearance +const TabsContainer = styled(Box)({ + display: 'flex', + alignItems: 'center', + justifyItems:'center', + width: '338px', + border: '1px solid #000', + borderTopLeftRadius: 14, + borderTopRightRadius: 14, + borderBottomLeftRadius: 0, + borderBottomRightRadius: 0, + overflow: 'hidden', + background: '#fff', + paddingBottom:'0.5px' +}); + + +// Styled tab button for ChromeTabs, highlights when selected +const TabButton = styled(Button, { + shouldForwardProp: (prop) => prop !== '$isSelected' && prop !== '$height' +})<{ + $isSelected: boolean; + $height: number; +}>(({ $isSelected, $height }) => ({ + flex: 1, + minWidth: 0, + height: $height, + fontWeight: $isSelected ? 400 : 300, + fontSize: 15, + background: $isSelected ? '#ededed' : '#fff', + color: '#000', + border: 'none', + borderRadius: 0, + boxShadow: 'none', + textTransform: 'none', + transition: 'background 0.2s', + '&:hover': { + background: $isSelected ? '#ededed' : '#f5f5f5', + }, + // Remove focus ring + '&:focus-visible': { + outline: 'none', + }, +})); + + +// Export ChromeTabs for use in Agent screens +export default ChromeTabs; + \ No newline at end of file diff --git a/frontend/mobile-ui/src/app/features/Agent/components/DetailsCard.tsx b/frontend/mobile-ui/src/app/features/Agent/components/DetailsCard.tsx new file mode 100644 index 0000000..679b368 --- /dev/null +++ b/frontend/mobile-ui/src/app/features/Agent/components/DetailsCard.tsx @@ -0,0 +1,43 @@ + +// DetailsCard displays a styled card with a heading and a list of key-value pairs. +// Used in Agent screens to show property or user details in a readable format. +// Accepts a heading and an array of items to render. + +import React from 'react'; +import '../../../../styles/Agent/DetailsCard.css'; + + +// KeyValue type for each row in the details list +type KeyValue = { + key: string; + value: React.ReactNode; +}; + + +// Props for DetailsCard: +// - heading: card title +// - items: array of key-value pairs to display +interface DetailsCardProps { + heading: string; + items: KeyValue[]; +} + + +// Render a card with heading and key-value rows +const DetailsCard: React.FC = ({ heading, items }) => ( +
+
{heading}
+
+ {items.map(({ key, value }, i) => ( +
+ {key} : + {value} +
+ ))} +
+
+); + + +// Export DetailsCard for use in Agent screens +export default DetailsCard; \ No newline at end of file diff --git a/frontend/mobile-ui/src/app/features/Agent/components/Layout.tsx b/frontend/mobile-ui/src/app/features/Agent/components/Layout.tsx new file mode 100644 index 0000000..e510ac9 --- /dev/null +++ b/frontend/mobile-ui/src/app/features/Agent/components/Layout.tsx @@ -0,0 +1,466 @@ +import React, { useState, useEffect, useRef } from 'react'; +import BottomNavigation from '../components/BottomNavigation'; +import '../../../../styles/Layout.css'; +import LocationOnOutlinedIcon from '@mui/icons-material/LocationOnOutlined'; +import KeyboardBackspaceOutlinedIcon from '@mui/icons-material/KeyboardBackspaceOutlined'; +import HomeOutlinedIcon from '@mui/icons-material/HomeOutlined'; +import LogoutIcon from '@mui/icons-material/Logout'; +import { useAuth } from '../../../../context/AuthProvider'; +import { useNavigate } from 'react-router-dom'; +import { useLanguage } from '../../../../context/LanguageContext'; +import { useAppLocalization } from '../../../../services/AgentLocalisation/localisation-search-property'; +import translateIndicSvg from '../../../assets/Citizen/home_page/translate_indic.svg'; +import AccountCircleOutlinedIcon from '@mui/icons-material/AccountCircleOutlined'; +import { Button, FormControl, InputLabel, MenuItem, Select } from '@mui/material'; + +type NavigationTab = 'home' | 'inbox' | 'notifications' | 'search'; + +interface AgentUser { + id: string; + username: string; + email: string; + role: string; + isActive: boolean; + zoneData: { + zoneNumber: string; + wards: string[]; + }[]; + preferredLanguage: string; + profile: { + firstName: string; + lastName: string; + fullName: string; + phoneNumber: string; + adhaarNo: number; + gender: string; + address: { + addressLine1: string; + addressLine2: string | null; + city: string; + state: string; + pinCode: string; + }; + department: string; + designation: string; + }; + createdDate: string; + updatedDate: string; + createdBy: string; + updatedBy: string; +} + +interface LayoutProps { + children: React.ReactNode; + activeTab: NavigationTab; + onTabChange: (tab: NavigationTab) => void; + showHeader?: boolean; + showNavigation?: boolean; + hideLocationIcon?: boolean; + headerProps?: { + title?: string; + showBackButton?: boolean; + onBack?: () => void; + showLanguage?: boolean; + showProfile?: boolean; + showHome?: boolean; + onHome?: () => void; + locationText?: string; + onLanguageSelect?: (locale: string) => void; + currentLocale?: string; + jurisdictionText?: string; + languageText?: string; + profileText?: string; + logoutText?: string; + homeNavText?: string; + inboxNavText?: string; + insightsNavText?: string; + searchNavText?: string; + }; +} + +const Layout: React.FC = ({ + children, + activeTab, + onTabChange, + showNavigation = true, + hideLocationIcon = false, + headerProps = {}, +}) => { + const { logout } = useAuth(); + const { locale, setLocale } = useLanguage(); + const { jurisdictionText, languageText, profileText, logoutText } = + useAppLocalization(); + // Read agent user from sessionStorage + const agentUser: AgentUser | null = (() => { + try { + const userStr = sessionStorage.getItem('user'); + return userStr ? JSON.parse(userStr) : null; + } catch { + return null; + } + })(); + const zoneData = agentUser?.zoneData || []; + const [selectedZoneIndex, setSelectedZoneIndex] = useState(0); + const [selectedWard, setSelectedWard] = useState( + zoneData?.[0]?.wards?.[0] || '' + ); + + const [showProfileDropdown, setShowProfileDropdown] = useState(false); + const [showLanguageDropdown, setShowLanguageDropdown] = useState(false); + const [showLocationPopup, setShowLocationPopup] = useState(false); + const profileRef = useRef(null); + const languageRef = useRef(null); + const locationPopupRef = useRef(null); + const navigate = useNavigate(); + const languages = [ + { code: 'en', name: 'English' }, + { code: 'hi', name: 'เคนเคฟเค‚เคฆเฅ€' }, + { code: 'kn', name: 'เฒ•เฒจเณเฒจเฒก' }, + ]; + + useEffect(() => { + const handleClickOutside = (event: MouseEvent) => { + const target = event.target as Node; + + // Profile dropdown + if (profileRef.current && !profileRef.current.contains(target)) { + setShowProfileDropdown(false); + } + + // Language dropdown + if (languageRef.current && !languageRef.current.contains(target)) { + setShowLanguageDropdown(false); + } + + // Location popup (with MUI Select support) + if (showLocationPopup) { + const popup = locationPopupRef.current; + + // If clicking inside the location popup, ignore + if (popup && popup.contains(target)) return; + + // If clicking inside MUI Select menu, ignore + const popoverMenu = document.querySelector('.MuiPopover-root,.MuiMenu-root'); + if (popoverMenu && popoverMenu.contains(target)) return; + + // If clicking outside, close + setShowLocationPopup(false); + } + }; + + document.addEventListener('mousedown', handleClickOutside); + return () => { + document.removeEventListener('mousedown', handleClickOutside); + }; + }, [showLocationPopup]); + + const handleProfileClick = () => { + navigate('/profile'); + }; + + const handleLanguageClick = () => { + setShowLanguageDropdown(!showLanguageDropdown); + }; + + const handleLanguageSelect = (langCode: string) => { + setLocale(langCode); + setShowLanguageDropdown(false); + }; + + const handleLogout = () => { + logout(); + setShowProfileDropdown(false); + navigate('/login'); + }; + + const handleZoneSelect = (i: number) => { + setSelectedZoneIndex(i); + setSelectedWard(zoneData[i]?.wards?.[0] || ''); + }; + + const handleWardSelect = (ward: string) => { + setSelectedWard(ward); + }; + + const handleJurisdictionConfirm = () => { + setShowLocationPopup(false); + // Here you can save selected zone/ward if needed elsewhere + }; + + return ( +
+
+
+
+ {headerProps.showBackButton && headerProps.onBack ? ( + + ) : !hideLocationIcon ? ( +
+
setShowLocationPopup(true)} + style={{ cursor: 'pointer' }} + aria-label="Location" + > +
+ +
+ {jurisdictionText} +
+
+ {zoneData[selectedZoneIndex]?.zoneNumber ?? ''} +
+
+ {selectedWard} +
+
+
+
+
+ {/* Location Popup */} + {showLocationPopup && ( +
+
+
+ + Select Zone & Ward + + +
+
+ + Zone + + + + Ward + + +
+ +
+
+ )} +
+ ) : null} +
+ + {headerProps.title && ( + + )} + +
+ {headerProps.showLanguage && ( +
+ + + {languageText} + + {showLanguageDropdown && ( +
+ {languages.map((lang) => ( +
handleLanguageSelect(lang.code)} + style={{ + backgroundColor: + locale === lang.code ? '#f0f0f0' : 'transparent', + fontWeight: locale === lang.code ? 'bold' : 'normal', + }} + > + {lang.name} +
+ ))} +
+ )} +
+ )} + {headerProps.showHome && ( +
(e.currentTarget as HTMLElement).blur()} + > + +
+ )} + {headerProps.showProfile && ( +
+
(e.currentTarget as HTMLElement).blur()} + > + +
+ + {profileText} + + {showProfileDropdown && ( +
+
+ + {logoutText} +
+
+ )} +
+ )} +
+
+ {children} +
+ {showNavigation && ( + + )} +
+ ); +}; + +export default Layout; diff --git a/frontend/mobile-ui/src/app/features/Agent/components/LocationPinMap.tsx b/frontend/mobile-ui/src/app/features/Agent/components/LocationPinMap.tsx new file mode 100644 index 0000000..ac229dc --- /dev/null +++ b/frontend/mobile-ui/src/app/features/Agent/components/LocationPinMap.tsx @@ -0,0 +1,242 @@ + +// LocationPinMap component displays a Leaflet map with a fixed center pin and reverse geocoding +import React, { useEffect, useRef } from 'react'; +import { MapContainer, TileLayer } from 'react-leaflet'; +import 'leaflet/dist/leaflet.css'; +import L from 'leaflet'; + +// Fix for default markers not appearing in Leaflet +delete (L.Icon.Default.prototype as any)._getIconUrl; +L.Icon.Default.mergeOptions({ + iconRetinaUrl: 'https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.7.1/images/marker-icon-2x.png', + iconUrl: 'https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.7.1/images/marker-icon.png', + shadowUrl: 'https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.7.1/images/marker-shadow.png', +}); + + +// Props for LocationPinMap +interface LocationPinMapProps { + center: [number, number]; // Initial center of the map + onLocationUpdate: (lat: number, lng: number, address: string) => void; // Callback when location changes +} + +// Helper function to get reverse geocoded address with fallback +// Tries Photon API, then a simple area lookup, then falls back to coordinates +const getReverseGeocodedAddress = async (lat: number, lng: number): Promise => { + try { + // Use Photon API which is CORS-friendly + const response = await fetch( + `https://photon.komoot.io/reverse?lat=${lat}&lon=${lng}`, + { + method: 'GET', + headers: { + 'Accept': 'application/json' + } + } + ); + + if (response.ok) { + const data = await response.json(); + if (data.features && data.features.length > 0) { + const feature = data.features[0]; + if (feature.properties) { + const props = feature.properties; + const parts = []; + + // Build address from available components + if (props.housenumber) parts.push(props.housenumber); + if (props.street) parts.push(props.street); + if (props.district) parts.push(props.district); + if (props.city) parts.push(props.city); + if (props.state) parts.push(props.state); + + if (parts.length > 0) { + return parts.join(', '); + } + + // Fallback to name if available + if (props.name) { + return props.name; + } + } + } + } + } catch (error) { + console.warn('Photon geocoding failed, trying alternative:', error); + } + + // Try alternative approach with a simple area lookup + try { + // For Indian coordinates, provide a basic area estimation + if (lat >= 8 && lat <= 37 && lng >= 68 && lng <= 97) { + // This is within India bounds + const areas = { + bangalore: { lat: 12.9716, lng: 77.5946, name: 'Bangalore, Karnataka' }, + delhi: { lat: 28.6139, lng: 77.2090, name: 'Delhi' }, + mumbai: { lat: 19.0760, lng: 72.8777, name: 'Mumbai, Maharashtra' }, + chennai: { lat: 13.0827, lng: 80.2707, name: 'Chennai, Tamil Nadu' }, + hyderabad: { lat: 17.3850, lng: 78.4867, name: 'Hyderabad, Telangana' }, + pune: { lat: 18.5204, lng: 73.8567, name: 'Pune, Maharashtra' } + }; + + // Find closest major city + let closestArea = 'Unknown Area, India'; + let minDistance = Infinity; + + Object.values(areas).forEach(area => { + const distance = Math.sqrt( + Math.pow(lat - area.lat, 2) + Math.pow(lng - area.lng, 2) + ); + if (distance < minDistance) { + minDistance = distance; + closestArea = area.name; + } + }); + + return `Near ${closestArea}`; + } + } catch (error) { + console.warn('Area lookup failed:', error); + } + + // Final fallback: return formatted coordinates + return `Location: ${lat.toFixed(4)}ยฐN, ${lng.toFixed(4)}ยฐE`; +}; + + +const LocationPinMap: React.FC = ({ center, onLocationUpdate }) => { + // Reference to the Leaflet map instance + const mapRef = useRef(null); + // Reference for debouncing location updates + const debounceTimeoutRef = useRef(null); + // Reference to the map container div + const containerRef = useRef(null); + + // ResizeObserver to handle map resizing when container size changes + useEffect(() => { + const resizeObserver = new ResizeObserver(() => { + if (mapRef.current) { + setTimeout(() => { + mapRef.current?.invalidateSize(); + }, 100); + } + }); + + if (containerRef.current) { + resizeObserver.observe(containerRef.current); + } + + return () => { + resizeObserver.disconnect(); + }; + }, []); + + // Aggressively fix map size after mount + useEffect(() => { + const fixMapSize = () => { + if (mapRef.current) { + mapRef.current.invalidateSize(true); + mapRef.current.getContainer().style.height = '100%'; + } + }; + + const intervals = [100, 250, 500, 1000]; + const timeouts = intervals.map(delay => setTimeout(fixMapSize, delay)); + + return () => { + timeouts.forEach(clearTimeout); + }; + }, []); + + // Clean up debounce timeout on unmount + useEffect(() => { + return () => { + if (debounceTimeoutRef.current) { + clearTimeout(debounceTimeoutRef.current); + } + }; + }, []); + + // Handler for when the map stops moving (user pans/zooms) + const handleMapMoveEnd = () => { + if (!mapRef.current) return; + + // Get the center coordinates for location display (no pin needed) + const mapCenter = mapRef.current.getCenter(); + const lat = mapCenter.lat; + const lng = mapCenter.lng; + + // Clear previous timeout + if (debounceTimeoutRef.current) { + clearTimeout(debounceTimeoutRef.current); + } + + // Debounce the location update + debounceTimeoutRef.current = window.setTimeout(async () => { + if (!mapRef.current) return; + + try { + // Use a more reliable geocoding approach + const address = await getReverseGeocodedAddress(lat, lng); + onLocationUpdate(lat, lng, address); + } catch (error) { + console.error('Error getting address:', error); + onLocationUpdate(lat, lng, `${lat.toFixed(6)}, ${lng.toFixed(6)}`); + } + }, 500); // 500ms debounce + }; + + // Handler for when the map is ready (mounted) + const handleMapReady = () => { + // Simplified map size fixing with new CSS overrides + setTimeout(() => { + if (mapRef.current) { + mapRef.current.invalidateSize(true); + } + }, 100); + setTimeout(() => { + if (mapRef.current) { + mapRef.current.invalidateSize(true); + } + }, 500); + }; + + return ( +
+ {/* Leaflet MapContainer with no visible marker, just a center pin overlay */} + { + if (mapInstance) { + mapRef.current = mapInstance; + mapInstance.on('moveend', handleMapMoveEnd); + handleMapReady(); + } + }} + zoomControl={false} + attributionControl={false} + > + + + + {/* Center Pin Overlay with Popup - Figma Design */} +
+
+
+ Move the map to position the pin +
+
+
+ ); +}; + +export default LocationPinMap; \ No newline at end of file diff --git a/frontend/mobile-ui/src/app/features/Agent/components/Pagination.tsx b/frontend/mobile-ui/src/app/features/Agent/components/Pagination.tsx new file mode 100644 index 0000000..e312d17 --- /dev/null +++ b/frontend/mobile-ui/src/app/features/Agent/components/Pagination.tsx @@ -0,0 +1,64 @@ +// Pagination component displays page navigation controls for lists with multiple pages. +// Used in Agent screens to navigate between paginated data sets. +import React from "react"; +import "../../../../styles/Pagination.css"; + +// Props for Pagination: +// - page: current page number +// - totalPages: total number of pages +// - onPageChange: callback for changing page +interface PaginationProps { + page: number; + totalPages: number; + onPageChange: (page: number) => void; +} + +const Pagination: React.FC = ({ page, totalPages, onPageChange }) => { + // Only show pagination controls if there are at least 2 pages + if (totalPages < 2) return null; + + return ( +
+ {/* Left Arrow: go to previous page, disabled on first page */} + + {/* Current page indicator */} + + {/* Next page button, shown if not on last page */} + {page < totalPages && ( + + )} + + {/* Ellipsis and last page button, shown if more than one page ahead */} + {page < totalPages - 1 && ( + <> + ... + + + )} + + {/* Right Arrow: go to next page, disabled on last page */} + +
+ ); +}; + +// Export Pagination for use in Agent screens +export default Pagination; \ No newline at end of file diff --git a/frontend/mobile-ui/src/app/features/Agent/components/SearchPropertyResultCard.tsx b/frontend/mobile-ui/src/app/features/Agent/components/SearchPropertyResultCard.tsx new file mode 100644 index 0000000..2f7c359 --- /dev/null +++ b/frontend/mobile-ui/src/app/features/Agent/components/SearchPropertyResultCard.tsx @@ -0,0 +1,174 @@ +// SearchPropertyResultCard displays a property search result with status, address, and location map. +// Used in Agent screens to show property details and allow viewing location on a map. +import React from 'react'; +import { Box, Chip, Typography, Button } from '@mui/material'; +import OpenInNewOutlinedIcon from '@mui/icons-material/OpenInNewOutlined'; +import { MapContainer, TileLayer, Marker } from 'react-leaflet'; +import L from 'leaflet'; + +// Custom SVG icon for map marker (room icon) +const roomIconSvgString = ``; +const markerIcon = L.divIcon({ + html: roomIconSvgString, + className: '', + iconSize: [18, 18], + iconAnchor: [9, 18], +}); + +// Props for SearchPropertyResultCard: +// - id: property ID +// - address: property address +// - isVerified: property verification status +// - highlight: optional highlight flag +// - onViewLocation: callback for location view button +export interface SearchPropertyResultCardProps { + id: string; + address: string; + isVerified: boolean; + highlight?: boolean; + latlng: { lat: number; lng: number }; + onViewLocation?: () => void; +} + +// Helper to get status label and colors based on verification +const getStatusProps = (isVerified: boolean) => { + if (isVerified) { + return { + label: 'Verified', + color: '#00703C', + bg: '#F5F5F5', + }; + } + return { + label: 'Pending', + color: '#A59400', + bg: '#FBEEE8', + }; +}; + +const SearchPropertyResultCard: React.FC = ({ + id, + address, + isVerified, + latlng, + onViewLocation, +}) => { + // Get status label and colors + const status = getStatusProps(isVerified); + + return ( + + {/* Left section: status, ID, address */} + + + + {id} + + + Address + + + {address} + + + {/* Map and view location button */} + + + + + + + + {/* Button to view location in detail */} + + + + ); +}; + +// Export SearchPropertyResultCard for use in Agent screens +export default SearchPropertyResultCard; diff --git a/frontend/mobile-ui/src/app/features/Agent/components/StepHeader.tsx b/frontend/mobile-ui/src/app/features/Agent/components/StepHeader.tsx new file mode 100644 index 0000000..21cd231 --- /dev/null +++ b/frontend/mobile-ui/src/app/features/Agent/components/StepHeader.tsx @@ -0,0 +1,73 @@ +// StepHeader displays a multi-step header with title, subtitle, step progress, and navigation buttons. +// Used in Agent property workflows to show progress and provide navigation actions. +import React from 'react'; +import ArrowBackIosNewIcon from '@mui/icons-material/ArrowBackIosNew'; +import '../../../../styles/Agent/StepHeader.css'; +import SaveOutlinedIcon from '@mui/icons-material/SaveOutlined'; + +// Props for StepHeader: +// - title: main header title +// - subtitle: subheader text +// - steps: total number of steps (default 6) +// - activeStep: current active step (default 0) +// - onPrevious: callback for previous button +// - previousText: label for previous button +// - onSaveDraft: callback for save draft button +// - saveDraftText: label for save draft button +export interface StepHeaderProps { + title: string; + subtitle: string; + steps?: number; + activeStep?: number; + onPrevious?: () => void; + previousText?: string; + onSaveDraft?: () => void; + saveDraftText?: string; +} + +const StepHeader: React.FC = ({ + title, + subtitle, + steps = 6, + activeStep = 0, + onPrevious, + previousText = "Previous", + onSaveDraft, + saveDraftText = "Save Draft", +}) => { + // Render step header with title, subtitle, step progress, and navigation buttons + return ( +
+ {/* Main header section */} +
+
+

{title}

+
{subtitle}
+
+
+ {/* Step progress indicator */} +
+ {[...Array(steps)].map((_, i) => ( +
+ ))} +
+ {/* Navigation buttons: Previous and Save Draft */} +
+ + +
+
+ ); +}; + +// Export StepHeader for use in Agent screens +export default StepHeader; \ No newline at end of file diff --git a/frontend/mobile-ui/src/app/features/Agent/models/HomePageData.model.ts b/frontend/mobile-ui/src/app/features/Agent/models/HomePageData.model.ts new file mode 100644 index 0000000..7949438 --- /dev/null +++ b/frontend/mobile-ui/src/app/features/Agent/models/HomePageData.model.ts @@ -0,0 +1,229 @@ +// This file defines TypeScript interfaces for Agent home page data models. +// Used for typing API responses, property details, and related entities. +//import type { GISDataResponse } from "../../../../redux/apis/gisApi"; + +export interface Amenity { + ID: string; + Type: string; + Description: string; + ExpiryDate: string; + PropertyID: string; + CreatedAt: string; + UpdatedAt: string; +} + +// Details for each floor in a property +export interface FloorDetail { + ID: string; + FloorNo: number; + Classification: string; + NatureOfUsage: string; + FirmName: string; + OccupancyType: string; + OccupancyName: string; + constructionDate: string; + effectiveFromDate: string; + UnstructuredLand: string; + LengthFt: number; + BreadthFt: number; + PlinthAreaSqFt: number; + BuildingPermissionNo: string; + FloorDetailsEntered: boolean; + ConstructionDetailsID: string; + CreatedAt: string; + UpdatedAt: string; +} + +// Construction details for a property, including all floors +export interface ConstructionDetails { + ID: string; + FloorType: string; + WallType: string; + RoofType: string; + WoodType: string; + PropertyID: string; + FloorDetails: FloorDetail[]; + CreatedAt: string; + UpdatedAt: string; +} + +// GIS coordinate for mapping property location +export interface GISCoordinate { + ID: string; + Latitude: number; + Longitude: number; + GISDataID: string; + CreatedAt: string; +} + +// GIS data for a property, including coordinates +export interface GISData { + ID: string; + Source: string; + Type: string; + EntityType: string; + PropertyID: string; + Coordinates: GISCoordinate[]; + CreatedAt: string; + UpdatedAt: string; +} + +// Document metadata for property files +export interface Document { + ID: string; + PropertyID: string; + DocumentType: string; + DocumentName: string; + FileStoreID: string | null; + UploadDate: string; +} + +// Suggestion for Address interface +// Address details for a property +export interface Address { + ID: string; + Locality: string; + ZoneNo: string; + WardNo: string; + BlockNo: string; + Street: string; + ElectionWard: string; + SecretariatWard: string; + PinCode: number; + DifferentCorrespondenceAddress: boolean; + PropertyID: string; + CreatedAt: string; + UpdatedAt: string; +} + +// Assessment details for a property +export interface AssessmentDetails { + ID: string; + PropertyID: string; + ExtendOfSite: string; + IsLandUnderneathBuilding: boolean; + IsUnspecifiedShare: boolean; + OccupancyCertificateDate: string; + OccupancyCertificateNumber: string; + ReasonOfCreation: string; + CreatedAt: string; + UpdatedAt: string; +} + +// Additional details for a property, including amenities and certifications +export interface AdditionalDetails { + ID: string; + FieldName: string; + fieldValue: { + amenities: string[]; + certification: { + earthquake_resistant: boolean; + fire_safety: string; + green_building: boolean; + }; + construction_year: number; + elevator: boolean; + floors: number; + security: { + access_control: string; + cctv: boolean; + guard: string; + }; + units_per_floor: number; + }; + PropertyID: string; + CreatedAt: string; + UpdatedAt: string; +} + +// Application data for property workflows +export interface Application { + ID: string; + ApplicationNo: string; + PropertyID: string; + Priority: string; + TenantID: string; + DueDate: string; + AssignedAgent: string; + Status: string; + WorkflowInstanceID: string; + AppliedBy: string; + AssesseeID: string; + Property: PropertyDetails; + ApplicationLogs: any | null; + IsDraft: boolean; + CreatedAt: string; + UpdatedAt: string; +} + +// IGRS details for property registration +export interface IGRS { + id: string; + habitation: string; + igrsWard: string; + igrsLocality: string; + igrsBlock: string; + doorNoFrom: string; + doorNoTo: string; + igrsClassification: string; + builtUpAreaPct: number; + frontSetback: number; + rearSetback: number; + sideSetback: number; + totalPlinthArea: number; + createdAt: string; + updatedAt: string; + PropertyID: string; +} + +// Main property details object, includes all related entities +export interface PropertyDetails { + ID: string; + PropertyNo: string; + OwnershipType: string; + PropertyType: string; + ComplexName: string; + Address: Address | null; + AssessmentDetails: AssessmentDetails | null; + Amenities: Amenity | null; + ConstructionDetails: ConstructionDetails | null; + AdditionalDetails: AdditionalDetails | null; + GISData:{ + ID: string; + Source: string; + Type: string; + EntityType: string; + PropertyID: string; + Latitude: number; + Longitude: number; + Coordinates: Array<{ + ID: string; + Latitude: number; + Longitude: number; + GISDataID: string; + CreatedAt: string; + }>; + CreatedAt: string; + UpdatedAt: string; + } | null; + CreatedAt: string; + UpdatedAt: string; + Documents: Document[]; + IGRS: IGRS | null; +} + +// Pagination info for paginated API responses +export interface PaginationInfo { + page: number; + size: number; + totalItems: number; + totalPages: number; +} + +// API response for Agent home page property list +export interface HomePageResponse { + data: Application[]; + message: string; + pagination: PaginationInfo; + success: boolean; +} diff --git a/frontend/mobile-ui/src/app/features/Agent/models/PropertyInfoSubmittedData.model.ts b/frontend/mobile-ui/src/app/features/Agent/models/PropertyInfoSubmittedData.model.ts new file mode 100644 index 0000000..a09c187 --- /dev/null +++ b/frontend/mobile-ui/src/app/features/Agent/models/PropertyInfoSubmittedData.model.ts @@ -0,0 +1,49 @@ +// This file defines TypeScript interfaces for submitted property info data in Agent workflows. +// Used for typing form submissions, property details, usage, assessment, and documents. +import type { Owner } from "../../Citizen/models/Owner.model"; + +// Main data structure for submitted property info +export interface PropertyInfoSubmittedData { + propertyId: string; + owner: Owner; + propertyDetails: PropertyDetails; + usageDetails: UsageDetails; + assessmentDetails: AssessmentDetails; + documents: Document[]; +} + +// Basic property details (type, location, area) +export interface PropertyDetails { + propertyType: string; + zoneWard: string; + doorNo: string; + plotArea: string; +} + +// Usage details for property (survey, GIS, cadastral info) +export interface UsageDetails { + surveyNumber: string; + gisDelination: string; + gisReference: string; + cadastralMap: string; + gisRegistration: string; +} + +// Assessment details for property (construction, usage, tax zone) +export interface AssessmentDetails { + constructionYear: number; + buildingUsage: string; + builtUpArea: string; + floorCount: number; + propertyTaxZone: string; + assessmentStatus: string; + notes: string; +} + +// Document metadata for submitted files +export interface Document { + id: string; + name: string; + type: string; + url?: string; +} \ No newline at end of file diff --git a/frontend/mobile-ui/src/app/features/Agent/models/ReviewPage.model.ts b/frontend/mobile-ui/src/app/features/Agent/models/ReviewPage.model.ts new file mode 100644 index 0000000..20dc576 --- /dev/null +++ b/frontend/mobile-ui/src/app/features/Agent/models/ReviewPage.model.ts @@ -0,0 +1,58 @@ +// This file defines TypeScript interfaces for Agent review page data models. +// Used for typing API responses, property details, and application items for review workflows. +import type {Address, AssessmentDetails, ConstructionDetails, GISData, Amenity, Document, AdditionalDetails} from "./HomePageData.model"; + +// Property details for review page, includes all related entities +export interface PropertyDetails { + ID: string; + PropertyNo: string; + OwnershipType: string; + PropertyType: string; + ComplexName: string; + Address: Address; + AssessmentDetails: AssessmentDetails; + Amenities: Amenity[]; + ConstructionDetails: ConstructionDetails; + AdditionalDetails: AdditionalDetails; + GISData: GISData; + CreatedAt: string; + UpdatedAt: string; + Documents: Document; + IGRS: any; +} + +// Application item for review workflows +export interface ApplicationItem { + ID: string; + ApplicationNo: string; + PropertyID: string; + Priority: string; + TenantID: string; + DueDate: string; + AssignedAgent: string; + Status: string; + WorkflowInstanceID: string; + AppliedBy: string; + AssesseeID: string; + Property: PropertyDetails; + ApplicationLogs: any; + IsDraft: boolean; + CreatedAt: string; + UpdatedAt: string; +} + +// Pagination info for paginated API responses +export interface PaginationInfo { + page: number; + size: number; + totalItems: number; + totalPages: number; +} + +// API response for Agent review page property list +export interface ApplicationsResponse { + data: ApplicationItem[]; + message: string; + pagination: PaginationInfo; + success: boolean; +} \ No newline at end of file diff --git a/frontend/mobile-ui/src/app/features/Agent/models/ReviewedPropertyData.model.ts b/frontend/mobile-ui/src/app/features/Agent/models/ReviewedPropertyData.model.ts new file mode 100644 index 0000000..01da7b0 --- /dev/null +++ b/frontend/mobile-ui/src/app/features/Agent/models/ReviewedPropertyData.model.ts @@ -0,0 +1,8 @@ +// This file defines TypeScript interfaces for reviewed property data in Agent workflows. +// Used for typing lists of properties that have been reviewed by the agent. +import type { Property } from "../../../../models/Citizen/Property"; + +// Main data structure for reviewed properties +export interface ReviewedPropertyData { + reviewedProperties: Property[]; +} \ No newline at end of file diff --git a/frontend/mobile-ui/src/app/features/Agent/models/SearchPropertyData.model.ts b/frontend/mobile-ui/src/app/features/Agent/models/SearchPropertyData.model.ts new file mode 100644 index 0000000..3d68a5c --- /dev/null +++ b/frontend/mobile-ui/src/app/features/Agent/models/SearchPropertyData.model.ts @@ -0,0 +1,121 @@ +// Represents the address details of a property +export interface Address { + ID: string; // Unique identifier for the address + Locality: string; // Locality or neighborhood + ZoneNo: string; // Zone number + WardNo: string; // Ward number + BlockNo: string; // Block number + Street: string; // Street name + ElectionWard: string; // Election ward + SecretariatWard: string; // Secretariat ward + PinCode: number; // Postal code + DifferentCorrespondenceAddress: boolean; // If correspondence address is different + PropertyID: string; // Linked property ID + CreatedAt: string; // Creation timestamp + UpdatedAt: string; // Last update timestamp + correspondenceAddress1: string; // Correspondence address line 1 + correspondenceAddress2: string; // Correspondence address line 2 + correspondenceAddress3: string; // Correspondence address line 3 +} + +// Details related to property assessment +export interface AssessmentDetails { + ID: string; // Unique identifier + ReasonOfCreation: string; // Reason for assessment creation + OccupancyCertificateNumber: string; // Occupancy certificate number + OccupancyCertificateDate: string; // Date of occupancy certificate + ExtentOfSite: string; // Site area/extent + IsLandUnderneathBuilding: string; // Whether land is underneath building + IsUnspecifiedShare: boolean; // If property has unspecified share + PropertyID: string; // Linked property ID + CreatedAt: string; // Creation timestamp + UpdatedAt: string; // Last update timestamp +} + +// Construction-related details of the property +export interface ConstructionDetails { + ID: string; // Unique identifier + FloorType: string; // Type of floor + WallType: string; // Type of wall + RoofType: string; // Type of roof + WoodType: string; // Type of wood used + PropertyID: string; // Linked property ID + FloorDetails: any; // Details about each floor (structure may vary) + CreatedAt: string; // Creation timestamp + UpdatedAt: string; // Last update timestamp +} + +// Any additional custom details for the property +export interface AdditionalDetails { + ID: string; // Unique identifier + FieldName: string; // Name of the additional field + fieldValue: any; // Value of the field + PropertyID: string; // Linked property ID + CreatedAt: string; // Creation timestamp + UpdatedAt: string; // Last update timestamp +} + +// Main property data model +export interface PropertyData { + ID: string; // Unique property identifier + PropertyNo: string; // Property number + OwnershipType: string; // Type of ownership + PropertyType: string; // Type/category of property + ComplexName: string; // Name of the complex (if any) + Address: Address; // Address details + AssessmentDetails: AssessmentDetails | null; // Assessment details + Amenities: any; // Amenities available (structure may vary) + ConstructionDetails: ConstructionDetails | null; // Construction details + AdditionalDetails: AdditionalDetails | null; // Additional custom details + GISData: any; // Geographic Information System data + CreatedAt: string; // Creation timestamp + UpdatedAt: string; // Last update timestamp + Documents: any; // Related documents + IGRS: any; // Integrated Grievance Redressal System or similar +} + +// Represents an application related to a property (e.g., assessment, mutation) +export interface ApplicationData { + ID: string; // Unique application identifier + ApplicationNo: string; // Application number + PropertyID: string; // Linked property ID + Priority: string; // Priority of the application + TenantID: string; // Tenant or jurisdiction ID + DueDate: string; // Due date for processing + AssignedAgent: string; // Agent assigned to the application + Status: string; // Current status + WorkflowInstanceID: string; // Workflow instance identifier + AppliedBy: string; // User who applied + AssesseeID: string; // Assessee (taxpayer) ID + Property: PropertyData; // Property details + ApplicationLogs: any; // Logs related to the application + IsDraft: boolean; // Whether the application is a draft + CreatedAt: string; // Creation timestamp + UpdatedAt: string; // Last update timestamp +} + +// Pagination information for paginated responses +export interface Pagination { + page: number; // Current page number + size: number; // Number of items per page + totalItems: number; // Total number of items + totalPages: number; // Total number of pages +} + +// Response structure for property search API +export interface SearchPropertyResponse { + data: ApplicationData[]; // List of application data + message: string; // Response message + pagination: Pagination; // Pagination info + success: boolean; // Success status +} + +// Parameters for searching properties +export interface SearchPropertyParams { + zoneNo?: string; // Filter by zone number + wardNo?: string; // Filter by ward number + page?: number; // Page number for pagination + size?: number; // Page size for pagination + sortBy?: string; // Field to sort by + sortOrder?: 'asc' | 'desc'; // Sort order +} \ No newline at end of file diff --git a/frontend/mobile-ui/src/app/features/Agent/utils/propertyMapper.ts b/frontend/mobile-ui/src/app/features/Agent/utils/propertyMapper.ts new file mode 100644 index 0000000..fc5d83c --- /dev/null +++ b/frontend/mobile-ui/src/app/features/Agent/utils/propertyMapper.ts @@ -0,0 +1,37 @@ +// Utility to map Application model to PropertyItem type for Agent screens. +// Used to transform API data into frontend-friendly format for property lists. +import type { Application } from '../models/HomePageData.model'; +import type { PropertyItem } from '../../../../types'; + +// Maps an Application object to a PropertyItem for display in property lists. +export const mapApplicationToPropertyItem = (application: Application): PropertyItem => { + const property = application.Property; + + + // Return mapped property item with normalized fields + return { + id: application.ID, + pId: application.ApplicationNo, + propertyNo: property.PropertyNo || 'N/A', + type: property.PropertyType || 'RESIDENTIAL', + description: `${property.PropertyType} - ${property.OwnershipType}`, + address: property.Address + ? `${property.Address.Street}, ${property.Address.Locality}` + : 'Address not available', + phoneNumber: '', // Not available in Application/Property data + area: property.AssessmentDetails?.ExtendOfSite || 'N/A', + propertyType: property.PropertyType || 'RESIDENTIAL', + status: application.Priority || 'MEDIUM', + dueDate: application.DueDate || new Date().toISOString(), + // isNew: application.Status === 'ASSIGNED', + isNew: (application.Status === 'ASSIGNED'), + isDraft: application.IsDraft === true, + isVerified: application.Status === 'VERIFIED' || application.Status === 'APPROVED' || application.Status === 'AUDIT_VERIFIED', + createdDate: application.CreatedAt, + gisData: property.GISData ? { + latitude: property.GISData.Latitude, + longitude: property.GISData.Longitude, + coordinates: property.GISData.Coordinates + } : undefined, + }; +}; \ No newline at end of file diff --git a/frontend/mobile-ui/src/app/features/Citizen/api/Citizen.api.ts b/frontend/mobile-ui/src/app/features/Citizen/api/Citizen.api.ts new file mode 100644 index 0000000..688496a --- /dev/null +++ b/frontend/mobile-ui/src/app/features/Citizen/api/Citizen.api.ts @@ -0,0 +1,63 @@ +// import { createApi } from '@reduxjs/toolkit/query/react'; +// import type { CitizenHomeData } from '../models/CitizenHome.model'; +// import type { Property } from '../models/Property.model'; +// import type { UrgentAttention } from '../models/UrgentAttention.model'; +// import customBaseQuery from '../../../service/BaseQuery.api'; + +// export const citizenApi = createApi({ +// reducerPath: 'citizenApi', +// baseQuery: customBaseQuery, +// tagTypes: ['Properties', 'CitizenHome'], +// endpoints: (builder) => ({ +// getCitizenHome: builder.query({ +// query: () => `/api/v1/citizen/home`, +// transformResponse: (response: any) => { +// const homeJson = response?.home ?? {}; + +// const user = homeJson.user ?? {}; +// const activeLicenses = user.activeLicenses ?? 0; +// const numberOfProperties = user.numberOfProperties ?? 0; + +// const properties: Property[] = (homeJson.properties ?? []).map((prop: any) => ({ +// id: prop.id, +// apartmentName: prop.apartmentName ?? '', +// address: (prop.address as any) ?? '', +// enumerationProgress: prop.enumerationProgress ?? 0, +// locationData: prop.locationData ?? { address: '', coordinates: { lat: 0, lng: 0 }, timestamp: '' }, +// })); + +// const urgentAttention: UrgentAttention[] = (homeJson.urgentAttention ?? []).map((item: any) => ({ +// id: item.id, +// type: item.type, +// message: item.message, +// date: item.date, +// status: item.status, +// })); + +// return { activeLicenses, numberOfProperties, properties, urgentAttention }; +// }, +// providesTags: ['CitizenHome'], +// }), + +// getProperties: builder.query({ +// query: () => `/api/v1/citizen/properties`, +// transformResponse: (response: any) => { +// if (response == null) return []; +// if (response && 'properties' in response) { +// return response.properties as Property[]; +// } else { +// return response as Property[]; +// } +// }, +// providesTags: (result) => +// result +// ? [ +// ...result.map(({ id }) => ({ type: 'Properties' as const, id })), +// { type: 'Properties', id: 'LIST' }, +// ] +// : [{ type: 'Properties', id: 'LIST' }], +// }), +// }), +// }); + +// export const { useGetCitizenHomeQuery, useGetPropertiesQuery } = citizenApi; \ No newline at end of file diff --git a/frontend/mobile-ui/src/app/features/Citizen/api/CitizenDocumentPageApi/fileStoreApi.ts b/frontend/mobile-ui/src/app/features/Citizen/api/CitizenDocumentPageApi/fileStoreApi.ts new file mode 100644 index 0000000..c03c140 --- /dev/null +++ b/frontend/mobile-ui/src/app/features/Citizen/api/CitizenDocumentPageApi/fileStoreApi.ts @@ -0,0 +1,52 @@ +// fileStoreApi defines API endpoints for file upload and retrieval for Citizen document workflows. +// Uses Redux Toolkit Query to provide hooks for file blob fetching and uploading to filestore. +import { filestoreApiSlice } from '../../../../../redux/fileStoreApiSlice'; +import type { UploadResult } from '../../models/CitizenDocumentPageModel/fileStoreModel'; + +// Response type for file URL lookup +export interface FileUrlResponse { + url: string; + fileStoreId: string; +} + +// Inject endpoints for file blob retrieval and file upload +export const filestoreApi = filestoreApiSlice.injectEndpoints({ + endpoints: (builder) => ({ + // Fetch file directly as blob (not URL) + getFileBlob: builder.query( + { + query: ({ fileStoreId, tenantId = "pg" }) => ({ + url: `/filestore/v1/files/${fileStoreId}?tenantId=${tenantId}`, + method: 'GET', + responseHandler: (response) => response.blob(), // Get blob directly + }), + } + ), + + // Upload file to filestore using multipart/form-data + uploadFileToFilestore: builder.mutation( + { + query: ({ file, tenantId = "pg", module = "HCM-ADMIN-CONSOLE-CLIENT", tag = "test" }) => { + const formData = new FormData(); + formData.append('file', file); + formData.append('tenantId', tenantId); + formData.append('module', module); + formData.append('tag', tag); + + return { + url: '/filestore/v1/files', + method: 'POST', + body: formData, + }; + }, + } + ), + }), +}); + +// Export RTK Query hooks for file blob and upload operations +export const { + useGetFileBlobQuery, + useLazyGetFileBlobQuery, + useUploadFileToFilestoreMutation, +} = filestoreApi; \ No newline at end of file diff --git a/frontend/mobile-ui/src/app/features/Citizen/api/CitizenHomePageApi/CitizenHomePageApi.ts b/frontend/mobile-ui/src/app/features/Citizen/api/CitizenHomePageApi/CitizenHomePageApi.ts new file mode 100644 index 0000000..bde6020 --- /dev/null +++ b/frontend/mobile-ui/src/app/features/Citizen/api/CitizenHomePageApi/CitizenHomePageApi.ts @@ -0,0 +1,28 @@ +// CitizenHomePageApi defines API endpoints for fetching property applications for the Citizen homepage. +// Uses Redux Toolkit Query to provide hooks for searching applications by assesseeId and draft status. +import { apiSlice } from '../../../../../redux/apiSlice'; +import type { CitizenApplicationSearchResponse } from './CitizenHomePageModel'; + +// Inject endpoint for searching citizen applications (homepage) +export const citizenHomepageApi = apiSlice.injectEndpoints({ + endpoints: (builder) => ({ + // Fetch applications for 'homepage' by assesseeId & isDraft + getCitizenApplications: builder.query< + CitizenApplicationSearchResponse, + { assesseeId: string; isDraft?: boolean } + >({ + query: ({ assesseeId, isDraft=true }) => ({ + url: `/v1/applications/search`, + params: { + assesseeId, + isDraft, + }, + method: 'GET', + }), + }), + }), +}); + +// Export RTK Query hook for fetching citizen applications +export const { useGetCitizenApplicationsQuery } = citizenHomepageApi; +export default citizenHomepageApi; diff --git a/frontend/mobile-ui/src/app/features/Citizen/api/CitizenHomePageApi/CitizenHomePageModel.ts b/frontend/mobile-ui/src/app/features/Citizen/api/CitizenHomePageApi/CitizenHomePageModel.ts new file mode 100644 index 0000000..d5ad4f8 --- /dev/null +++ b/frontend/mobile-ui/src/app/features/Citizen/api/CitizenHomePageApi/CitizenHomePageModel.ts @@ -0,0 +1,86 @@ +// Model definitions for Citizen homepage application search API response. +// Each interface represents a part of the response structure for property applications. +// Used by CitizenHomePageApi to type API data and enable type-safe access in components. +// +// Top-level response from /v1/applications/search?assesseeId=...&isDraft=... +export interface CitizenApplicationSearchResponse { + data: CitizenApplicationSummary[]; + message: string; + pagination: { + page: number; + size: number; + totalItems: number; + totalPages: number; + }; + success: boolean; +} + +// Application summary for each property application returned in the data array +export interface CitizenApplicationSummary { + ID: string; + ApplicationNo: string; + PropertyID: string; + Priority: string; + TenantID: string; + DueDate: string; + AssignedAgent: string; + Status: string; + WorkflowInstanceID: string; + AppliedBy: string; + AssesseeID: string; + Property: CitizenPropertySummary; + ApplicationLogs: any; + IsDraft: boolean; + CreatedAt: string; + UpdatedAt: string; +} + +// Property details nested within each application summary +export interface CitizenPropertySummary { + ID: string; + PropertyNo: string; + OwnershipType: string; + PropertyType: string; + ComplexName: string; + Address: CitizenPropertyAddress; + AssessmentDetails: any; + Amenities: any[]; + ConstructionDetails: any; + AdditionalDetails: any; + GISData: any; + CreatedAt: string; + UpdatedAt: string; + Documents: CitizenPropertyDocument[]; + IGRS: any; + __appId: string; +} + +// Address details for a property, nested within CitizenPropertySummary +export interface CitizenPropertyAddress { + ID: string; + Locality: string; + ZoneNo: string; + WardNo: string; + BlockNo: string; + Street: string; + ElectionWard: string; + SecretariatWard: string; + PinCode: number; + DifferentCorrespondenceAddress: boolean; + PropertyID: string; + CreatedAt: string; + UpdatedAt: string; +} + +// Document metadata for property documents, used in CitizenPropertySummary.Documents +export interface CitizenPropertyDocument { + ID: string; + PropertyID: string; + DocumentType: string; + DocumentName: string; + FileStoreID: string; + UploadDate: string; + action: string; + uploadedBy: string; + size: string; +} \ No newline at end of file diff --git a/frontend/mobile-ui/src/app/features/Citizen/api/CitizenPropertiesPageApi/CitizenPropertiesPageApi.ts b/frontend/mobile-ui/src/app/features/Citizen/api/CitizenPropertiesPageApi/CitizenPropertiesPageApi.ts new file mode 100644 index 0000000..1773f36 --- /dev/null +++ b/frontend/mobile-ui/src/app/features/Citizen/api/CitizenPropertiesPageApi/CitizenPropertiesPageApi.ts @@ -0,0 +1,28 @@ +// CitizenPropertiesPageApi defines API endpoints for fetching property applications for the Citizen properties page. +// Uses Redux Toolkit Query to provide hooks for searching applications by assesseeId and draft status. +import { apiSlice } from '../../../../../redux/apiSlice'; +import type { CitizenApplicationSearchResponse } from '../CitizenHomePageApi/CitizenHomePageModel'; + +// Inject endpoint for searching citizen properties (properties page) +export const citizenPropertiesPageApi = apiSlice.injectEndpoints({ + endpoints: (builder) => ({ + // Fetch applications for 'homepage' by assesseeId & isDraft + getCitizenProperties: builder.query< + CitizenApplicationSearchResponse, + { assesseeId: string; Status: string; isDraft: boolean } + >({ + query: ({ assesseeId, isDraft=true }) => ({ + url: `/v1/applications/search`, + params: { + assesseeId, + isDraft, + }, + method: 'GET', + }), + }), + }), +}); + +// Export RTK Query hook for fetching citizen properties +export const { useGetCitizenPropertiesQuery } = citizenPropertiesPageApi; +export default citizenPropertiesPageApi; \ No newline at end of file diff --git a/frontend/mobile-ui/src/app/features/Citizen/api/CitizenPropertiesPageApi/CitizenPropertyPageApi.ts b/frontend/mobile-ui/src/app/features/Citizen/api/CitizenPropertiesPageApi/CitizenPropertyPageApi.ts new file mode 100644 index 0000000..2db6faa --- /dev/null +++ b/frontend/mobile-ui/src/app/features/Citizen/api/CitizenPropertiesPageApi/CitizenPropertyPageApi.ts @@ -0,0 +1,24 @@ +// CitizenPropertyPageApi defines API endpoints for fetching a single property by propertyId for the Citizen property details page. +// Uses Redux Toolkit Query to provide hooks for retrieving property details. +import { apiSlice } from '../../../../../redux/apiSlice'; +import type { CitizenPropertyResponse } from '../../models/CitizenPropertiesPageModel/CitizenPropertyPageModel'; + +// Inject endpoint for fetching a single citizen property by ID +export const citizenPropertyPageApi = apiSlice.injectEndpoints({ + endpoints: (builder) => ({ + // Fetch single property by propertyId + getCitizenPropertyById: builder.query< + CitizenPropertyResponse, + { propertyId: string } + >({ + query: ({ propertyId }) => ({ + url: `/v1/properties/${propertyId}`, + method: 'GET', + }), + }), + }), +}); + +// Export RTK Query hook for fetching a single citizen property by ID +export const { useGetCitizenPropertyByIdQuery } = citizenPropertyPageApi; +export default citizenPropertyPageApi; \ No newline at end of file diff --git a/frontend/mobile-ui/src/app/features/Citizen/api/Property.slice.ts b/frontend/mobile-ui/src/app/features/Citizen/api/Property.slice.ts new file mode 100644 index 0000000..4bd82a4 --- /dev/null +++ b/frontend/mobile-ui/src/app/features/Citizen/api/Property.slice.ts @@ -0,0 +1,26 @@ +// import { createSlice, type PayloadAction } from '@reduxjs/toolkit'; +// import type { Property } from '../models/Property.model'; +// import type { PropertyState } from '../models/PropertyState.model'; + +// const initialState: PropertyState = { +// selectedProperty: null, +// }; + +// const propertySlice = createSlice({ +// name: 'property', +// initialState, +// reducers: { +// setSelectedProperty(state, action: PayloadAction) { +// state.selectedProperty = action.payload; +// }, +// clearSelectedProperty(state) { +// state.selectedProperty = null; +// }, +// }, +// }); + +// export const { setSelectedProperty, clearSelectedProperty } = propertySlice.actions; +// export default propertySlice.reducer; + + +/// \ No newline at end of file diff --git a/frontend/mobile-ui/src/app/features/Citizen/components/ChromeTabs.tsx b/frontend/mobile-ui/src/app/features/Citizen/components/ChromeTabs.tsx new file mode 100644 index 0000000..e159a61 --- /dev/null +++ b/frontend/mobile-ui/src/app/features/Citizen/components/ChromeTabs.tsx @@ -0,0 +1,128 @@ +// ChromeTabs.tsx displays a tab switcher UI for toggling between Map and List views on the Citizen homepage. +// It uses MUI for UI, localization for tab labels, and styled Button for custom tab appearance. +// Main responsibilities: +// - Render two tabs (Map, List) with dynamic selection +// - Pass selected tab index and change handler via props +// - Use localization for tab labels +// Props: +// selected (number): index of selected tab +// onTabChange (function): callback for tab change +// height, customWidth, selectedColor (optional): style overrides +import React from 'react'; +import { Box, Button, styled } from '@mui/material'; +import { useAppSelector } from '../../../../redux/Hooks'; +import { getMessagesFromSession, useLocalization } from '../../../../services/Citizen/Localization/LocalizationContext'; +import LoadingPage from '../../../components/Loader'; +// Props for ChromeTabs: selected tab index, change handler, style overrides +interface ChromeTabsProps { + selected: number; + onTabChange: (idx: number) => void; + selectedColor?: string; + height?: number; + customWidth?: string | number; +} + +const SELECTED_BG = "#DFDFDF"; +const UNSELECTED_BG = "#fff"; +const SELECTED_COLOR = "#222"; +const UNSELECTED_COLOR = "#222"; +const BORDER_COLOR = "#222"; + +// ChromeTabs component: renders two tabs (Map, List) with selection and localization +const ChromeTabs: React.FC = ({ + selected, + onTabChange, + height = 56, + customWidth, +}) => { + const lang = useAppSelector(state => state.lang.citizenLang); // Current language + const { loading } = useLocalization(); // Global loading state + const messages = getMessagesFromSession("CITIZEN")!; // Localized messages + + // Show loader if localization is loading + if (loading) { + return ; + } + + // Render tab switcher UI + return ( + + onTabChange(0)} + > + {messages['citizen.home'][lang]?.['map-btn'] ?? "Map"} + + onTabChange(1)} + > + {messages['citizen.home'][lang]?.['list-btn'] ?? "List"} + + + ); +}; + +// TabButton: styled MUI Button for tab appearance and selection +const TabButton = styled(Button, { + shouldForwardProp: (prop) => ( + prop !== '$isSelected' && + prop !== '$height' && + prop !== '$selectedTab' && + prop !== '$borderRadius' + ) +})<{ + $isSelected: boolean; + $height: number; + $selectedTab: number; + $borderRadius: string; +}>( + ({ $isSelected, $height, $borderRadius, theme }) => ({ + flex: 1, // Each tab fills half the ChromeTabs container + height: $height, + padding: theme.spacing(0, 2), + fontWeight: 600, + borderRadius: $borderRadius, + fontSize: 18, + textTransform: 'none', + backgroundColor: $isSelected ? SELECTED_BG : UNSELECTED_BG, + color: $isSelected ? SELECTED_COLOR : UNSELECTED_COLOR, + border: 'none', + borderBottom: $isSelected ? `2px solid ${SELECTED_BG}` : `2px solid transparent`, + boxShadow: 'none', + margin: 0, + letterSpacing: '0.3px', + '&:hover': { + backgroundColor: $isSelected ? SELECTED_BG : "#F6F6F6" + }, + '&:focus-visible': { + outline: `2px solid ${SELECTED_BG}`, + outlineOffset: 2 + }, + '&:not(:first-of-type)': { + marginLeft: 0 + } + }) +); + +// Export ChromeTabs for use in Citizen homepage +export default ChromeTabs; \ No newline at end of file diff --git a/frontend/mobile-ui/src/app/features/Citizen/components/EnumOptComponent.tsx b/frontend/mobile-ui/src/app/features/Citizen/components/EnumOptComponent.tsx new file mode 100644 index 0000000..8ae40cd --- /dev/null +++ b/frontend/mobile-ui/src/app/features/Citizen/components/EnumOptComponent.tsx @@ -0,0 +1,108 @@ +// EnumOptComponent.tsx displays either enumerated info cards or a progress bar for property enumeration status. +// It uses MUI for UI, localization for labels, and shows last updated date. +// Main responsibilities: +// - Show EnumeratedInfo cards if progress is 100% +// - Otherwise, show progress bar and last updated info +// - Use localization for labels/messages +// Props: property (CitizenPropertyData) - the property whose enumeration status is shown +import type { FC } from 'react'; +import EnumeratedInfo from './EnumeratedInfo'; +import { Box, LinearProgress, Paper, Typography } from '@mui/material'; +import { useAppSelector } from '../../../../redux/Hooks'; +import { + getMessagesFromSession, + useLocalization, +} from '../../../../services/Citizen/Localization/LocalizationContext'; +import LoadingPage from '../../../components/Loader'; +import type { CitizenPropertyData } from '../models/CitizenPropertiesPageModel/CitizenPropertyPageModel'; + +interface ExtendedPropertyData extends CitizenPropertyData { + enumerationProgress?: number; + isDraft?: boolean; + applicationStatus?: string; +} + +interface EnumOptComponentProps { + property: ExtendedPropertyData; +} + +// EnumOptComponent: shows enumerated info or progress bar for property enumeration +const EnumOptComponent: FC = ({ property }) => { + // Localization, state, and hooks + const lang = useAppSelector((state) => state.lang.citizenLang); // Current language + const { loading } = useLocalization(); // Global loading state + const messages = getMessagesFromSession('CITIZEN')!; // Localized messages + + // No property: render nothing + if (!property) return null; + + // Get enumeration progress from property + // Default to 50 if not provided and not a draft + let progress = 50; + + if (property.enumerationProgress !== undefined) { + // If enumerationProgress is -1, it means draft, show 0% progress + if (property.enumerationProgress === -1) { + progress = 0; + } else { + console.log(property.enumerationProgress); + + progress = property.enumerationProgress; + } + } + + // Get last updated date from property + const lastUpdated = property.UpdatedAt + ? new Date(property.UpdatedAt).toLocaleDateString() + : ''; + + // Show loader if localization is loading + if (loading) { + return ; + } + + // Render enumerated info cards if progress is 100%, else show progress bar + return progress === 100 ? ( + { + /* handle view bills */ + }} + onViewLicenses={() => { + /* handle view licenses */ + }} + /> + ) : ( + + + {messages['citizen.my-properties'][lang]['enum-progress']} + + + + {progress}% + + {lastUpdated && ( + + {messages['citizen.commons'][lang]['last-updated']}: {lastUpdated} + + )} + + ); +}; + +// Export EnumOptComponent for use in Citizen property details +export default EnumOptComponent; diff --git a/frontend/mobile-ui/src/app/features/Citizen/components/EnumeratedInfo.tsx b/frontend/mobile-ui/src/app/features/Citizen/components/EnumeratedInfo.tsx new file mode 100644 index 0000000..5a6c216 --- /dev/null +++ b/frontend/mobile-ui/src/app/features/Citizen/components/EnumeratedInfo.tsx @@ -0,0 +1,139 @@ +// EnumeratedInfo.tsx displays summary cards for bills due and issued licenses on the Citizen dashboard. +// It uses MUI for UI, localization for labels, and provides buttons to view bills and licenses. +// Main responsibilities: +// - Render two cards: bills due and issued licenses +// - Show total amount and count +// - Provide buttons for navigation to bills/licenses +// Props: +// billsDue (number): count of bills due +// billsAmount (number): total amount due +// issuedLicenses (number): count of issued licenses +// onViewBills, onViewLicenses (function, optional): navigation handlers +import React from "react"; +import { Box, Button, Typography, Paper } from "@mui/material"; +import ArrowForwardIosIcon from "@mui/icons-material/ArrowForwardIos"; +import { useAppSelector } from "../../../../redux/Hooks"; +import { getMessagesFromSession, useLocalization } from "../../../../services/Citizen/Localization/LocalizationContext"; +import LoadingPage from "../../../components/Loader"; + + +// Props for EnumeratedInfo: bills/amount/licenses and navigation handlers +interface EnumeratedInfoProps { + billsDue: number; + billsAmount: number; + issuedLicenses: number; + onViewBills?: () => void; + onViewLicenses?: () => void; +} + +// EnumeratedInfo component: renders summary cards for bills and licenses +const EnumeratedInfo: React.FC = ({ + billsAmount, + issuedLicenses, + onViewBills, + onViewLicenses +}) => { + const lang = useAppSelector(state => state.lang.citizenLang); // Current language + const { loading } = useLocalization(); // Global loading state + const messages = getMessagesFromSession("CITIZEN")!; // Localized messages + + // Show loader if localization is loading + if (loading) { + return ; + } + + // Render summary cards for bills and licenses + return ( + + {/* Bills Card */} + + + {messages['citizen.my-properties'][lang]['bills-due']}: + + + {/* {messages['citizen.my-properties'][lang]['total-amount']}: */} + Total Amount : + + + โ‚น{billsAmount?.toLocaleString?.() || billsAmount} + + + + {/* Licenses Card */} + + + Issued Licenses: + + + {issuedLicenses} + + + + + ); +}; + +// Export EnumeratedInfo for use in Citizen dashboard +export default EnumeratedInfo; \ No newline at end of file diff --git a/frontend/mobile-ui/src/app/features/Citizen/components/ErrorMessage.tsx b/frontend/mobile-ui/src/app/features/Citizen/components/ErrorMessage.tsx new file mode 100644 index 0000000..edd0f03 --- /dev/null +++ b/frontend/mobile-ui/src/app/features/Citizen/components/ErrorMessage.tsx @@ -0,0 +1,63 @@ +// ErrorMessage.tsx displays a styled error message for the Citizen UI. +// It uses MUI for UI and shows an error icon, title, and message. +// Main responsibilities: +// - Render a centered error card with icon and message +// - Use Paper for card styling and Typography for text +// No props required; static error message +import {type FC} from "react"; +import { Box, Typography, Paper } from "@mui/material"; +import ErrorOutlineIcon from "@mui/icons-material/ErrorOutline"; + +// ErrorMessage component: renders a styled error card with icon and message +const ErrorMessage: FC = () => ( + + + {/* Error icon */} + + {/* Error title */} + + Error + + {/* Error message */} + + Something went wrong + + + +); + +// Export ErrorMessage for use in error boundaries and error states +export default ErrorMessage; \ No newline at end of file diff --git a/frontend/mobile-ui/src/app/features/Citizen/components/InfoCard.tsx b/frontend/mobile-ui/src/app/features/Citizen/components/InfoCard.tsx new file mode 100644 index 0000000..6cced97 --- /dev/null +++ b/frontend/mobile-ui/src/app/features/Citizen/components/InfoCard.tsx @@ -0,0 +1,34 @@ +// InfoCard.tsx displays a styled card with a title and count for summary info on the Citizen dashboard. +// It uses MUI for UI and is used for showing counts (e.g., bills, licenses, etc.). +// Main responsibilities: +// - Render a card with title and count +// - Style card for dashboard summary +// Props: +// title (string): label for the card +// count (number): value to display +import React from 'react'; +import { Typography, Paper } from '@mui/material'; + +// InfoCard component: renders a styled card with title and count +const InfoCard: React.FC<{ title: string; count: number }> = ({ title, count }) => ( + + {/* Card title */} + {title} + {/* Card count value */} + {count} + +); + +// Export InfoCard for use in dashboard summary sections +export default InfoCard; \ No newline at end of file diff --git a/frontend/mobile-ui/src/app/features/Citizen/components/MapComponent.tsx b/frontend/mobile-ui/src/app/features/Citizen/components/MapComponent.tsx new file mode 100644 index 0000000..4e7931a --- /dev/null +++ b/frontend/mobile-ui/src/app/features/Citizen/components/MapComponent.tsx @@ -0,0 +1,107 @@ +// MapComponent.tsx displays a Leaflet map centered on a given latitude/longitude with a marker. +// It uses react-leaflet for map rendering and supports custom tile URL and marker icon. +// Main responsibilities: +// - Render a map centered at lat/lng +// - Show a marker at the property location +// - Use custom tile URL and icon for map/marker +// Props: +// latLng: { lat, lng } - coordinates to center and mark +// tileUrl: string - URL for map tiles +// customIcon: L.Icon - Leaflet icon for marker +import { useEffect, useRef } from 'react'; +import type { FC } from 'react'; +import maplibregl from 'maplibre-gl'; +import 'maplibre-gl/dist/maplibre-gl.css'; + +type LatLng = { lat: number; lng: number }; +type CustomIconLike = { + iconUrl?: string; + iconSize?: [number, number]; + iconAnchor?: [number, number]; + popupAnchor?: [number, number]; + className?: string; +}; + +const MapComponent: FC<{ + latLng: LatLng; + tileUrl: string; // kept for compatibility with existing callers (tab toggle) + customIcon: CustomIconLike; +}> = ({ latLng, tileUrl, customIcon }) => { + const containerRef = useRef(null); + const mapRef = useRef(null); + const markerRef = useRef(null); + + useEffect(() => { + if (!containerRef.current) return; + + // cleanup previous map if any + if (mapRef.current) { + markerRef.current?.remove(); + mapRef.current.remove(); + mapRef.current = null; + markerRef.current = null; + } + + // Use the tileUrl passed from props as the style + mapRef.current = new maplibregl.Map({ + container: containerRef.current, + style: tileUrl, + center: [latLng.lng, latLng.lat], + zoom: 15, + attributionControl: false, + scrollZoom: false, + doubleClickZoom: false, + }); + + // create marker element using provided icon-like object (keeps visual same) + const el = document.createElement('div'); + el.style.display = 'inline-block'; + el.style.lineHeight = '0'; + el.style.pointerEvents = 'auto'; + + const img = document.createElement('img'); + img.src = customIcon?.iconUrl ?? ''; + if (customIcon?.iconSize) { + img.style.width = `${customIcon.iconSize[0]}px`; + img.style.height = `${customIcon.iconSize[1]}px`; + } else { + img.style.width = '40px'; + img.style.height = '40px'; + } + img.alt = 'marker'; + if (customIcon?.className) img.className = customIcon.className; + + el.appendChild(img); + + // position marker with anchor adjustments (maplibre Marker positions by element's top-left) + // we'll add margin to mimic iconAnchor behaviour if provided + if (customIcon?.iconAnchor) { + // convert anchor so element bottom center aligns to coordinates + const [ax, ay] = customIcon.iconAnchor; + // apply transform so coordinate aligns similarly to Leaflet anchor + el.style.transform = `translate(${ + -ax + (customIcon.iconSize ? customIcon.iconSize[0] / 2 : 20) + }px, ${-ay}px)`; + } else { + el.style.transform = 'translate(-20px, -40px)'; + } + mapRef.current.addControl(new maplibregl.NavigationControl(), 'top-right'); + markerRef.current = new maplibregl.Marker({ element: el, anchor: 'bottom' }) + .setLngLat([latLng.lng, latLng.lat]) + .addTo(mapRef.current); + + return () => { + markerRef.current?.remove(); + markerRef.current = null; + + if (mapRef.current) { + mapRef.current.remove(); + mapRef.current = null; + } + }; + }, [latLng.lat, latLng.lng, tileUrl, customIcon]); + + return
; +}; + +export default MapComponent; diff --git a/frontend/mobile-ui/src/app/features/Citizen/components/MapView.tsx b/frontend/mobile-ui/src/app/features/Citizen/components/MapView.tsx new file mode 100644 index 0000000..8816be2 --- /dev/null +++ b/frontend/mobile-ui/src/app/features/Citizen/components/MapView.tsx @@ -0,0 +1,445 @@ +// MapView.tsx displays a Leaflet map with property markers for the Citizen property list/map view. +// It supports selection, custom marker icons, and property details popups. +// Main responsibilities: +// - Render map with property markers and selection +// - Show property info card on marker select +// - Handle marker click and details navigation +// - Use custom icons and panes for selected marker +// Props: +// properties: array of property objects +// selectedMarkerIdx: index of selected marker +// setSelectedMarkerIdx: callback to set selected marker +// center, height, showEmptyMessage, zoom, onViewDetails: map options and event handlers +import React, { useMemo, useEffect, useRef } from 'react'; +import { Box } from '@mui/material'; +import '../../../../styles/Citizen/PropertyMarker.css'; +import maplibregl from 'maplibre-gl'; +import 'maplibre-gl/dist/maplibre-gl.css'; +import { useNavigate } from 'react-router-dom'; + +import pointerLight from '../../../assets/Citizen/home_page/property_pointer_light.svg'; +import pointerDark from '../../../assets/Citizen/home_page/property_pointer_dark.svg'; + +// Accept the *application* shape where GISData.Coordinates is under Property +// ...existing code... + +interface GenericProperty { + Property?: { + GISData?: { + Latitude?: number; + Longitude?: number; + Coordinates?: { Latitude?: number; Longitude?: number }[]; + }; + Address?: { + BlockNo?: string; + PinCode?: string | number; + Display?: string; + Street?: string; + [key: string]: any; + }; + [key: string]: any; + }; + locationData?: { + address?: string; + coordinates?: { + lat?: number; + lng?: number; + }; + }; + PropertyID?: string; + id?: string; + Status?: string; + enumerationProgress?: number; + [key: string]: any; +} + +// MapViewProps defines the props for the MapView component +interface MapViewProps { + properties: GenericProperty[]; + selectedMarkerIdx: number | null; + setSelectedMarkerIdx: (idx: number | null) => void; + center?: [number, number]; + height?: number; + showEmptyMessage?: boolean; + zoom?: number; + onViewDetails?: (property: GenericProperty) => void; +} + +const FALLBACK_CENTER: [number, number] = [12.9716, 77.5946]; + +const STATUS_PROGRESS_MAP: Record = { + INITIATED: 20, + ASSIGNED: 40, + VERIFIED: 60, + AUDIT_VERIFIED: 80, + APPROVED: 100, +}; + +// propertyToMarkerInfo: extracts marker info from property object +function propertyToMarkerInfo(p: GenericProperty): { + lat?: number; + lng?: number; + address?: any; + blockNo?: string; + pinCode?: string | number; + id?: string; + Status?: string; + enumerationProgress?: number; +} { + const status = (p.Status || '').toUpperCase(); + const enumerationProgress = STATUS_PROGRESS_MAP[status] ?? 0; + + if (p?.locationData?.coordinates) { + return { + lat: p.Property?.GISData?.Latitude, + lng: p.Property?.GISData?.Longitude, + address: p.locationData.address, + blockNo: p?.Property?.Address?.BlockNo, + pinCode: p?.Property?.Address?.PinCode, + id: p.id, + enumerationProgress, + }; + } + + // Check if GISData has direct Latitude/Longitude + const gisData = p?.Property?.GISData; + let lat: number | undefined; + let lng: number | undefined; + + if (gisData) { + // First try direct Latitude/Longitude + if (gisData.Latitude != null && gisData.Longitude != null) { + lat = gisData.Latitude; + lng = gisData.Longitude; + } + // Fallback to Coordinates array + else if (gisData.Coordinates?.[0]) { + lat = gisData.Coordinates[0].Latitude; + lng = gisData.Coordinates[0].Longitude; + } + } + + const addressObj = p?.Property?.Address; + let addressString = ''; + + if (addressObj) { + // Use Display if available, otherwise construct from parts + if (addressObj.Display) { + addressString = addressObj.Display; + } else if (addressObj.Street || addressObj.Locality) { + const parts = [ + addressObj.Street, + addressObj.Locality, + addressObj.BlockNo, + addressObj.WardNo, + ].filter(Boolean); + addressString = parts.join(', '); + } else { + addressString = 'Address not available'; + } + } else { + addressString = p?.PropertyID || 'Unknown address'; + } + + return { + lat, + lng, + address: addressString, + blockNo: p?.Property?.Address?.BlockNo, + pinCode: p?.Property?.Address?.PinCode, + id: p.id || p.PropertyID, + enumerationProgress, + }; +} + +// createMarkerElement: builds a DOM element for MapLibre marker (keeps same HTML/style as Leaflet DivIcon) +function createMarkerElement( + selected: boolean, + markerData?: ReturnType +): HTMLElement { + const pointerSize = selected ? 70 : 60; + const blockNoStr = markerData?.blockNo + ? `
Block No: ${markerData.blockNo}
` + : ''; + const pinCodeStr = markerData?.pinCode + ? `
Pincode: ${markerData.pinCode}
` + : ''; + + const cardHtml = + selected && markerData + ? ` +
+
+
${ + markerData.address ?? 'Unknown address' + }
+ ${blockNoStr} + ${pinCodeStr} +
+
+ ${markerData.enumerationProgress ?? 0}% Enumeration process complete +
+ +
+
+
+ ` + : ''; + + const wrapper = document.createElement('div'); + wrapper.className = `property-marker${selected ? ' selected' : ''}`; + wrapper.innerHTML = ` + property marker + ${cardHtml} + `; + + // set basic sizing so MapLibre marker placement matches previous behavior + wrapper.style.width = `${pointerSize}px`; + wrapper.style.height = `${pointerSize + (selected ? 130 : 0)}px`; + wrapper.style.display = 'block'; + wrapper.style.cursor = 'pointer'; + return wrapper; +} + +// NOTE: Leaflet-specific pane logic removed โ€” MapLibre markers use element zIndex instead. + +// MapView component: renders MapLibre map with property markers and selection logic +const MapView: React.FC = ({ + properties, + selectedMarkerIdx, + setSelectedMarkerIdx, + center, + height = 400, + showEmptyMessage = true, + zoom = 15, + onViewDetails, +}) => { + const navigate = useNavigate(); + const mapContainerRef = useRef(null); + const mapRef = useRef(null); + const markersRef = useRef([]); + const markersData = useMemo(() => { + return properties + .map((p, idx) => ({ + ...propertyToMarkerInfo(p), + idx, + original: p, + })) + .filter((m) => m.lat != null && m.lng != null); + }, [properties]); + + // computed center in [lng, lat] for MapLibre + const computedCenterLngLat: [number, number] = + markersData.length > 0 + ? [ + markersData[0].lng ?? FALLBACK_CENTER[1], + markersData[0].lat ?? FALLBACK_CENTER[0], + ] + : center + ? [center[1], center[0]] + : [FALLBACK_CENTER[1], FALLBACK_CENTER[0]]; + + // init map once + useEffect(() => { + if (!mapContainerRef.current) return; + + // cleanup existing map if any + if (mapRef.current) { + mapRef.current.remove(); + mapRef.current = null; + } + + const styleUrl = + 'https://api.maptiler.com/maps/base-v4/style.json?key=YguiTF06mLtcpSVKIQyc'; + + mapRef.current = new maplibregl.Map({ + container: mapContainerRef.current, + style: styleUrl, + center: computedCenterLngLat, + zoom, + attributionControl: false, + pitch: 0, + bearing: 0, + dragRotate: true, + pitchWithRotate: true, + touchPitch: true, + }); + + mapRef.current.addControl(new maplibregl.NavigationControl(), 'top-right'); + + // prevent default context menu so right-click drag works (keeps parity with previous behavior) + const handleContextMenu = (e: Event) => e.preventDefault(); + mapContainerRef.current.addEventListener('contextmenu', handleContextMenu); + + // cleanup on unmount + return () => { + if (mapRef.current) { + markersRef.current.forEach((m) => m.remove()); + markersRef.current = []; + mapRef.current.remove(); + mapRef.current = null; + } + if (mapContainerRef.current) { + mapContainerRef.current.removeEventListener('contextmenu', handleContextMenu); + } + }; + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); // initialize once + + // update markers when data or selection changes + useEffect(() => { + const map = mapRef.current; + if (!map) return; + + // remove old markers + markersRef.current.forEach((m) => m.remove()); + markersRef.current = []; + + if (markersData.length === 0) { + // add a center default marker similar to previous logic + const el = document.createElement('div'); + el.style.width = '20px'; + el.style.height = '20px'; + el.style.background = '#1976d2'; + el.style.borderRadius = '50%'; + el.style.border = '2px solid white'; + + const marker = new maplibregl.Marker({ element: el }) + .setLngLat(computedCenterLngLat) + .addTo(map); + markersRef.current.push(marker); + return; + } + + const bounds = new maplibregl.LngLatBounds(); + + markersData.forEach((m, idx) => { + const isSelected = selectedMarkerIdx === idx; + const el = createMarkerElement(isSelected, isSelected ? m : undefined); + + // set zIndex for selected marker so its card appears above others + if (isSelected) { + el.style.zIndex = '750'; + } else { + el.style.zIndex = '500'; + } + + // ensure clicks inside marker elements are visible to listeners + el.style.pointerEvents = 'auto'; + + const marker = new maplibregl.Marker({ element: el }) + .setLngLat([m.lng!, m.lat!]) + .addTo(map); + + // click handler to toggle selection (preserve original behavior) + const onMarkerClick = (e: MouseEvent) => { + e.stopPropagation(); + const target = e.target as HTMLElement; + // if the click was on the view-details button, let document handler handle it + if (target.closest && target.closest('.marker-card-btn-2')) return; + setSelectedMarkerIdx(selectedMarkerIdx === idx ? null : idx); + }; + el.addEventListener('click', onMarkerClick); + + markersRef.current.push(marker); + bounds.extend([m.lng!, m.lat!]); + }); + + // NOTE: fitBounds moved to a separate effect that runs only when markersData changes, + // so selecting a marker (selectedMarkerIdx change) won't trigger a re-fit/zoom out. + }, [markersData, selectedMarkerIdx, setSelectedMarkerIdx]); + + // Fit map to show all markers only when markersData changes (not on selection changes) + useEffect(() => { + const map = mapRef.current; + if (!map || markersData.length === 0) return; + const bounds = new maplibregl.LngLatBounds(); + markersData.forEach((m) => bounds.extend([m.lng!, m.lat!])); + // if only one marker, center on it instead of fitting bounds to avoid weird zoom + if (markersData.length === 1) { + map.easeTo({ center: [markersData[0].lng!, markersData[0].lat!], zoom }); + } else { + map.fitBounds(bounds, { padding: 50, maxZoom: 18, duration: 500 }); + } + }, [markersData, zoom]); + + // Handle "View Details" button click (same document-level listener as before) + useEffect(() => { + function handleClick(e: MouseEvent) { + const target = e.target as HTMLElement; + const btn = target.closest + ? (target.closest('.marker-card-btn-2') as HTMLElement | null) + : null; + if (!btn) return; + const idAttr = btn.getAttribute('data-prop-id'); + const markerData = markersData.find((m) => String(m.id) === String(idAttr)); + + if (markerData) { + // if (onViewDetails) { + // onViewDetails(markerData.original); + // } else { + // navigate(`/citizen/properties/${markerData.id}`, { + // state: { + // applicationId: markerData.id, + // }, + // }); + // } + } + } + document.addEventListener('click', handleClick); + return () => document.removeEventListener('click', handleClick); + }, [markersData, navigate, onViewDetails]); + + return ( + +
+ {markersData.length === 0 && showEmptyMessage && ( + + + No properties yet. Start by adding one. + + + )} + + ); +}; + +export default MapView; diff --git a/frontend/mobile-ui/src/app/features/Citizen/components/NoProperties.tsx b/frontend/mobile-ui/src/app/features/Citizen/components/NoProperties.tsx new file mode 100644 index 0000000..c9fb624 --- /dev/null +++ b/frontend/mobile-ui/src/app/features/Citizen/components/NoProperties.tsx @@ -0,0 +1,69 @@ +// NoProperties.tsx displays a message when the user has no properties added. +// It uses MUI for UI, localization for messages, and shows a sad icon and instructions. +// Main responsibilities: +// - Render a styled card with icon and localized messages +// - Show loader if localization is loading +// No props required; static message for empty property list +// NoProperties.tsx +import { Box, Typography } from '@mui/material'; +import { SentimentDissatisfied as SadIcon } from '@mui/icons-material'; +import { useAppSelector } from '../../../../redux/Hooks'; +import { + getMessagesFromSession, + useLocalization, +} from '../../../../services/Citizen/Localization/LocalizationContext'; +import LoadingPage from '../../../components/Loader'; + + +// NoProperties component: renders a styled card with icon and localized empty state messages +const NoProperties: React.FC = () => { + const lang = useAppSelector((state) => state.lang.citizenLang); // Current language + const { loading: localizationLoading } = useLocalization(); // Global loading state + const messages = getMessagesFromSession('CITIZEN')!; // Localized messages + + // Show loader if localization is loading + if (localizationLoading) { + return ; + } + + // Render empty state card with icon and messages + return ( + + {/* Sad icon for empty state */} + + {/* Main message */} + + {/* No properties found */} + {messages['citizen.no-property'][lang]['no-properties-found']} + + {/* Sub-messages */} + + {/* You have not added any property yet. */} + {messages['citizen.no-property'][lang]['no-property-added']} + + {/* Add properties to manage your assets! */} + {messages['citizen.no-property'][lang]['add-properties']} + + + ); +}; + +// Export NoProperties for use in empty property list views +export default NoProperties; diff --git a/frontend/mobile-ui/src/app/features/Citizen/components/OverviewStack.tsx b/frontend/mobile-ui/src/app/features/Citizen/components/OverviewStack.tsx new file mode 100644 index 0000000..a6342f0 --- /dev/null +++ b/frontend/mobile-ui/src/app/features/Citizen/components/OverviewStack.tsx @@ -0,0 +1,176 @@ +// OverviewStack.tsx displays a summary stack of property details for the Citizen property details page. +// It shows property type, construction year, built-up area, plot area, and property value using MUI and localization. +// Main responsibilities: +// - Map API property data to display fields +// - Render summary rows for key property info +// - Use icons and localization for labels +// Props: property (CitizenPropertyData) - the property whose summary is shown +import { Box, Stack, Typography } from '@mui/material'; +import type { FC } from 'react'; +import CropSquareIcon from '@mui/icons-material/CropSquare'; +import InfoOutlinedIcon from '@mui/icons-material/InfoOutlined'; +import { HouseOutlined } from '@mui/icons-material'; +import { useAppSelector } from '../../../../redux/Hooks'; +import { + getMessagesFromSession, + useLocalization, +} from '../../../../services/Citizen/Localization/LocalizationContext'; +import LoadingPage from '../../../components/Loader'; +import type { CitizenPropertyData } from '../models/CitizenPropertiesPageModel/CitizenPropertyPageModel'; +import activity_zone from "../../../assets/activity_zone.svg" + +// Props for OverviewStack: expects property data +interface OverviewStackProps { + property: CitizenPropertyData; +} + +// OverviewStack component: renders summary stack of property details +const OverviewStack: FC = ({ property }) => { + // Localization, state, and hooks + const lang = useAppSelector((state) => state.lang.citizenLang); // Current language + const { loading } = useLocalization(); // Global loading state + const messages = getMessagesFromSession('CITIZEN')!; // Localized messages + + // Show loader if localization is loading + if (loading) { + return ; + } + + // No property: render nothing + if (!property) return null; + + // Map API property data to display fields for UI + const propertyType = property.PropertyType || '-'; + + // Construction year - extract from FloorDetails or use default + const constructionYear = property.ConstructionDetails?.FloorDetails?.[0]?.constructionDate + ? new Date(property.ConstructionDetails.FloorDetails[0].constructionDate).getFullYear() + : '-'; + + // Built-up Area - sum of all floor plinth areas + const builtUpArea = + property.ConstructionDetails?.FloorDetails?.reduce( + (sum, floor) => sum + (floor.PlinthAreaSqFt || 0), + 0 + ).toFixed(2) + ' sq ft' || '-'; + + // Plot Area - from IGRS or AssessmentDetails + const plotArea = + property.IGRS?.totalPlinthArea + ? `${property.IGRS.totalPlinthArea} sq ft` + : property.AssessmentDetails?.ExtendOfSite || '-'; + + // Property Value - you'll need to calculate or get from another source + // const propertyValue = '-'; + return ( + + {/* First Row: Property Type & Construction Year */} + + {/* Property Type */} + + + + + {messages['citizen.my-properties'][lang]['property-type']} + + + {propertyType} + + + + {/* Construction Year */} + + + + + {messages['citizen.my-properties'][lang]['construct-year']} + + + {constructionYear} + + + + + {/* Second Row: Built-up Area & Plot Area */} + + {/* Built-up Area */} + + Activity Zone + + + {messages['citizen.my-properties'][lang]['built-up-area']} + + + {builtUpArea} + + + + {/* Plot Area */} + + + + + {messages['citizen.my-properties'][lang]['plot-area']} + + + {plotArea} + + + + + {/* Property Value */} + + + {/* {messages['citizen.my-properties'][lang]['property-value']} + */} + + + {/* {propertyValue} */} + + + + ); +}; + +// Export OverviewStack for use in property overview sections +export default OverviewStack; \ No newline at end of file diff --git a/frontend/mobile-ui/src/app/features/Citizen/components/PropertyCard.tsx b/frontend/mobile-ui/src/app/features/Citizen/components/PropertyCard.tsx new file mode 100644 index 0000000..d3e705d --- /dev/null +++ b/frontend/mobile-ui/src/app/features/Citizen/components/PropertyCard.tsx @@ -0,0 +1,301 @@ +// PropertyCard displays a summary card for a property, including address, status, and a map preview. +// It supports navigation to property details or form completion, and adapts UI based on property status. + +import { type FC } from 'react'; +import { Paper, Typography, Button, Box, Chip } from '@mui/material'; +import { useNavigate } from 'react-router-dom'; +import markerSvg from '../../../assets/Citizen/property_page/location.svg'; +import { Edit } from '@mui/icons-material'; +import { useAppSelector } from '../../../../redux/Hooks'; +import { + getMessagesFromSession, + useLocalization, +} from '../../../../services/Citizen/Localization/LocalizationContext'; +import LoadingPage from '../../../components/Loader'; +import MapComponent from './MapComponent'; +import { useFormMode } from '../../../../context/FormModeContext'; + +// Plain icon-like object (compatible with MapComponent using MapLibre) +const customIcon = { + iconUrl: markerSvg, + iconSize: [40, 40] as [number, number], + iconAnchor: [20, 40] as [number, number], + popupAnchor: [0, -40] as [number, number], + className: '', +}; + +// Props for PropertyCard +interface PropertyCardProps { + property: any; // Property data object + propertyId?: string; // Optional property ID override +} + +// Color mapping for property status badges +const statusColors: Record = { + Enumerated: { bg: '#85B9A1', color: '#fff' }, + 'Under Enumeration': { bg: '#FFCDB6', color: '#000' }, + Draft: { bg: '#FFC107', color: '#000' }, +}; + +// Color mapping for property types +const typeColors: Record = { + Apartment: '#C84C0E', + 'Residential Property': '#C84C0E', + 'RESIDENTIAL Property': '#C84C0E', + 'Primary Property': '#D49C7A', + 'Industrial Property': '#53C56C', + 'INDUSTRIAL Property': '#53C56C', + 'Commercial Property': '#53C56C', + 'COMMERCIAL Property': '#53C56C', + 'MIXED Property': '#8B4513', + 'Mixed Property': '#8B4513', +}; + +const PropertyCard: FC = ({ property, propertyId }) => { + const navigate = useNavigate(); + const { setMode } = useFormMode(); + + // Compute property type label (e.g., "Residential Property") + const type = property.propertyType + ' Property'; + + // Determine property status based on enumeration progress + // -1: Draft, 100: Enumerated, otherwise: Under Enumeration + let status = 'Under Enumeration'; + if (property.enumerationProgress === -1) { + status = 'Draft'; + } else if (property.enumerationProgress === 100) { + status = 'Enumerated'; + } + + // Get color for property type and status badge + const typeColor = typeColors[type] || '#C84C0E'; + const badge = statusColors[status] || statusColors['Under Enumeration']; + + // Get current language and localization messages + const lang = useAppSelector((state) => state.lang.citizenLang); + const { loading } = useLocalization(); + const messages = getMessagesFromSession('CITIZEN')!; + + // Compose address string from propertyAddress or fallback to locationData + const address = property.propertyAddress + ? [ + property.propertyAddress.street, + property.propertyAddress.locality, + property.propertyAddress.wardNo, + property.propertyAddress.zoneNo, + property.propertyAddress.blockNo, + property.propertyAddress.pincode, + ] + .filter(Boolean) + .join(', ') + : property.locationData?.address || ''; + + // Extract latitude and longitude for map display + const latLng = property.GISData + ? { lat: property.GISData.Latitude || 0, lng: property.GISData.Longitude || 0 } + : { lat: 0, lng: 0 }; + + // Prevent click event from bubbling to Paper when clicking on button or map + const stopPropagation = (e: React.MouseEvent) => e.stopPropagation(); + + // Handle card click: navigate to property details or complete form if draft + const handleCardClick = () => { + if (status === 'Draft') { + handleCompleteForm(); + } else { + // Navigate to property details page with full property data + navigate(`/citizen/properties/${property.id}`, { + state: { + applicationId: property.__appId, + property: property, + enumerationProgress: property.enumerationProgress, + isDraft: property.isDraft, + applicationStatus: property.applicationStatus, + }, + }); + } + }; + + // Handle view location button click: navigate to map view + // const handleViewLocation = (e: React.MouseEvent) => { + // e.stopPropagation(); + // navigate('/citizen/property-location', { + // state: { property }, + // }); + // }; + + // Handle complete form button click (for drafts): set mode and navigate + const handleCompleteForm = (e?: React.MouseEvent) => { + if (e) { + e.stopPropagation(); + } + + // Resolve property and application ids (prefer passed props, then fallback) + const resolvedPropertyId = propertyId; + const resolvedApplicationId = property.__appId; + + if (resolvedPropertyId) { + localStorage.setItem('propertyId', resolvedPropertyId); + } + if (resolvedApplicationId) { + localStorage.setItem('applicationId', resolvedApplicationId); + } + // Set form mode to draft + setMode('draft'); + // Navigate to property form + navigate('/property-form/property-information'); + }; + + // Show loader while localization is loading + if (loading) { + return ; + } + + // Render the property card UI + return ( + + {/* Header: Property type and status badge */} + + + {type} + + + + {/* Address label */} + + {messages['citizen.my-properties'][lang]['address']} + + {/* Address value */} + + {address || 'Address not available'} + + {/* Action buttons: Complete Form (Draft) or View Location */} + + {status === 'Draft' && ( + + ) //: ( + // + //) + } + + {/* Map preview for property location */} + + + + + ); +}; + +export default PropertyCard; diff --git a/frontend/mobile-ui/src/app/features/Citizen/components/PropertyComponent.tsx b/frontend/mobile-ui/src/app/features/Citizen/components/PropertyComponent.tsx new file mode 100644 index 0000000..6f5cbf5 --- /dev/null +++ b/frontend/mobile-ui/src/app/features/Citizen/components/PropertyComponent.tsx @@ -0,0 +1,196 @@ +// PropertyComponent.tsx +// This component displays a card summarizing a property for the citizen user. +// Shows address details, and provides buttons to view location and details. +// Props: +// property: MappedProperty object containing location and details +// bgcolor: background color for the card +// propertyDetails: additional property summary info +// Used in: Citizen property listing views + +import React from 'react'; +import { Card, CardContent, Typography, Button, Box, LinearProgress } from '@mui/material'; +import LaunchOutlinedIcon from '@mui/icons-material/LaunchOutlined'; +import { useNavigate } from 'react-router-dom'; +import type { CitizenPropertySummary } from '../../Citizen/api/CitizenHomePageApi/CitizenHomePageModel'; +import { useAppSelector } from '../../../../redux/Hooks'; +import { getMessagesFromSession, useLocalization } from '../../../../services/Citizen/Localization/LocalizationContext'; +import LoadingPage from '../../../components/Loader'; +import CottageOutlinedIcon from '@mui/icons-material/CottageOutlined'; + +export interface MappedProperty { + id: string; + locationData: { + address: string; + coordinates: { lat: number; lng: number }; + BlockNo?: string; + Locality?: string; + PinCode?: number | string; + Street?: string; + WardNo?: string; + ZoneNo?: string; + }; + status: string; + propertyDetails?: CitizenPropertySummary; +} + +interface PropertyCardProps { + applicationId: string; + property: MappedProperty; + bgcolor: string; +} + +const PropertyCard: React.FC = ({ + applicationId, + property, + bgcolor, +}) => { + const navigate = useNavigate(); + + // Get current language and localization loading state + const lang = useAppSelector((state) => state.lang.citizenLang); + const { loading } = useLocalization(); + const messages = getMessagesFromSession('CITIZEN')!; + + // Show loader if localization is loading + if (loading) { + return ; + } + + const STATUS_PROGRESS_MAP: Record = { + INITIATED: 20, + ASSIGNIED: 40, + VERIFIED: 60, + AUDIT_VERIFIED: 80, + APPROVED: 100, + }; + + const progress = STATUS_PROGRESS_MAP[property.status] ?? 20; + + const viewLocationLabel = messages['citizen.home'][lang]['view-location']; + + const handleViewLocation = () => { + navigate('/citizen/property-location', { + state: { property }, + }); + }; + + const handleViewDetails = () => { + navigate( + `/citizen/properties/${property.id}`, + { + state: { + applicationId : applicationId, + } + } + ); + }; + + const details = property.locationData || {}; + const propFallback = property.propertyDetails?.Address; + + // Build address string from available fields + const addressFields = [ + details.BlockNo || propFallback?.BlockNo, + details.Locality || propFallback?.Locality, + details.Street || propFallback?.Street, + details.WardNo || propFallback?.WardNo, + details.ZoneNo || propFallback?.ZoneNo, + (details.PinCode ?? propFallback?.PinCode)?.toString(), + ] + .filter(Boolean) + .join(', '); + + // Render property card UI + return ( + + + + + + + + {/* Property address header with icon */} + + {/* */} + + {addressFields || 'Address not available'} + + + + + {progress}% + + + + + + + + ); +}; + +// Export PropertyCard for use in citizen property views +export default PropertyCard; diff --git a/frontend/mobile-ui/src/app/features/Citizen/components/PropertyList.tsx b/frontend/mobile-ui/src/app/features/Citizen/components/PropertyList.tsx new file mode 100644 index 0000000..ee15494 --- /dev/null +++ b/frontend/mobile-ui/src/app/features/Citizen/components/PropertyList.tsx @@ -0,0 +1,83 @@ + +// PropertyList displays a list of properties for the citizen user, mapping application summaries to property cards. +import React from 'react'; +import type { CitizenApplicationSummary } from '../../Citizen/api/CitizenHomePageApi/CitizenHomePageModel'; +import PropertyCard from './PropertyComponent'; + + + +// Helper function to map application summaries to property card data structure +function mapApplicationsToProperties(applications: CitizenApplicationSummary[]) { + return applications.map(app => { + const property = app.Property || {}; + // Extract coordinates from GISData if available + const coordsArr = property.GISData?.Coordinates || []; + const coordinates = (Array.isArray(coordsArr) && coordsArr.length > 0) + ? { + lat: coordsArr[0]?.Latitude ?? 0, + lng: coordsArr[0]?.Longitude ?? 0, + } + : { lat: 0, lng: 0 }; + + // Compose address string from address fields + const addressObj = property.Address || {}; + + return { + applicationId: app.ID, // Application ID + id: property.ID, // Property ID + status: app.Status || '', // Application status + locationData: { + address: [ + addressObj.BlockNo, + addressObj.Locality, + addressObj.Street, + addressObj.WardNo, + addressObj.ZoneNo, + addressObj.PinCode + ].filter(Boolean).join(', ') || property.ComplexName || '', + coordinates, + BlockNo: addressObj.BlockNo || '', + Locality: addressObj.Locality || '', + PinCode: addressObj.PinCode || '', + Street: addressObj.Street || '', + WardNo: addressObj.WardNo || '', + ZoneNo: addressObj.ZoneNo || '', + }, + propertyDetails: property, // Full property details + }; + }); +} + + +// PropertyList: Maps CitizenApplicationSummary[] to PropertyCard shape, +// passing the mapped property object to each PropertyCard. +const PropertyList: React.FC<{ properties: CitizenApplicationSummary[] }> = ({ properties }) => { + // Map incoming application summaries to property card data + const mappedProperties = mapApplicationsToProperties(properties); + + return ( +
+ {mappedProperties.length === 0 ? ( + // Show message if no properties are found +
No properties found.
+ ) : ( + mappedProperties.map(property => { + const bgcolor = '#F7E4DB'; + + return ( + // Render a PropertyCard for each mapped property + + ); + }) + )} +
+ ); +}; + +export default PropertyList; \ No newline at end of file diff --git a/frontend/mobile-ui/src/app/features/Citizen/components/PropertyMapSection.tsx b/frontend/mobile-ui/src/app/features/Citizen/components/PropertyMapSection.tsx new file mode 100644 index 0000000..a393b9f --- /dev/null +++ b/frontend/mobile-ui/src/app/features/Citizen/components/PropertyMapSection.tsx @@ -0,0 +1,118 @@ +// PropertyMapSection.tsx +// This component displays a map section for a property, allowing users to toggle between different map views (standard and land use). +// Props: +// latLng: Object with latitude and longitude of the property +// customIcon: Leaflet icon to mark the property location +// Used in: Citizen property detail and location views + +import React, { type FC } from 'react'; +import { Box } from '@mui/material'; + +import { useAppSelector } from '../../../../redux/Hooks'; +import { + getMessagesFromSession, + useLocalization, +} from '../../../../services/Citizen/Localization/LocalizationContext'; +import LoadingPage from '../../../components/Loader'; +import MapComponent from './MapComponent'; + +// Keep the old URLs for compatibility with existing UI tab toggles (not used by MapLibre style directly) +const MAP_URL = + 'https://api.maptiler.com/maps/base-v4/style.json?key=YguiTF06mLtcpSVKIQyc'; +const LANDUSE_URL = + 'https://api.maptiler.com/maps/streets-v2/style.json?key=YguiTF06mLtcpSVKIQyc'; + +type PropertyMapProps = { + latLng: { + lat: number; + lng: number; + }; + customIcon: { + iconUrl?: string; + iconSize?: [number, number]; + iconAnchor?: [number, number]; + popupAnchor?: [number, number]; + className?: string; + }; +}; + +const PropertyMapSection: FC = ({ latLng, customIcon }) => { + const lang = useAppSelector((state) => state.lang.citizenLang); + const { loading } = useLocalization(); + const messages = getMessagesFromSession('CITIZEN')!; + + const MAP_TABS = [ + { label: messages['citizen.home'][lang]['map-btn'], key: 'map' }, + { label: messages['citizen.my-properties'][lang]['land-use'], key: 'landuse' }, + ]; + + const [activeMapTab, setActiveMapTab] = React.useState('map'); + const tileUrl = activeMapTab === 'landuse' ? LANDUSE_URL : MAP_URL; + + // Show loader if localization is loading + if (loading) { + return ; + } + + return ( + + + {MAP_TABS.map((tab, i) => ( + setActiveMapTab(tab.key)} + sx={{ + flex: 1, + textAlign: 'center', + cursor: 'pointer', + fontWeight: activeMapTab === tab.key ? 700 : 500, + fontSize: '18px', + color: activeMapTab === tab.key ? '#C84C0E' : '#787878', + bgcolor: '#fff', + borderTopLeftRadius: i === 0 ? '10px' : 0, + borderTopRightRadius: i === MAP_TABS.length - 1 ? '10px' : 0, + border: '1.5px solid #E0E0E0', + borderBottom: activeMapTab === tab.key ? '3px solid #E26512' : 'none', + borderRight: i === 0 ? 'none' : '1.5px solid #E0E0E0', + pt: '7px', + pb: '3px', + transition: 'none', + backgroundClip: 'padding-box', + }} + > + {tab.label} + + ))} + + + + {/* Pass the selected tileUrl for compatibility; MapComponent uses MapTiler style internally */} + + + + ); +}; + +export default PropertyMapSection; diff --git a/frontend/mobile-ui/src/app/features/Citizen/components/UrgentCard.tsx b/frontend/mobile-ui/src/app/features/Citizen/components/UrgentCard.tsx new file mode 100644 index 0000000..1895718 --- /dev/null +++ b/frontend/mobile-ui/src/app/features/Citizen/components/UrgentCard.tsx @@ -0,0 +1,39 @@ +// UrgentCard.tsx +// This component displays a notification card for urgent attention items in the citizen UI. +// Highlights immediate/pending items with a distinct color and icon. +// Props: +// item: UrgentAttention object containing type, status, message, and date +// Used in: Lists or sections showing urgent notifications to the user + +import React from 'react'; +import { Box, Typography } from '@mui/material'; +import NotificationsNoneIcon from '@mui/icons-material/NotificationsNone'; +import type { UrgentAttention } from '../models/UrgentAttention.model'; + +const UrgentCard: React.FC<{ item: UrgentAttention }> = ({ item }) => { + // Determine if the item requires immediate attention (type or status) + const isImmediate = item.type === 'immediate' || item.status === 'pending'; + return ( + + {/* Notification icon with color based on urgency */} + + {/* Notification message */} + {item.message} + {/* Notification date */} + {item.date} + + ); +}; + +// Export UrgentCard for use in urgent notification lists +export default UrgentCard; \ No newline at end of file diff --git a/frontend/mobile-ui/src/app/features/Citizen/components/index.ts b/frontend/mobile-ui/src/app/features/Citizen/components/index.ts new file mode 100644 index 0000000..cb9f2eb --- /dev/null +++ b/frontend/mobile-ui/src/app/features/Citizen/components/index.ts @@ -0,0 +1,8 @@ +export * from "./EnumOptComponent" +export * from "./PropertyCard" +export * from "./EnumOptComponent" +export * from "./ErrorMessage" +export * from "./MapComponent" +export * from "./NoProperties" +export * from "./OverviewStack" +export * from "./PropertyMapSection" \ No newline at end of file diff --git a/frontend/mobile-ui/src/app/features/Citizen/components/ui/DocumentsTab.tsx b/frontend/mobile-ui/src/app/features/Citizen/components/ui/DocumentsTab.tsx new file mode 100644 index 0000000..badb85e --- /dev/null +++ b/frontend/mobile-ui/src/app/features/Citizen/components/ui/DocumentsTab.tsx @@ -0,0 +1,442 @@ +// DocumentsTab.tsx displays and manages property documents for the Citizen property details page. +// It fetches document metadata, retrieves file blobs, and provides UI for viewing, downloading, editing, and uploading documents. +// Uses MUI for UI, Redux Toolkit Query for API calls, and localization for labels/messages. +// +// Main responsibilities: +// - Transform API document data for display +// - Fetch file blobs for each document +// - Show upload cards for missing documents +// - Handle view/download/edit actions +// - Display loading and error states +// +// Props: property (CitizenPropertyData) - the property whose documents are shown +import { Box, Button, IconButton, Paper, Stack, Typography, CircularProgress } from '@mui/material'; +import VisibilityOutlinedIcon from '@mui/icons-material/VisibilityOutlined'; +import DownloadOutlinedIcon from '@mui/icons-material/DownloadOutlined'; +// import EditOutlinedIcon from '@mui/icons-material/EditOutlined'; +import ErrorOutlineIcon from '@mui/icons-material/ErrorOutline'; +import { AddAPhotoOutlined, TaskOutlined } from '@mui/icons-material'; +import type { FC } from 'react'; +import { useState, useEffect } from 'react'; +import { useAppSelector } from '../../../../../redux/Hooks'; +import { + getMessagesFromSession, + useLocalization, +} from '../../../../../services/Citizen/Localization/LocalizationContext'; +import LoadingPage from '../../../../components/Loader'; +import type { CitizenPropertyData } from '../../models/CitizenPropertiesPageModel/CitizenPropertyPageModel'; +import { useLazyGetFileBlobQuery } from '../../api/CitizenDocumentPageApi/fileStoreApi'; + +const iconColor = '#C84C0E'; +const TENANT_ID = 'pg'; + +// DocumentDisplay defines the shape of document data for UI rendering +interface DocumentDisplay { + title: string; + filename?: string; + size?: string; + date?: string; + documentType?: string; + fileStoreId?: string; + action?: string; + isUpload?: boolean; + isChooseFile?: boolean; +} + +// Converts property.Documents from API format to DocumentDisplay[] for UI rendering +function buildDocumentDisplayList(property: CitizenPropertyData): DocumentDisplay[] { + if (!property || !property.Documents || property.Documents.length === 0) { + return []; + } + + const list: DocumentDisplay[] = []; + + for (const doc of property.Documents) { + const hasFile = doc.FileStoreID && doc.FileStoreID.trim() !== ''; + + list.push({ + title: doc.DocumentType || 'Document', + filename: doc.DocumentName || '', + size: '', + date: doc.UploadDate ? new Date(doc.UploadDate).toLocaleDateString() : '', + documentType: doc.DocumentType, + fileStoreId: doc.FileStoreID, + action: doc.action, + isUpload: !hasFile, + isChooseFile: !hasFile, + }); + } + + return list; +} + +// Props for Documents component: expects property data +interface DocumentsProps { + property: CitizenPropertyData; +} + +// Documents component: displays document cards, handles file fetch/view/download/upload +const Documents: FC = ({ property }) => { + // Localization, state, and hooks + const lang = useAppSelector((state) => state.lang.citizenLang); // Current language + const { loading } = useLocalization(); // Global loading state + const messages = getMessagesFromSession('CITIZEN')!; // Localized messages + const [documentDisplayList, setDocumentDisplayList] = useState([]); // UI document list + const [fileBlobs, setFileBlobs] = useState>({}); // Cached file blobs + const [fileErrors, setFileErrors] = useState>({}); // File fetch errors + const [loadingFiles, setLoadingFiles] = useState>({}); // Per-file loading state + + // RTK Query lazy hook for fetching file blobs + const [fetchFileBlob] = useLazyGetFileBlobQuery(); + + // Build document display list from property data + useEffect(() => { + if (!property) return; + const initialDocs = buildDocumentDisplayList(property); + setDocumentDisplayList(initialDocs); + }, [property]); + + // Fetch file blobs for each document (sequentially) + useEffect(() => { + if (documentDisplayList.length === 0) return; + + const fetchFilesSequentially = async () => { + const blobs: Record = {}; + const errors: Record = {}; + const loading: Record = {}; + + for (const doc of documentDisplayList) { + // Skip if no fileStoreId or is upload needed + if (!doc.fileStoreId || doc.isUpload) continue; + + try { + // Set loading state for this file + loading[doc.fileStoreId] = true; + setLoadingFiles({ ...loading }); + + // Fetch file blob from filestore + const blob = await fetchFileBlob({ + fileStoreId: doc.fileStoreId, + tenantId: TENANT_ID, + }).unwrap(); + + if (!blob) { + throw new Error('No blob returned from filestore'); + } + + blobs[doc.fileStoreId] = blob; + + // Update document size in UI + const sizeInMB = (blob.size / (1024 * 1024)).toFixed(2); + setDocumentDisplayList(prev => + prev.map(d => + d.fileStoreId === doc.fileStoreId + ? { ...d, size: `${sizeInMB} MB` } + : d + ) + ); + + // Update file blob cache + setFileBlobs({ ...blobs }); + + } catch (error) { + // Handle file fetch error + console.error(`Error fetching file ${doc.fileStoreId}:`, error); + const errorMessage = error instanceof Error ? error.message : 'Failed to fetch file'; + const apiError = error as { data?: { message?: string } }; + errors[doc.fileStoreId] = apiError.data?.message || errorMessage; + setFileErrors({ ...errors }); + } finally { + // Clear loading state for this file + loading[doc.fileStoreId] = false; + setLoadingFiles({ ...loading }); + } + } + }; + + fetchFilesSequentially(); + }, [documentDisplayList.length, fetchFileBlob]); + + // Show loader if localization is loading + if (loading) { + return ; + } + + // No property data: render nothing + if (!property) return null; + + // Sort documents: upload-needed first, then normal docs + const sortedDocuments = + documentDisplayList.length > 0 + ? [...documentDisplayList].sort((a, b) => { + const aNeedsUpload = a.isUpload || a.isChooseFile; + const bNeedsUpload = b.isUpload || b.isChooseFile; + if (aNeedsUpload === bNeedsUpload) return 0; + return aNeedsUpload ? -1 : 1; + }) + : []; + + // View document in new tab using cached blob + const handleViewDocument = async (fileStoreId: string) => { + try { + const blob = fileBlobs[fileStoreId]; + if (!blob) { + console.error('File not found in cache'); + alert('File is still loading or not available. Please try again.'); + return; + } + + const url = URL.createObjectURL(blob); + window.open(url, '_blank'); + setTimeout(() => URL.revokeObjectURL(url), 1000); + } catch (error) { + console.error('Error viewing document:', error); + alert('Failed to view document. Please try again.'); + } + }; + + // Download document using cached blob + const handleDownloadDocument = async (fileStoreId: string, filename: string) => { + try { + const blob = fileBlobs[fileStoreId]; + if (!blob) { + console.error('File not found in cache'); + alert('File is still loading or not available. Please try again.'); + return; + } + + const url = URL.createObjectURL(blob); + const a = document.createElement('a'); + a.href = url; + a.download = filename || 'document'; + document.body.appendChild(a); + a.click(); + document.body.removeChild(a); + URL.revokeObjectURL(url); + } catch (error) { + console.error('Error downloading document:', error); + alert('Failed to download document. Please try again.'); + } + }; + + // const handleEditDocument = (fileStoreId: string) => { + // console.log('Edit document:', fileStoreId); + // }; + + // Choose file handler for upload (stub) + const handleChooseFile = (documentType: string) => { + console.log('Choose file for:', documentType); + }; + + // Render document cards: upload-needed and normal documents + return ( + + + {messages['citizen.my-properties'][lang]['documents']} + + + {sortedDocuments && sortedDocuments.length > 0 ? ( + + {sortedDocuments.map((doc, idx) => { + const isChooseFile = doc.isUpload || doc.isChooseFile; + const borderColor = isChooseFile ? '#C84C0E' : '#e0e0e0'; + const isFileLoading = loadingFiles[doc.fileStoreId || '']; + const hasError = Boolean(fileErrors[doc.fileStoreId || '']); + + // Upload-needed document card + if (isChooseFile) { + return ( + + + + + + {doc.title} + + + + + Take Image + + + + + + PDF, JPG, PNG
(Max 5MB) +
+
+
+ ); + } + + // Normal document card: view, download, edit, error, loading + return ( + + + {isFileLoading ? ( + + ) : hasError ? ( + + ) : ( + + )} + + + + + {doc.title} + + {doc.action === 'PENDING' && !hasError && ( + + PENDING APPROVAL + + )} + {hasError && ( + + FILE NOT FOUND + + )} + {/* handleEditDocument(doc.fileStoreId || '')} + disabled={isFileLoading || hasError} + > + + */} + + + {doc.filename} + + + + {hasError ? ( + {fileErrors[doc.fileStoreId || '']} + ) : isFileLoading ? ( + 'Loading file...' + ) : ( + <>{doc.size && `${doc.size} โ€ข `}{doc.date} + )} + + handleViewDocument(doc.fileStoreId || '')} + disabled={!fileBlobs[doc.fileStoreId || ''] || hasError || isFileLoading} + > + + + handleDownloadDocument(doc.fileStoreId || '', doc.filename || 'document')} + disabled={!fileBlobs[doc.fileStoreId || ''] || hasError || isFileLoading} + > + + + + + + ); + })} +
+ ) : ( + + No documents found. + + )} +
+ ); +}; + +export default Documents; \ No newline at end of file diff --git a/frontend/mobile-ui/src/app/features/Citizen/components/ui/HistoryCard.tsx b/frontend/mobile-ui/src/app/features/Citizen/components/ui/HistoryCard.tsx new file mode 100644 index 0000000..b5563ad --- /dev/null +++ b/frontend/mobile-ui/src/app/features/Citizen/components/ui/HistoryCard.tsx @@ -0,0 +1,77 @@ +import { + // Box, + // Chip, + Paper, + Stack, + // Tooltip, + Typography, +} from "@mui/material"; +import type { FC } from "react"; +import { useAppSelector } from "../../../../../redux/Hooks"; +import { getMessagesFromSession, useLocalization } from "../../../../../services/Citizen/Localization/LocalizationContext"; +// import InfoOutlinedIcon from "@mui/icons-material/InfoOutlined"; +import LoadingPage from "../../../../components/Loader"; +import type { CitizenPropertyData } from "../../models/CitizenPropertiesPageModel/CitizenPropertyPageModel"; + +// Tag color by ownershipType (case-insensitive) +// const TYPE_COLORS: Record = { +// owner: "#C84C0E", +// tenant: "#92731C", +// }; + +interface HistoryProps { + property: CitizenPropertyData; +} + +const History: FC = ({ property }) => { + const lang = useAppSelector((state) => state.lang.citizenLang); + const { loading } = useLocalization(); + const messages = getMessagesFromSession("CITIZEN")!; + + if (loading) { + return ; + } + + if (!property) return null; + + // Note: The API response doesn't include a 'history' field + // You'll need to either: + // 1. Add a separate API endpoint to fetch property history + // 2. Use property ownership/transaction data from another source + // For now, we'll show a placeholder message + const hasHistory = false; // Set to true when history data is available + + return ( + + + + {hasHistory ? ( + + {/* When you have history data, map it here */} + {/* Example structure: + {property.history.map((h, idx) => ( + + // History card content + + ))} + */} + + ) : ( + + {messages['citizen.my-properties'][lang]['no-history'] || 'No ownership history available.'} + + )} + + ); +}; + +export default History; \ No newline at end of file diff --git a/frontend/mobile-ui/src/app/features/Citizen/components/ui/OverviewCard.tsx b/frontend/mobile-ui/src/app/features/Citizen/components/ui/OverviewCard.tsx new file mode 100644 index 0000000..df29d04 --- /dev/null +++ b/frontend/mobile-ui/src/app/features/Citizen/components/ui/OverviewCard.tsx @@ -0,0 +1,160 @@ +// OverviewCard.tsx displays a summary of property details for the Citizen property details page. +// It shows government numbers, land use, zoning, and FSI, using MUI for UI and localization for labels. +// Main responsibilities: +// - Map API property data to display fields +// - Render overview and land use/zoning cards +// - Use OverviewStack for additional summary info +// - Show loading state and handle missing data +// Props: property (CitizenPropertyData) - the property whose overview is shown +import { Box, Paper, Stack, Typography } from "@mui/material"; +import type { FC } from "react"; +import OverviewStack from "../OverviewStack"; +import InfoOutlinedIcon from "@mui/icons-material/InfoOutlined"; +// import MapIcon from "@mui/icons-material/Map"; +import { useAppSelector } from "../../../../../redux/Hooks"; +import { getMessagesFromSession, useLocalization } from "../../../../../services/Citizen/Localization/LocalizationContext"; +import LoadingPage from "../../../../components/Loader"; +import type { CitizenPropertyData } from "../../models/CitizenPropertiesPageModel/CitizenPropertyPageModel"; + +// Props for OverviewCard: expects property data +interface OverviewCardProps { + property: CitizenPropertyData; +} + +// OverviewCard component: displays property summary and land use/zoning info +const OverviewCard: FC = ({ property }) => { + // Localization, state, and hooks + const lang = useAppSelector((state) => state.lang.citizenLang); // Current language + const { loading } = useLocalization(); // Global loading state + const messages = getMessagesFromSession("CITIZEN")!; // Localized messages + + // Show loader if localization is loading + if (loading) { + return ; + } + + // No property data: render nothing + if (!property) { + return null; + } + + // Map API data to display fields + // Note: These fields might not exist in CitizenPropertyData, + // you'll need to adjust based on actual data structure + // const surveyNumber = property.AdditionalDetails?.fieldValue?.serialNo || 'N/A'; + const zoneNo = property.Address?.ZoneNo || 'N/A'; + const ward = property.Address?.WardNo || 'N/A'; + const currentUse = property.PropertyType || 'N/A'; + const approvedUse = property.PropertyType || 'N/A'; + const zoning = property.Address?.ZoneNo || 'N/A'; + const fsi = property.IGRS?.builtUpAreaPct ? `${property.IGRS.builtUpAreaPct}%` : 'N/A'; + + // Render overview and land use/zoning cards + return ( + <> + {/* Overview summary card */} + + + + + {messages['citizen.my-properties'][lang]['gov-numbers']} + + + {/* {messages['citizen.my-properties'][lang]['survey-number']}: {zoneNo} */} + Zone No: {zoneNo} + + + {messages['citizen.my-properties'][lang]['ward']}: {ward} + + + + {/* Land Use & Zoning Card - ONLY in Overview */} + + + + + + {messages['citizen.my-properties'][lang]['land-use-zone']} + + + {/* */} + + + + + + {messages['citizen.my-properties'][lang]['current-use']} + + + {currentUse} + + + + + {messages['citizen.my-properties'][lang]['approved-use']} + + + {approvedUse} + + + + + + + + {messages['citizen.my-properties'][lang]['zoning']} + + + {zoning} + + + + + {messages['citizen.my-properties'][lang]['fsi']} + + + {fsi} + + + + + + ); +} + +export default OverviewCard; \ No newline at end of file diff --git a/frontend/mobile-ui/src/app/features/Citizen/components/ui/PlotInfoCard.tsx b/frontend/mobile-ui/src/app/features/Citizen/components/ui/PlotInfoCard.tsx new file mode 100644 index 0000000..34cc590 --- /dev/null +++ b/frontend/mobile-ui/src/app/features/Citizen/components/ui/PlotInfoCard.tsx @@ -0,0 +1,197 @@ +// PlotInfoCard.tsx displays plot and building setback information for a property on the Citizen property details page. +// It shows survey, address, and IGRS setback details using MUI for UI and localization for labels. +// Main responsibilities: +// - Map API property data to display fields +// - Render info grid for plot details +// - Render building setback grid +// - Show loading state and handle missing data +// Props: property (CitizenPropertyData) - the property whose plot info is shown +import { Box, Divider, Paper, Typography } from "@mui/material"; +import type { FC } from "react"; +import { useAppSelector } from "../../../../../redux/Hooks"; +import { getMessagesFromSession, useLocalization } from "../../../../../services/Citizen/Localization/LocalizationContext"; +import LoadingPage from "../../../../components/Loader"; +import type { CitizenPropertyData } from "../../models/CitizenPropertiesPageModel/CitizenPropertyPageModel"; +import activity_zone from "../../../../assets/activity_zone.svg" + +// Props for PlotInfo: expects property data +interface PlotInfoProps { + property: CitizenPropertyData; +} + +// PlotInfo component: displays plot and building setback info for a property +const PlotInfo: FC = ({ property }) => { + // Localization, state, and hooks + const lang = useAppSelector((state) => state.lang.citizenLang); // Current language + const { loading } = useLocalization(); // Global loading state + const messages = getMessagesFromSession("CITIZEN")!; // Localized messages + + // Show loader if localization is loading + if (loading) { + return ; + } + + // No property data: render nothing + if (!property) return null; + + // Map API data to display fields + // const surveyNumber = property.AdditionalDetails?.fieldValue?.serialNo?.toString() || '-'; + const complexName = property.ComplexName.toString() || '-'; + const locality = property.Address?.Locality || '-'; + const zoneNo = property.Address?.ZoneNo || '-'; + const wardNo = property.Address?.WardNo || '-'; + const blockNo = property.Address?.BlockNo || '-'; + const street = property.Address?.Street || '-'; + + // Building Setbacks from IGRS (if available) + const frontSetback = property.IGRS?.frontSetback ? `${property.IGRS.frontSetback} ft` : '-'; + const coverage = property.IGRS?.builtUpAreaPct ? `${property.IGRS.builtUpAreaPct}%` : '-'; + const rearSetback = property.IGRS?.rearSetback ? `${property.IGRS.rearSetback} ft` : '-'; + const sideSetback = property.IGRS?.sideSetback ? `${property.IGRS.sideSetback} ft` : '-'; + + // Render plot info and building setback grids + return ( + + {/* Heading with icon */} + + + {/* svg icon for plot info */} + Activity Zone + + + {messages['citizen.my-properties'][lang]['plt-info']} + + + {/* Info Grid: survey, address, etc. */} + + {/* Survey Number / Locality */} + + + {/* {messages['citizen.my-properties'][lang]['survey-number']} */} + Apartment Name + + + {complexName} + + + + + Locality + + + {locality} + + + {/* Zone No / Ward No */} + + + Zone No + + + {zoneNo} + + + + + Ward No + + + {wardNo} + + + {/* Block No / Street */} + + + Block No + + + {blockNo} + + + + + Street + + + {street} + + + + + + {/* Building Setbacks grid */} + + {messages['citizen.my-properties'][lang]['build-setbacks']} + + + {/* Front Setback / Coverage */} + + + {messages['citizen.my-properties'][lang]['front-setback']} + + + {frontSetback} + + + + + {messages['citizen.my-properties'][lang]['coverage']} + + + {coverage} + + + {/* Rear Setback / Side Setbacks */} + + + {messages['citizen.my-properties'][lang]['rear-setback']} + + + {rearSetback} + + + + + {messages['citizen.my-properties'][lang]['side-setback']} + + + {sideSetback} + + + + + ); +}; + +export default PlotInfo; \ No newline at end of file diff --git a/frontend/mobile-ui/src/app/features/Citizen/components/ui/PropertyList.tsx b/frontend/mobile-ui/src/app/features/Citizen/components/ui/PropertyList.tsx new file mode 100644 index 0000000..7d88398 --- /dev/null +++ b/frontend/mobile-ui/src/app/features/Citizen/components/ui/PropertyList.tsx @@ -0,0 +1,36 @@ +// PropertyList.tsx displays a list of property cards for the Citizen property list page. +// It receives an array of property summaries and renders a PropertyCard for each. +// Main responsibilities: +// - Map over properties and render PropertyCard for each +// - Pass property data as props to PropertyCard +// Props: properties (CitizenPropertySummary[]) - array of property summaries to display +import type { FC } from 'react'; +import { Box } from '@mui/material'; +import PropertyCard from '../PropertyCard'; +import type { CitizenPropertySummary } from '../../api/CitizenHomePageApi/CitizenHomePageModel'; + +// PropertyList component: renders a list of PropertyCard components for each property +const PropertyList: FC<{ properties: CitizenPropertySummary[] }> = ({ properties }) => { + return ( + <> + {properties.map((prop: CitizenPropertySummary) => ( + + {/* */} + + + ))} + + ); +}; + +// Export PropertyList for use in property list pages +export default PropertyList; \ No newline at end of file diff --git a/frontend/mobile-ui/src/app/features/Citizen/models/AssessmentDetails.model.ts b/frontend/mobile-ui/src/app/features/Citizen/models/AssessmentDetails.model.ts new file mode 100644 index 0000000..e70d6d3 --- /dev/null +++ b/frontend/mobile-ui/src/app/features/Citizen/models/AssessmentDetails.model.ts @@ -0,0 +1,9 @@ +// Represents assessment details for a property +export type AssessmentDetails = { + reason: string; // Reason for assessment creation + extentOfSite: number; // Area/extent of the site + landUnderBuilding: number; // Area of land under the building + isUnspecifiedShare: boolean; // Whether the property has an unspecified share + occupancyCertificateDate: string; // Date of occupancy certificate + occupancyCertificateNumber: string; // Occupancy certificate number +} \ No newline at end of file diff --git a/frontend/mobile-ui/src/app/features/Citizen/models/Bill.model.ts b/frontend/mobile-ui/src/app/features/Citizen/models/Bill.model.ts new file mode 100644 index 0000000..7f0d771 --- /dev/null +++ b/frontend/mobile-ui/src/app/features/Citizen/models/Bill.model.ts @@ -0,0 +1,12 @@ +// Represents a property tax bill +export type Bill = { + id: string; // Unique bill identifier + propertyId: string; // Linked property ID + billNo: string; // Bill number + billType: string; // Type of bill (e.g., property tax, penalty) + amount: number; // Bill amount + status: string; // Bill status (e.g., paid, unpaid) + dueDate: string; // Due date for payment + createdAt: string; // Creation timestamp + updatedAt: string; // Last update timestamp +} \ No newline at end of file diff --git a/frontend/mobile-ui/src/app/features/Citizen/models/CitizenDocumentPageModel/fileStoreModel.ts b/frontend/mobile-ui/src/app/features/Citizen/models/CitizenDocumentPageModel/fileStoreModel.ts new file mode 100644 index 0000000..7658381 --- /dev/null +++ b/frontend/mobile-ui/src/app/features/Citizen/models/CitizenDocumentPageModel/fileStoreModel.ts @@ -0,0 +1,8 @@ +// Represents the result of a file upload operation +export interface UploadResult { + files: { + fileStoreId: string; // Unique identifier for the uploaded file in the file store + tenantId: string; // Tenant or jurisdiction ID associated with the file + }[]; +} + \ No newline at end of file diff --git a/frontend/mobile-ui/src/app/features/Citizen/models/CitizenHome.model.ts b/frontend/mobile-ui/src/app/features/Citizen/models/CitizenHome.model.ts new file mode 100644 index 0000000..47b65d4 --- /dev/null +++ b/frontend/mobile-ui/src/app/features/Citizen/models/CitizenHome.model.ts @@ -0,0 +1,10 @@ +import type { UrgentAttention } from "../models/UrgentAttention.model"; +import type { Property } from "../models/Property.model"; + +// Represents the main data structure for the citizen home/dashboard view +export interface CitizenHomeData { + activeLicenses: number; // Number of active licenses for the citizen + numberOfProperties: number; // Total number of properties owned + properties: Property[]; // List of property objects + urgentAttention: UrgentAttention[]; // List of items requiring urgent attention +} \ No newline at end of file diff --git a/frontend/mobile-ui/src/app/features/Citizen/models/CitizenPropertiesPageModel/CitizenPropertyPageModel.ts b/frontend/mobile-ui/src/app/features/Citizen/models/CitizenPropertiesPageModel/CitizenPropertyPageModel.ts new file mode 100644 index 0000000..daa4fc8 --- /dev/null +++ b/frontend/mobile-ui/src/app/features/Citizen/models/CitizenPropertiesPageModel/CitizenPropertyPageModel.ts @@ -0,0 +1,170 @@ +// Response structure for citizen property API +export interface CitizenPropertyResponse { + success: boolean; // Indicates if the API call was successful + message: string; // Response message + data: CitizenPropertyData; // Main property data +} + +// Main property data model for citizen view +export interface CitizenPropertyData { + ID: string; // Unique property identifier + PropertyNo: string; // Property number + OwnershipType: string; // Type of ownership + PropertyType: string; // Type/category of property + ComplexName: string; // Name of the complex (if any) + Address: PropertyAddress; // Address details + AssessmentDetails: AssessmentDetails; // Assessment details + Amenities: Amenities; // Amenities available + ConstructionDetails: ConstructionDetails; // Construction details + AdditionalDetails: AdditionalDetails; // Additional custom details + GISData: GISData; // Geographic Information System data + CreatedAt: string; // Creation timestamp + UpdatedAt: string; // Last update timestamp + Documents: PropertyDocument[]; // Related documents + IGRS: IGRSData; // IGRS (Integrated Grievance Redressal System) data +} + +// Address details for a property +export interface PropertyAddress { + ID: string; // Unique address identifier + Locality: string; // Locality or neighborhood + ZoneNo: string; // Zone number + WardNo: string; // Ward number + BlockNo: string; // Block number + Street: string; // Street name + ElectionWard: string; // Election ward + SecretariatWard: string; // Secretariat ward + PinCode: number; // Postal code + DifferentCorrespondenceAddress: boolean; // If correspondence address is different + PropertyID: string; // Linked property ID + CreatedAt: string; // Creation timestamp + UpdatedAt: string; // Last update timestamp +} + +// Assessment details for the property +export interface AssessmentDetails { + ID: string; // Unique identifier + ReasonOfCreation: string; // Reason for assessment creation + OccupancyCertificateNumber: string; // Occupancy certificate number + OccupancyCertificateDate: string; // Date of occupancy certificate + ExtendOfSite: string; // Site area/extent + IsLandUnderneathBuilding: boolean; // Whether land is underneath building + IsUnspecifiedShare: boolean; // If property has unspecified share + PropertyID: string; // Linked property ID + CreatedAt: string; // Creation timestamp + UpdatedAt: string; // Last update timestamp +} + +// Amenities available for the property +export interface Amenities { + ID: string; // Unique identifier + type: string[]; // Types of amenities + Description: string; // Description of amenities + ExpiryDate: string; // Expiry date for amenities + PropertyID: string; // Linked property ID + CreatedAt: string; // Creation timestamp + UpdatedAt: string; // Last update timestamp +} + +// Construction-related details of the property +export interface ConstructionDetails { + ID: string; // Unique identifier + FloorType: string; // Type of floor + WallType: string; // Type of wall + RoofType: string; // Type of roof + WoodType: string; // Type of wood used + PropertyID: string; // Linked property ID + FloorDetails: FloorDetail[]; // Details about each floor + CreatedAt: string; // Creation timestamp + UpdatedAt: string; // Last update timestamp +} + +// Details for each floor in the property +export interface FloorDetail { + ID: string; // Unique floor identifier + FloorNo: number; // Floor number + Classification: string; // Classification of the floor + NatureOfUsage: string; // Usage type (e.g., residential, commercial) + FirmName: string; // Name of firm (if any) + OccupancyType: string; // Type of occupancy + OccupancyName: string; // Name of occupant + constructionDate: string; // Date of construction + effectiveFromDate: string; // Effective from date + UnstructuredLand: string; // Unstructured land info + LengthFt: number; // Length in feet + BreadthFt: number; // Breadth in feet + PlinthAreaSqFt: number; // Plinth area in sq ft + BuildingPermissionNo: string; // Building permission number + FloorDetailsEntered: boolean; // Whether floor details are entered + ConstructionDetailsID: string; // Linked construction details ID + CreatedAt: string; // Creation timestamp + UpdatedAt: string; // Last update timestamp +} + +// Any additional custom details for the property +export interface AdditionalDetails { + ID: string; // Unique identifier + FieldName: string; // Name of the additional field + fieldValue: { + DocumentType: number; // Type of document + revenueDocumentNo: number; // Revenue document number + serialNo: number; // Serial number + }; + PropertyID: string; // Linked property ID + CreatedAt: string; // Creation timestamp + UpdatedAt: string; // Last update timestamp +} + +// Geographic Information System (GIS) data for the property +export interface GISData { + ID: string; // Unique GIS data identifier + Source: string; // Source of GIS data + Type: string; // Type of GIS data + Latitude: number; // Latitude coordinate + Longitude: number; // Longitude coordinate + EntityType: string; // Type of entity (e.g., property) + PropertyID: string; // Linked property ID + Coordinates: Coordinate[]; // List of coordinates + CreatedAt: string; // Creation timestamp + UpdatedAt: string; // Last update timestamp +} + +// Single coordinate point for GIS data +export interface Coordinate { + ID: string; // Unique coordinate identifier + Latitude: number; // Latitude value + Longitude: number; // Longitude value + GISDataID: string; // Linked GIS data ID + CreatedAt: string; // Creation timestamp +} + +// Document associated with the property +export interface PropertyDocument { + ID: string; // Unique document identifier + PropertyID: string; // Linked property ID + DocumentType: string; // Type of document + DocumentName: string; // Name of the document + FileStoreID: string; // File store identifier + UploadDate: string; // Date of upload + action: string; // Action performed (e.g., upload, delete) +} + +// IGRS (Integrated Grievance Redressal System) data for the property +export interface IGRSData { + id: string; // Unique IGRS data identifier + habitation: string; // Habitation name + igrsWard: string; // IGRS ward + igrsLocality: string; // IGRS locality + igrsBlock: string; // IGRS block + doorNoFrom: string; // Door number (from) + doorNoTo: string; // Door number (to) + igrsClassification: string; // IGRS classification + builtUpAreaPct: number; // Built-up area percentage + frontSetback: number; // Front setback + rearSetback: number; // Rear setback + sideSetback: number; // Side setback + totalPlinthArea: number; // Total plinth area + createdAt: string; // Creation timestamp + updatedAt: string; // Last update timestamp + PropertyID: string; // Linked property ID +} \ No newline at end of file diff --git a/frontend/mobile-ui/src/app/features/Citizen/models/ConstructionDetails.model.ts b/frontend/mobile-ui/src/app/features/Citizen/models/ConstructionDetails.model.ts new file mode 100644 index 0000000..9c2bd5f --- /dev/null +++ b/frontend/mobile-ui/src/app/features/Citizen/models/ConstructionDetails.model.ts @@ -0,0 +1,7 @@ +// Represents construction details for a property +export type ConstructionDetails = { + roofType: string; // Type of roof used in the property + wallType: string; // Type of wall construction + woodType: string; // Type of wood used (if any) + floorType: string; // Type of flooring +} \ No newline at end of file diff --git a/frontend/mobile-ui/src/app/features/Citizen/models/Document.model.ts b/frontend/mobile-ui/src/app/features/Citizen/models/Document.model.ts new file mode 100644 index 0000000..c5b0095 --- /dev/null +++ b/frontend/mobile-ui/src/app/features/Citizen/models/Document.model.ts @@ -0,0 +1,13 @@ +import type { DocumentFile } from "./DocumentFile.model"; + +// Represents a legal or property-related document +export type Document = { + no: string; // Document number or identifier + files: DocumentFile[]; // List of associated document files + courtName: string; // Name of the court (if applicable) + documentType: string; // Type/category of the document + constructionDate: string; // Date of construction (if relevant) + mroProceedingDate: string; // Date of MRO (Mandal Revenue Officer) proceeding + mroProceedingNumber: string; // MRO proceeding number + testatorAndTwoWitnessesSigned: boolean; // Whether the document is signed by testator and two witnesses +} \ No newline at end of file diff --git a/frontend/mobile-ui/src/app/features/Citizen/models/DocumentFile.model.ts b/frontend/mobile-ui/src/app/features/Citizen/models/DocumentFile.model.ts new file mode 100644 index 0000000..273bcc2 --- /dev/null +++ b/frontend/mobile-ui/src/app/features/Citizen/models/DocumentFile.model.ts @@ -0,0 +1,8 @@ +// Represents a file associated with a document +export type DocumentFile = { + fileName: string; // Name of the file + fileSize: number; // Size of the file in bytes + fileType: string; // MIME type of the file + fileStoreId: string; // Unique identifier in the file store + dateOfUpload: string; // Date when the file was uploaded +} \ No newline at end of file diff --git a/frontend/mobile-ui/src/app/features/Citizen/models/FloorDetails.model.ts b/frontend/mobile-ui/src/app/features/Citizen/models/FloorDetails.model.ts new file mode 100644 index 0000000..ce5dff1 --- /dev/null +++ b/frontend/mobile-ui/src/app/features/Citizen/models/FloorDetails.model.ts @@ -0,0 +1,18 @@ +// Represents details for a single floor in a property +export type FloorDetails = { + length: number; // Length of the floor (in feet/meters) + breadth: number; // Breadth of the floor (in feet/meters) + firmName: string; // Name of the firm (if any) occupying the floor + occupancy: string; // Type of occupancy (e.g., owner, tenant) + plinthArea: number; // Plinth area of the floor + floorNumber: string; // Floor number or label + occupantName: string; // Name of the occupant + natureOfUsage: string; // Usage type (e.g., residential, commercial) + constructionDate: string; // Date of construction + unstructuredLand: string; // Unstructured land info (if any) + effectiveFromDate: string; // Date from which the floor is effective + igrsClassification: string; // IGRS classification for the floor + buildingPermissionNo: string; // Building permission number + floorsDetailsEntered: boolean; // Whether floor details have been entered + buildingClassification: string; // Classification of the building +} \ No newline at end of file diff --git a/frontend/mobile-ui/src/app/features/Citizen/models/History.model.ts b/frontend/mobile-ui/src/app/features/Citizen/models/History.model.ts new file mode 100644 index 0000000..c098c3d --- /dev/null +++ b/frontend/mobile-ui/src/app/features/Citizen/models/History.model.ts @@ -0,0 +1,11 @@ +// Represents a single item in the property ownership or transaction history +export type HistoryItem = { + id: string; // Unique identifier for the history item + propertyId: string; // Linked property ID + ownerName: string; // Name of the owner during this period + ownershipType: string; // Type of ownership (e.g., freehold, leasehold) + description: string; // Description of the transaction or change + periodStart: string; // Start date of this ownership/period + transactionDate: string; // Date of the transaction + createdAt: string; // Creation timestamp +} \ No newline at end of file diff --git a/frontend/mobile-ui/src/app/features/Citizen/models/IGRSAdditionalDetails.model.ts b/frontend/mobile-ui/src/app/features/Citizen/models/IGRSAdditionalDetails.model.ts new file mode 100644 index 0000000..56113a0 --- /dev/null +++ b/frontend/mobile-ui/src/app/features/Citizen/models/IGRSAdditionalDetails.model.ts @@ -0,0 +1,10 @@ +// Represents additional amenities/details for IGRS (Integrated Grievance Redressal System) +export type ISGRAdditionalDetails = { + lifts: boolean; // Whether lifts are available + toilet: boolean; // Whether toilets are available + watertap: boolean; // Whether water tap is available + electricity: boolean; // Whether electricity is available + cableConnection: boolean; // Whether cable connection is available + waterHarvesting: boolean; // Whether water harvesting is available + attachedBathroom: boolean; // Whether attached bathroom is available +} \ No newline at end of file diff --git a/frontend/mobile-ui/src/app/features/Citizen/models/IGRSDetails.model.ts b/frontend/mobile-ui/src/app/features/Citizen/models/IGRSDetails.model.ts new file mode 100644 index 0000000..2d555f3 --- /dev/null +++ b/frontend/mobile-ui/src/app/features/Citizen/models/IGRSDetails.model.ts @@ -0,0 +1,9 @@ +// Represents IGRS (Integrated Grievance Redressal System) property details +export type ISGRDetails = { + doorNoTo: string; // Door number (to) + igrsWard: string; // IGRS ward + igrsBlock: string; // IGRS block + doorNoFrom: string; // Door number (from) + habitation: string; // Habitation name + igrsLocality: string; // IGRS locality +} \ No newline at end of file diff --git a/frontend/mobile-ui/src/app/features/Citizen/models/License.model.ts b/frontend/mobile-ui/src/app/features/Citizen/models/License.model.ts new file mode 100644 index 0000000..e266fee --- /dev/null +++ b/frontend/mobile-ui/src/app/features/Citizen/models/License.model.ts @@ -0,0 +1,11 @@ +// Represents a license associated with a property +export type License = { + id: string; // Unique license identifier + propertyId: string; // Linked property ID + licenseNo: string; // License number + licenseType: string; // Type of license (e.g., trade, construction) + status: string; // License status (e.g., active, expired) + issuedDate: string; // Date when the license was issued + expiryDate: string; // Date when the license expires + createdAt: string; // Creation timestamp +} \ No newline at end of file diff --git a/frontend/mobile-ui/src/app/features/Citizen/models/Location.model.ts b/frontend/mobile-ui/src/app/features/Citizen/models/Location.model.ts new file mode 100644 index 0000000..8c135dd --- /dev/null +++ b/frontend/mobile-ui/src/app/features/Citizen/models/Location.model.ts @@ -0,0 +1,9 @@ +// Represents location information for a property or event +export type LocationData = { + address: string; // Full address as a string + coordinates: { + lat: number; // Latitude value + lng: number; // Longitude value + }; + timestamp: string; // Timestamp when the location was recorded +} \ No newline at end of file diff --git a/frontend/mobile-ui/src/app/features/Citizen/models/Owner.model.ts b/frontend/mobile-ui/src/app/features/Citizen/models/Owner.model.ts new file mode 100644 index 0000000..a62b953 --- /dev/null +++ b/frontend/mobile-ui/src/app/features/Citizen/models/Owner.model.ts @@ -0,0 +1,10 @@ +// Represents an owner of a property +export type Owner = { + email: string; // Owner's email address + gender: string; // Owner's gender + mobile: string; // Owner's mobile number + aadhaar: string; // Owner's Aadhaar number (unique ID in India) + guardian: string; // Name of the guardian (if applicable) + ownerName: string; // Name of the property owner + guardianRelationship: string; // Relationship to the guardian +} \ No newline at end of file diff --git a/frontend/mobile-ui/src/app/features/Citizen/models/Property.model.ts b/frontend/mobile-ui/src/app/features/Citizen/models/Property.model.ts new file mode 100644 index 0000000..a0f2f17 --- /dev/null +++ b/frontend/mobile-ui/src/app/features/Citizen/models/Property.model.ts @@ -0,0 +1,56 @@ +import type { AssessmentDetails } from "./AssessmentDetails.model"; +import type { Bill } from "./Bill.model"; +import type { ConstructionDetails } from "./ConstructionDetails.model"; +import type { Document } from "./Document.model"; +import type { FloorDetails } from "./FloorDetails.model"; +import type { HistoryItem } from "./History.model"; +import type { ISGRAdditionalDetails } from "./IGRSAdditionalDetails.model"; +import type { ISGRDetails } from "./IGRSDetails.model"; +import type { License } from "./License.model"; +import type { LocationData } from "./Location.model"; +import type { Owner } from "./Owner.model"; +import type { PropertyAddress } from "./PropertyAddress.model"; + +// Represents a property and all its associated details +export interface Property { + apartmentName: string; // Name of the apartment (if applicable) + approvedUse: string; // Approved use of the property (e.g., residential, commercial) + assessmentDetails: AssessmentDetails; // Assessment details for the property + bills: Bill[]; // List of bills associated with the property + billsAmount: number; // Total amount of all bills + billsDue: number; // Total due amount + builtUpArea: string; // Built-up area of the property + categoryOfOwnership: string; // Category of ownership (e.g., freehold, leasehold) + constructionDetails: ConstructionDetails; // Construction details + constructionYear: number; // Year of construction + coverage: string; // Coverage area + currentUse: string; // Current use of the property + district: string; // District where the property is located + documents: Document[]; // List of property-related documents + enumerationProgress: number; // Progress of property enumeration (e.g., for surveys) + floors: FloorDetails[]; // Details for each floor + frontSetback: string; // Front setback distance + fsi: string; // Floor Space Index + history: HistoryItem[]; // Ownership or transaction history + hobli: string; // Hobli (administrative division) + id: string; // Unique property identifier + isgrAdditionalDetails: ISGRAdditionalDetails; // Additional IGRS details + isgrDetails: ISGRDetails; // IGRS details + issuedLicenses: number; // Number of licenses issued + licenses: License[]; // List of licenses + locationData: LocationData; // Location information + owners: Owner[]; // List of property owners + plotArea: string; // Plot area + propertyAddress: PropertyAddress; // Address details + propertyType: string; // Type/category of property + propertyValue: string; // Value of the property + rearSetback: string; // Rear setback distance + sideSetback: string; // Side setback distance + subdivision: string; // Subdivision name/number + surveyNumber: string; // Survey number + taluk: string; // Taluk (administrative division) + utilities: any; // Utilities associated with the property + village: string; // Village name + ward: string; // Ward number or name + zoning: string; // Zoning information +} \ No newline at end of file diff --git a/frontend/mobile-ui/src/app/features/Citizen/models/PropertyAddress.model.ts b/frontend/mobile-ui/src/app/features/Citizen/models/PropertyAddress.model.ts new file mode 100644 index 0000000..b83d5da --- /dev/null +++ b/frontend/mobile-ui/src/app/features/Citizen/models/PropertyAddress.model.ts @@ -0,0 +1,12 @@ +// Represents the address details for a property +export type PropertyAddress = { + street: string; // Street name + wardNo: string; // Ward number + zoneNo: string; // Zone number + blockNo: string; // Block number + pincode: string; // Postal code + locality: string; // Locality or neighborhood + electionWard: string; // Election ward + secretariatWard: string; // Secretariat ward + isCorrespondenceAddressDifferent: boolean; // Whether correspondence address is different +} \ No newline at end of file diff --git a/frontend/mobile-ui/src/app/features/Citizen/models/PropertyContext.model.ts b/frontend/mobile-ui/src/app/features/Citizen/models/PropertyContext.model.ts new file mode 100644 index 0000000..d98983a --- /dev/null +++ b/frontend/mobile-ui/src/app/features/Citizen/models/PropertyContext.model.ts @@ -0,0 +1,11 @@ +import type { Property } from "./Property.model"; + +// Represents the context type for managing property state in React context +export interface PropertyContextType { + properties: Property[]; // List of all properties + selectedProperty: Property | null; // Currently selected property + setSelectedProperty: (property: Property | null) => void; // Function to set the selected property + reloadProperties: () => void; // Function to reload property list + loading: boolean; // Loading state for property operations + error: string | null; // Error message, if any +} \ No newline at end of file diff --git a/frontend/mobile-ui/src/app/features/Citizen/models/PropertyState.model.ts b/frontend/mobile-ui/src/app/features/Citizen/models/PropertyState.model.ts new file mode 100644 index 0000000..5f3c7bb --- /dev/null +++ b/frontend/mobile-ui/src/app/features/Citizen/models/PropertyState.model.ts @@ -0,0 +1,6 @@ +import type { Property } from "./Property.model"; + +// Represents the state for property selection (e.g., in Redux or React context) +export interface PropertyState { + selectedProperty: Property | null; // Currently selected property, or null if none +} \ No newline at end of file diff --git a/frontend/mobile-ui/src/app/features/Citizen/models/UrgentAttention.model.ts b/frontend/mobile-ui/src/app/features/Citizen/models/UrgentAttention.model.ts new file mode 100644 index 0000000..2254b38 --- /dev/null +++ b/frontend/mobile-ui/src/app/features/Citizen/models/UrgentAttention.model.ts @@ -0,0 +1,15 @@ + +// Status of an urgent attention item +export type UrgentAttentionStatus = "success" | "pending" | "failed"; + +// Type of urgent attention required +export type UrgentAttentionType = "casual" | "immediate"; + +// Represents an item requiring urgent attention on the citizen dashboard +export interface UrgentAttention { + id: number; // Unique identifier for the urgent attention item + type: UrgentAttentionType; // Type of attention required (casual or immediate) + message: string; // Message or description of the issue + date: string; // ISO date string for when the attention is required + status: UrgentAttentionStatus; // Status of the attention item (success, pending, failed) +} \ No newline at end of file diff --git a/frontend/mobile-ui/src/app/features/PropertyForm/api/documentInfo.api.ts b/frontend/mobile-ui/src/app/features/PropertyForm/api/documentInfo.api.ts new file mode 100644 index 0000000..cc9123e --- /dev/null +++ b/frontend/mobile-ui/src/app/features/PropertyForm/api/documentInfo.api.ts @@ -0,0 +1,49 @@ +// documentInfo.api.ts +// This file defines RTK Query API endpoints for managing document info related to property forms. +// Endpoints include create, fetch by property ID, and update document info. +// Uses Redux Toolkit Query for data fetching and mutation, with tag-based cache management. +// Types: +// DocumentInfoRequest: request payload for document info +// DocumentInfoResponse: response payload for create/update +// DocumentInfoGetResponse: response payload for fetch + +import { apiSlice } from '../../../../redux/apiSlice'; +import { TAG_TYPES } from '../../../../redux/tagTypes'; +import type { DocumentInfoRequest, DocumentInfoResponse, DocumentInfoGetResponse } from '../models/documentInfo.model'; + +export const documentInfoApi = apiSlice.injectEndpoints({ + endpoints: (builder) => ({ + // Mutation to create new document info for a property + createDocumentInfo: builder.mutation({ + query: (body) => ({ + url: '/v1/additional-property-details', + method: 'POST', + body, + }), + invalidatesTags: [TAG_TYPES.DOCUMENT_INFO], + }), + // Query to fetch document info by property ID + getDocumentInfoByPropertyId: builder.query({ + query: (propertyId) => ({ + url: `/v1/additional-property-details/property/${propertyId}?fieldName=DocumentInfo`, + method: 'GET', + }), + providesTags: [TAG_TYPES.DOCUMENT_INFO], + }), + // Mutation to update document info by document ID + updateDocumentInfo: builder.mutation({ + query: ({ documentId, body }) => ({ + url: `/v1/additional-property-details/${documentId}`, + method: 'PUT', + body, + }), + invalidatesTags: [TAG_TYPES.DOCUMENT_INFO], + }), + }), +}); + +export const { + useCreateDocumentInfoMutation, + useGetDocumentInfoByPropertyIdQuery, + useUpdateDocumentInfoMutation, +} = documentInfoApi; \ No newline at end of file diff --git a/frontend/mobile-ui/src/app/features/PropertyForm/api/documentUpload.api.ts b/frontend/mobile-ui/src/app/features/PropertyForm/api/documentUpload.api.ts new file mode 100644 index 0000000..7395775 --- /dev/null +++ b/frontend/mobile-ui/src/app/features/PropertyForm/api/documentUpload.api.ts @@ -0,0 +1,56 @@ +// documentUpload.api.ts +// This file defines RTK Query API endpoints for managing document uploads related to property forms. +// Endpoints include fetch, create, update, and delete document upload details. +// Uses Redux Toolkit Query for data fetching and mutation, with tag-based cache management. +// Types: +// DocumentUploadDetailsRequest: request payload for document upload +// DocumentUploadDetailsResponse: response payload for upload operations + +import { apiSlice } from '../../../../redux/apiSlice'; +import { TAG_TYPES } from '../../../../redux/tagTypes'; +import type { DocumentUploadDetailsRequest, DocumentUploadDetailsResponse } from '../models/documentsUpload.model'; + +export const documentsUploadDetailsApi = apiSlice.injectEndpoints({ + endpoints: (builder) => ({ + // Query to fetch document upload details by property ID + getDocumentsUploadDetailsByPropertyId: builder.query({ + query: (propertyId) => ({ + url: `/v1/documents/property/${propertyId}`, + method: 'GET', + }), + providesTags:[TAG_TYPES.DOCUMENT] + }), + // Mutation to create new document upload details + createDocumentUploadDetails: builder.mutation({ + query: (body) => ({ + url: '/v1/documents', + method: 'POST', + body, // Send array directly + }), + invalidatesTags:[TAG_TYPES.DOCUMENT] + }), + // Mutation to update document upload details by document ID + updateDocumentUploadDetails: builder.mutation({ + query: ({ document_id, body }) => ({ + url: `/v1/documents/${document_id}`, + method: 'PUT', + body, + }), + }), + // Mutation to delete document upload details by document ID + deleteDocumentUploadDetails: builder.mutation<{ message: string }, string>({ + query: (documentId) => ({ + url: `/v1/documents/${documentId}`, + method: 'DELETE', + }), + invalidatesTags:[TAG_TYPES.DOCUMENT] + }), + }), +}); + +export const { + useGetDocumentsUploadDetailsByPropertyIdQuery, + useCreateDocumentUploadDetailsMutation, + useUpdateDocumentUploadDetailsMutation, + useDeleteDocumentUploadDetailsMutation, +} = documentsUploadDetailsApi; \ No newline at end of file diff --git a/frontend/mobile-ui/src/app/features/PropertyForm/components/ConstructionDetail/ConstructionDropdown.tsx b/frontend/mobile-ui/src/app/features/PropertyForm/components/ConstructionDetail/ConstructionDropdown.tsx new file mode 100644 index 0000000..4c11710 --- /dev/null +++ b/frontend/mobile-ui/src/app/features/PropertyForm/components/ConstructionDetail/ConstructionDropdown.tsx @@ -0,0 +1,163 @@ +// CustomDropdown is a reusable dropdown component for construction detail forms. +// It supports validation, custom styling, and controlled open/close behavior. +import React, { useRef } from 'react'; +import Box from '@mui/material/Box'; +import FormControl from '@mui/material/FormControl'; +import Select from '@mui/material/Select'; +import type { SelectChangeEvent } from '@mui/material/Select'; +import MenuItem from '@mui/material/MenuItem'; +import Typography from '@mui/material/Typography'; +import type { SxProps, Theme } from '@mui/material'; + +// Option type for dropdown items +export type DropdownOption = { id: string | number; label: string }; + +// Props for the CustomDropdown component +interface CustomDropdownProps { + label: string; // Field label + name: string; // Field name (for form handling) + value?: string; // Selected value + options: DropdownOption[]; // List of dropdown options + showDropdown: boolean; // Whether the dropdown is open + setShowDropdown: (b: boolean) => void; // Function to control dropdown open state + onSelect: (field: string, value: string) => void; // Callback when an option is selected + // Called by the dropdown before opening so parent can close others + closeOtherDropdowns?: () => void; + selectText?: string; // Placeholder text + required?: boolean; // Whether the field is required + error?: string; // Error message (if any) + touched?: boolean; // Whether the field has been touched + sx?: SxProps; // Custom styles + // Called when dropdown is closed (used by parent to mark touched/validate) + onBlur?: () => void; +} + +// Style objects for dropdown and label +const containerSx = { width: '100%', mb: 2 }; +const labelSx = { + fontSize: 14, + fontWeight: 400, + color: '#333333', + mb: '6px', + textAlign: 'left' as const, +}; +const formControlSx = { + width: '100%', + '& .MuiOutlinedInput-root': { borderRadius: 2 }, +}; +const placeholderStyle: React.CSSProperties = { color: '#9E9E9E' }; + +const CustomDropdown: React.FC = ({ + label, + name, + value, + options, + showDropdown, + setShowDropdown, + onSelect, + closeOtherDropdowns, + selectText = 'Select', + required = false, + error, + touched, + sx, + onBlur, +}) => { + // Use empty string if value is undefined + const safeValue = value ?? ''; + const justSelectedRef = useRef(false); + + // Open dropdown and close others if needed + const handleOpen = () => { + if (closeOtherDropdowns) closeOtherDropdowns(); + setShowDropdown(true); + }; + + // Close dropdown + const handleClose = () => { + // If the close is happening immediately after a selection, skip onBlur. + if (justSelectedRef.current) { + justSelectedRef.current = false; + setShowDropdown(false); + return; + } + + if (onBlur) onBlur(); + setShowDropdown(false); + }; + + // Handle selection change + const handleChange = (e: SelectChangeEvent) => { + const selected = e.target.value as string; + // mark that the close that follows is caused by selection + justSelectedRef.current = true; + onSelect(name, selected); + // close will be handled; we still call setShowDropdown(false) to make UI responsive + setShowDropdown(false); + }; + + // Render dropdown UI + return ( + + {/* Field label with required indicator */} + + {label} + {required ? * : null} + + :{' '} + + + + + + + + {/* Error message display */} +
+ {touched && error ? error : '\u00A0'} +
+
+ ); +}; + +// Export CustomDropdown for use in construction detail forms +export default CustomDropdown; \ No newline at end of file diff --git a/frontend/mobile-ui/src/app/features/PropertyForm/components/CountIncrementors.tsx b/frontend/mobile-ui/src/app/features/PropertyForm/components/CountIncrementors.tsx new file mode 100644 index 0000000..0f24f72 --- /dev/null +++ b/frontend/mobile-ui/src/app/features/PropertyForm/components/CountIncrementors.tsx @@ -0,0 +1,130 @@ +// CountIncrementor component: input with increment/decrement buttons for numeric values +import React from 'react'; +import { Box, TextField, IconButton, Typography } from '@mui/material'; +import ArrowDropUpIcon from '@mui/icons-material/ArrowDropUp'; +import ArrowDropDownIcon from '@mui/icons-material/ArrowDropDown'; +import InputAdornment from '@mui/material/InputAdornment'; + +// Props for CountIncrementor: label, value, setter, min/max +interface CountIncrementorProps { + label: string; + value: number; + setValue: (val: number) => void; + min?: number; + max?: number; +} + +// Main component for count increment/decrement input +const CountIncrementor: React.FC = ({ + label, + value, + setValue, + min = 0, + max = 100 +}) => { + // Handle manual input change in the text field + const handleChange = (e: React.ChangeEvent) => { + const val = e.target.value === "" ? "" : Number(e.target.value); + if (val === "" || (val >= min && val <= max)) setValue(val === "" ? 0 : val); + }; + + // Increment value (up arrow) + const inc = () => { + if (value === 0 && min <= 1) setValue(1); + else if (typeof value === "number" && value < max) setValue(value + 1); + }; + // Decrement value (down arrow) + const dec = () => { + if (typeof value === "number" && value > min) setValue(value - 1); + else if (value === 0 && min < 0) setValue(min); + }; + + // Render label, input, and increment/decrement buttons + return ( + + + {label} : + + + + = max : false} + tabIndex={-1} + > + + + + + + + + ), + }} + sx={{ + borderRadius: "10px", + background: "#fff", + // remove default number input arrows + "& input[type=number]::-webkit-outer-spin-button, & input[type=number]::-webkit-inner-spin-button": { + WebkitAppearance: "none", + margin: 0 + }, + "& input[type=number]": { + MozAppearance: "textfield" + }, + fontSize: 22, + fontWeight: 400, + color: "#b0b0b0", + "& .MuiOutlinedInput-root": { + borderRadius: "10px", + height: "48px", + minWidth: "160px", + fontSize: 16, + bgcolor: "#fff", + borderColor: "#616a6e", + "& fieldset": { + borderColor: "#616a6e", + }, + "&:hover fieldset": { + borderColor: "#b04c00", + }, + "&.Mui-focused fieldset": { + borderColor: "#b04c00", + }, + }, + "&::placeholder": { + fontSize: 20, + color: "#b0b0b0", + opacity: 1, + }, + }} + /> + + ); +}; + +export default CountIncrementor; \ No newline at end of file diff --git a/frontend/mobile-ui/src/app/features/PropertyForm/components/FloorDetail/FloorCard.tsx b/frontend/mobile-ui/src/app/features/PropertyForm/components/FloorDetail/FloorCard.tsx new file mode 100644 index 0000000..026cb26 --- /dev/null +++ b/frontend/mobile-ui/src/app/features/PropertyForm/components/FloorDetail/FloorCard.tsx @@ -0,0 +1,96 @@ + +// Card summarizing a single floor's details in the property form, with edit/delete actions. + +import React from 'react'; +import MeetingRoomOutlinedIcon from '@mui/icons-material/MeetingRoomOutlined'; +import deleteIcon from '../../../../assets/Agent/delete.svg'; +import editSquare from '../../../../assets/Agent/edit_square.svg'; +import type { FloorDetails } from '../../../../../context/PropertyFormContext'; +import { useFloorDetailsLocalization } from '../../../../../services/AgentLocalisation/localisation-floor-details'; +import '../../../../../styles/FloorSection.css' + +interface FloorCardProps { + floor: FloorDetails; + index: number; + onEdit: (floor: FloorDetails) => void; + onDelete: (index: number) => void; +} + +const FloorCard: React.FC = ({ floor, index, onEdit, onDelete }) => { + // Get localized labels for floor details + const { + floorText, + classificationText, + usageText, + plinthAreaLabel, + lengthLabel, + breadthLabel, + deleteText, + } = useFloorDetailsLocalization(); + + // Render floor card UI + return ( +
+ {/* Icon representing a floor */} + +
+ {/* Floor details */} +
+ {floorText}: {floor.floorNumber} +
+
+ {classificationText}: {floor.buildingClassification} +
+
+ {usageText}: {floor.natureOfUsage} +
+
+ {plinthAreaLabel}: {floor.plinthArea} +
+
+ {lengthLabel}: {floor.length} +
+
+ {breadthLabel}: {floor.breadth} +
+
+ {/* Edit and delete buttons for the floor */} +
+ + +
+
+ ); +}; + +// Export FloorCard for use in floor details forms +export default FloorCard; \ No newline at end of file diff --git a/frontend/mobile-ui/src/app/features/PropertyForm/components/IGRSDetail/IGRSFormTextFiled.tsx b/frontend/mobile-ui/src/app/features/PropertyForm/components/IGRSDetail/IGRSFormTextFiled.tsx new file mode 100644 index 0000000..cba8bae --- /dev/null +++ b/frontend/mobile-ui/src/app/features/PropertyForm/components/IGRSDetail/IGRSFormTextFiled.tsx @@ -0,0 +1,98 @@ + +// Custom text field for IGRS details in property forms. Supports validation, placeholder, error display, and style overrides. + +import React from 'react'; +import TextField from '@mui/material/TextField'; +import Typography from '@mui/material/Typography'; + +interface FormTextFieldProps { + label: string; + // allow undefined values safely + value?: string; + onChange: (value: string) => void; + onBlur?: () => void; + onKeyPress?: (e: React.KeyboardEvent) => void; + placeholder?: string; + type?: 'text' | 'number'; + required?: boolean; + error?: string; + touched?: boolean; + sx?: any; + inputProps?: React.InputHTMLAttributes; +} + +// Style object for label +const labelSx = { + fontSize: 14, + fontWeight: 400, + color: '#333333', + marginBottom: '6px', + textAlign: 'left' as const, +}; + +const FormTextField: React.FC = ({ + label, + value, + onChange, + onBlur, + onKeyPress, + placeholder, + type = 'text', + required = false, + error, + touched, + inputProps, + sx, +}) => { + // Ensure we never pass undefined to TextField value prop + const safeValue = value ?? ''; + + // Render text field UI + return ( +
+ {/* Field label with required indicator */} + + {label} + {required ? * : null} + : + + + onChange(e.target.value)} + onBlur={onBlur} + onKeyPress={onKeyPress} + placeholder={placeholder ?? ''} + type={type} + inputProps={{ inputMode: type === 'number' ? 'decimal' : 'text', ...inputProps }} + error={!!(touched && error)} + helperText={touched && error ? error : '\u00A0'} + FormHelperTextProps={{ sx: { minHeight: 20 } }} + sx={{ + fontFamily: 'Roboto, sans-serif !important', + '& .MuiOutlinedInput-input': { + fontFamily: 'Roboto, sans-serif', + boxSizing: 'border-box !important', + minHeight: '48px', + borderRadius: '10px', + }, + '& .MuiOutlinedInput-root': { + borderRadius: '10px', + fontSize: '16px !important', + boxSizing: 'border-box !important', + }, + '& .MuiOutlinedInput-notchedOutline': { + borderColor: '#C4C4C4 !important', + borderRadius: '10px !important', + }, + ...sx, + }} + /> +
+ ); +}; + +// Export FormTextField for use in IGRS detail forms +export default FormTextField; diff --git a/frontend/mobile-ui/src/app/features/PropertyForm/components/IGRSDetail/IGRSdropdown.tsx b/frontend/mobile-ui/src/app/features/PropertyForm/components/IGRSDetail/IGRSdropdown.tsx new file mode 100644 index 0000000..43b622b --- /dev/null +++ b/frontend/mobile-ui/src/app/features/PropertyForm/components/IGRSDetail/IGRSdropdown.tsx @@ -0,0 +1,172 @@ + +// Custom dropdown for IGRS details in property forms. Supports validation, placeholder, error display, and controlled open/close. + +import React, { useRef } from 'react'; +import Box from '@mui/material/Box'; +import FormControl from '@mui/material/FormControl'; +import Select from '@mui/material/Select'; +import type { SelectChangeEvent } from '@mui/material/Select'; +import MenuItem from '@mui/material/MenuItem'; +import Typography from '@mui/material/Typography'; +import type {SxProps, Theme} from '@mui/material/styles'; + +export type DropdownOption = { id: string | number; label: string }; + +interface CustomDropdownProps { + label: string; + name: string; + value?: string; + options: DropdownOption[]; + showDropdown: boolean; + setShowDropdown: (b: boolean) => void; + onSelect: (field: string, value: string) => void; + closeOtherDropdowns?: () => void; + selectText?: string; + required?: boolean; + error?: string; + touched?: boolean; + sx?: SxProps; + onBlur?: () => void; +} + +// Style objects for dropdown and label +const containerSx = { + width: '100%', + marginBottom: "2px", +}; + +const labelSx = { + fontSize: 14, + fontWeight: 400, + color: '#333333', + marginBottom: '1.4px', + textAlign: 'left' as const, +}; + +const formControlSx = { + width: '100%', + Height: "14px", + '& .MuiOutlinedInput-root': { + borderRadius: 2, + }, +}; + +const placeholderStyle: React.CSSProperties = { + color: '#9E9E9E', +}; + +const CustomDropdown: React.FC = ({ + label, + name, + value, + options, + showDropdown, + setShowDropdown, + onSelect, + closeOtherDropdowns, + selectText = 'Select', + required = false, + error, + touched, + onBlur, +}) => { + // Ref to track if selection is happening (to distinguish blur from selection) + const isSelectingRef = useRef(false); + + // Open dropdown and close others if needed + const handleOpen = () => { + if (closeOtherDropdowns) closeOtherDropdowns(); + setShowDropdown(true); + isSelectingRef.current = false; + }; + + // Close dropdown and trigger blur if no selection + const handleClose = () => { + setShowDropdown(false); + // Wait a brief moment to see if onChange fires (indicating a selection was made) + setTimeout(() => { + if (onBlur && !isSelectingRef.current) { + onBlur(); + } + isSelectingRef.current = false; // Reset for next time + }, 0); + }; + + // Handle selection change + const handleChange = (event: SelectChangeEvent) => { + const selected = event.target.value as string; + isSelectingRef.current = true; // Mark that selection is happening + onSelect(name, selected); + setShowDropdown(false); + }; + + // Use empty string if value is undefined + const safeValue = value ?? ''; + + // Render dropdown UI + return ( + + {/* Field label with required indicator */} + + {label} + {required ? * : null} + + : + + + + + + + + {/* Error message display */} +
+ {touched && error ? error : '\u00A0'} +
+
+ ); +}; + +// Export CustomDropdown for use in IGRS detail forms +export default CustomDropdown; \ No newline at end of file diff --git a/frontend/mobile-ui/src/app/features/PropertyForm/components/OwnerDetail/OwnerCard.tsx b/frontend/mobile-ui/src/app/features/PropertyForm/components/OwnerDetail/OwnerCard.tsx new file mode 100644 index 0000000..1887b7c --- /dev/null +++ b/frontend/mobile-ui/src/app/features/PropertyForm/components/OwnerDetail/OwnerCard.tsx @@ -0,0 +1,84 @@ +// OwnerCard.tsx +// This component displays a summary card for a property owner in the property form. +// Shows owner avatar, name, type (primary/secondary), and provides delete/view actions. +// Props: +// name: Owner's name +// isPrimary: Whether the owner is the primary owner +// onDelete: Callback to delete the owner +// onViewOwners: Callback to view all owners +// primaryOwnerText: Label for primary owner +// ownerText: Label for secondary owner +// nameText: Label for name field +// viewOwnersText: Label for view owners button +// Used in: Owner details section of property forms + +import React from 'react'; +import '../../../../../styles/OwnerCard.css'; +import accountCircle from '../../../../assets/Agent/account_circle.svg'; +import deleteIcon from '../../../../assets/Agent/delete.svg'; + +interface OwnerCardProps { + name: string; + isPrimary?: boolean; + onDelete?: () => void; + onViewOwners?: () => void; + primaryOwnerText?: string; + ownerText?: string; + nameText?: string; + viewOwnersText?: string; +} + +const OwnerCard: React.FC = ({ + name, + isPrimary = false, + onDelete, + onViewOwners, + primaryOwnerText = 'Primary Owner', + ownerText = 'Owner', + nameText = 'Name', + viewOwnersText = 'View Owners', +}) => ( + // Render owner summary card UI +
+
+
+ {/* Owner avatar icon */} + Owner +
+
+ {/* Owner type (primary/secondary) */} +
{isPrimary ? primaryOwnerText : ownerText}
+ {/* Owner name */} +
{nameText}: {name}
+
+ {/* Delete owner button if callback provided */} + {onDelete && ( + + )} +
+ {/* View owners button if callback provided */} + {onViewOwners && ( + + )} +
+); + +// Export OwnerCard for use in owner details forms +export default OwnerCard; \ No newline at end of file diff --git a/frontend/mobile-ui/src/app/features/PropertyForm/components/OwnerDetail/OwnerCardDetail.tsx b/frontend/mobile-ui/src/app/features/PropertyForm/components/OwnerDetail/OwnerCardDetail.tsx new file mode 100644 index 0000000..a99a2f2 --- /dev/null +++ b/frontend/mobile-ui/src/app/features/PropertyForm/components/OwnerDetail/OwnerCardDetail.tsx @@ -0,0 +1,102 @@ + +// Card displaying a property owner's details in the property form, with edit/delete actions. + +import React from 'react'; +import '../../../../../styles/OwnerCardDetail.css'; +import accountCircle from '../../../../assets/Agent/account_circle.svg'; +import deleteIcon from '../../../../assets/Agent/delete.svg'; +import editSquare from '../../../../assets/Agent/edit_square.svg'; + +interface OwnerCardProps { + name: string; + isPrimary?: boolean; + onDelete?: () => void; + onViewOwners?: () => void; + isDetailed: boolean; + aadhar?: string; + mobile?: string; + email?: string; + guardian?: string; + guardianRelationship?: string; + nameText: string; + mobileNumberLabel: string; + aadhaarLabel: string; + emailLabel: string; + guardianLabel: string; + primaryOwnerText: string; + onEdit?: () => void; +} + +const OwnerCardDetail: React.FC = ({ + name, + isPrimary = false, + onDelete, + isDetailed = false, + aadhar, + mobile, + email, + guardian, + guardianRelationship, + // nameText, + // mobileNumberLabel, + // aadhaarLabel, + // emailLabel, + guardianLabel, + primaryOwnerText, + onEdit, +}) => { + // Render owner detailed card UI + return ( +
+
+ {/* Owner avatar icon */} +
+ Owner +
+ {/* Owner info and details */} +
+ {/* Owner type (primary/secondary) */} +
+ {isPrimary ? primaryOwnerText : 'Secondary Owner'} +
+ {/* Owner details list */} +
+
Name: {name}
+ {isDetailed && ( + <> + {aadhar &&
Aadhar: {aadhar}
} + {mobile &&
Mobile: +91 {mobile}
} + {email &&
Email: {email}
} + {(guardian || guardianRelationship) && ( +
+ {guardianLabel}: {guardian}{guardianRelationship ? ` (${guardianRelationship})` : ''} +
+ )} + + )} +
+
+ {/* Top-right Delete Button if callback provided */} + {onDelete && ( + + )} + {/* Bottom-right Edit Button */} + +
+
+ ); +}; + +// Export OwnerCardDetail for use in owner details forms +export default OwnerCardDetail; \ No newline at end of file diff --git a/frontend/mobile-ui/src/app/features/PropertyForm/models/AssessmentDetails.model.ts b/frontend/mobile-ui/src/app/features/PropertyForm/models/AssessmentDetails.model.ts new file mode 100644 index 0000000..e34131b --- /dev/null +++ b/frontend/mobile-ui/src/app/features/PropertyForm/models/AssessmentDetails.model.ts @@ -0,0 +1,28 @@ +// Request payload for submitting assessment details +export interface AssessmentDetailsRequest { + reasonOfCreation: string; // Reason for creating the assessment + occupancyCertificateNumber: string; // Occupancy certificate number + occupancyCertificateDate: string; // Date of occupancy certificate + extentOfSite: string; // Area/extent of the site + isLandUnderneathBuilding: string; // Whether land is underneath building + isUnspecifiedShare: boolean; // Whether the property has an unspecified share + propertyId: string; // Linked property ID +} + +// Response structure for assessment details API +export interface AssessmentDetailsResponse { + success: boolean; // Indicates if the API call was successful + message: string; // Response message + data: { + ID: string; // Unique assessment ID + ReasonOfCreation: string; // Reason for creation + OccupancyCertificateNumber: string; // Occupancy certificate number + OccupancyCertificateDate: string; // Date of occupancy certificate + ExtentOfSite: string; // Site area/extent + IsLandUnderneathBuilding: string; // Whether land is underneath building + IsUnspecifiedShare: boolean; // Whether property has unspecified share + PropertyID: string; // Linked property ID + CreatedAt: string; // Creation timestamp + UpdatedAt: string; // Last update timestamp + }; +} \ No newline at end of file diff --git a/frontend/mobile-ui/src/app/features/PropertyForm/models/IgrsDetails.model.ts b/frontend/mobile-ui/src/app/features/PropertyForm/models/IgrsDetails.model.ts new file mode 100644 index 0000000..8281ceb --- /dev/null +++ b/frontend/mobile-ui/src/app/features/PropertyForm/models/IgrsDetails.model.ts @@ -0,0 +1,54 @@ +// Request payload for creating IGRS details +export interface IgrsDetailsRequest { + propertyId: string; // Linked property ID + habitation: string; // Habitation name + igrsWard?: string; // IGRS ward (optional) + igrsLocality?: string; // IGRS locality (optional) + igrsBlock?: string; // IGRS block (optional) + doorNoFrom?: string; // Door number (from, optional) + doorNoTo?: string; // Door number (to, optional) + igrsClassification?: string; // IGRS classification (optional) + builtUpAreaPct?: number; // Built-up area percentage (optional) + frontSetback?: number; // Front setback (optional) + rearSetback?: number; // Rear setback (optional) + sideSetback?: number; // Side setback (optional) + totalPlinthArea?: number; // Total plinth area (optional) +} + +// Request payload for updating IGRS details (all fields optional) +export interface IgrsDetailsUpdateRequest { + propertyId?: string; // Linked property ID (optional) + habitation?: string; // Habitation name (optional) + igrsWard?: string; // IGRS ward (optional) + igrsLocality?: string; // IGRS locality (optional) + igrsBlock?: string; // IGRS block (optional) + doorNoFrom?: string; // Door number (from, optional) + doorNoTo?: string; // Door number (to, optional) + igrsClassification?: string; // IGRS classification (optional) + builtUpAreaPct?: number; // Built-up area percentage (optional) + totalPlinthArea?: number; // Total plinth area (optional) +} + +// Response structure for IGRS details API +export interface IgrsDetailsResponse { + data: { + id: string; // Unique IGRS details ID + habitation: string; // Habitation name + igrsWard?: string; // IGRS ward (optional) + igrsLocality?: string; // IGRS locality (optional) + igrsBlock?: string; // IGRS block (optional) + doorNoFrom?: string; // Door number (from, optional) + doorNoTo?: string; // Door number (to, optional) + igrsClassification?: string; // IGRS classification (optional) + builtUpAreaPct?: number; // Built-up area percentage (optional) + frontSetback?: number; // Front setback (optional) + rearSetback?: number; // Rear setback (optional) + sideSetback?: number; // Side setback (optional) + totalPlinthArea?: number; // Total plinth area (optional) + createdAt: string; // Creation timestamp + updatedAt: string; // Last update timestamp + PropertyID: string; // Linked property ID + }; + message: string; // Response message + success: boolean; // Indicates if the API call was successful +} \ No newline at end of file diff --git a/frontend/mobile-ui/src/app/features/PropertyForm/models/documentInfo.model.ts b/frontend/mobile-ui/src/app/features/PropertyForm/models/documentInfo.model.ts new file mode 100644 index 0000000..907cb03 --- /dev/null +++ b/frontend/mobile-ui/src/app/features/PropertyForm/models/documentInfo.model.ts @@ -0,0 +1,41 @@ +// Represents the value of a document info field +export interface DocumentInfoFieldValue { + DocumentType: number | string; // Document type (can be number or string) + serialNo: number; // Serial number of the document + revenueDocumentNo: number; // Revenue document number +} + +// Request payload for submitting document info +export interface DocumentInfoRequest { + fieldName: string; // Name of the document info field + fieldValue: DocumentInfoFieldValue; // Value of the field + propertyId: string; // Linked property ID +} + +// Response structure for document info API (single item) +export interface DocumentInfoResponse { + success: boolean; // Indicates if the API call was successful + message: string; // Response message + data?: { + ID: string; // Unique document info ID + FieldName: string; // Name of the field + fieldValue: DocumentInfoFieldValue; // Value of the field + PropertyID: string; // Linked property ID + CreatedAt: string; // Creation timestamp + UpdatedAt: string; // Last update timestamp + }; +} + +// Response structure for document info API (multiple items) +export interface DocumentInfoGetResponse { + success: boolean; // Indicates if the API call was successful + message: string; // Response message + data?: Array<{ + ID: string; // Unique document info ID + FieldName: string; // Name of the field + fieldValue: DocumentInfoFieldValue; // Value of the field + PropertyID: string; // Linked property ID + CreatedAt: string; // Creation timestamp + UpdatedAt: string; // Last update timestamp + }>; +} \ No newline at end of file diff --git a/frontend/mobile-ui/src/app/features/PropertyForm/models/documentsUpload.model.ts b/frontend/mobile-ui/src/app/features/PropertyForm/models/documentsUpload.model.ts new file mode 100644 index 0000000..32b233c --- /dev/null +++ b/frontend/mobile-ui/src/app/features/PropertyForm/models/documentsUpload.model.ts @@ -0,0 +1,26 @@ +// Represents details for a single document upload +export interface DocumentUploadDetails { + PropertyId: string; // Linked property ID + DocumentType: string; // Type of document + DocumentName: string; // Name of the document + FileStoreID: string; // File store identifier +} + +// Response structure for document upload API +export interface DocumentUploadDetailsResponse { + message: string; // Response message + data: { + ID: string; // Unique document upload ID + PropertyID: string; // Linked property ID + DocumentType: string; // Type of document + DocumentName: string; // Name of the document + FileStoreID: string; // File store identifier + UploadDate: string; // Date of upload + action: string; // Action performed (e.g., upload, delete) + uploadedBy?: string; // User who uploaded (optional) + size?: string; // File size (optional) + }[]; +} + +// Array type for the document upload request +export type DocumentUploadDetailsRequest = DocumentUploadDetails[]; diff --git a/frontend/mobile-ui/src/app/models/AlertType.model.ts b/frontend/mobile-ui/src/app/models/AlertType.model.ts new file mode 100644 index 0000000..44d60d4 --- /dev/null +++ b/frontend/mobile-ui/src/app/models/AlertType.model.ts @@ -0,0 +1 @@ +export type AlertType = 'alert' | 'information' | 'warning' | 'success'; \ No newline at end of file diff --git a/frontend/mobile-ui/src/app/models/Colors.const.ts b/frontend/mobile-ui/src/app/models/Colors.const.ts new file mode 100644 index 0000000..0eaa61d --- /dev/null +++ b/frontend/mobile-ui/src/app/models/Colors.const.ts @@ -0,0 +1,9 @@ +export const COLORS = { + border: "#00000033", + bg: "#fff", + toggle: "#C84C0E", + text: "#222", + profileBg: "#FBEEE8", + verified: "#75BA74", + contact: "rgba(117, 186, 116, 0.35)", +}; \ No newline at end of file diff --git a/frontend/mobile-ui/src/app/models/Header.model.ts b/frontend/mobile-ui/src/app/models/Header.model.ts new file mode 100644 index 0000000..3b731c6 --- /dev/null +++ b/frontend/mobile-ui/src/app/models/Header.model.ts @@ -0,0 +1,7 @@ +import type { ReactNode } from "react"; + +export interface HeaderProps { + header: string; + subHeader: string; + icon?: ReactNode; +} \ No newline at end of file diff --git a/frontend/mobile-ui/src/app/models/NavButton.model.ts b/frontend/mobile-ui/src/app/models/NavButton.model.ts new file mode 100644 index 0000000..0d47929 --- /dev/null +++ b/frontend/mobile-ui/src/app/models/NavButton.model.ts @@ -0,0 +1,7 @@ +import type { ReactNode } from "react"; + +export interface NavButtonProps { + icon: ReactNode; + message: string; + onClick: () => void; +} \ No newline at end of file diff --git a/frontend/mobile-ui/src/app/models/Popup.model.ts b/frontend/mobile-ui/src/app/models/Popup.model.ts new file mode 100644 index 0000000..3b18981 --- /dev/null +++ b/frontend/mobile-ui/src/app/models/Popup.model.ts @@ -0,0 +1,10 @@ +import type { AlertType } from "./AlertType.model"; + +export type PopupProps = { + type: AlertType; + title: string; + message: string; + open: boolean; + duration?: number; + onClose?: () => void; +}; diff --git a/frontend/mobile-ui/src/app/models/UserProfile.mode.ts b/frontend/mobile-ui/src/app/models/UserProfile.mode.ts new file mode 100644 index 0000000..b2e154e --- /dev/null +++ b/frontend/mobile-ui/src/app/models/UserProfile.mode.ts @@ -0,0 +1,48 @@ +export interface UserProfile { + id?: string; + username?: string; + email?: string; + role?: string; + isActive?: boolean; + zone?: string[]; + ward?: string[]; + preferred_language?: string; + createdDate?: string; + updatedDate?: string; + createdBy?: string; + updatedBy?: string; + profile?: { + firstName?: string; + lastName?: string; + fullName?: string; + phoneNumber?: string; + adhaarNo?: number; + gender?: string; + guardian?: string; + guardianType?: string; + dateOfBirth?: string; + address?: Address; + department?: string; + designation?: string; + workLocation?: string; + profilePicture?: string; + relationshipToProperty?: string; + ownershipShare?: number; + isPrimaryOwner?: boolean; + isVerified?: boolean; + }; + // Fallback properties for session data + firstName?: string; + lastName?: string; + fullName?: string; + phoneNumber?: string; + address?: Address; +} + +export interface Address { + addressLine1?: string; + addressLine2?: string; + city?: string; + state?: string; + pinCode?: string; +} \ No newline at end of file diff --git a/frontend/mobile-ui/src/app/pages/Agent/AddRequestOrComment.tsx b/frontend/mobile-ui/src/app/pages/Agent/AddRequestOrComment.tsx new file mode 100644 index 0000000..932688b --- /dev/null +++ b/frontend/mobile-ui/src/app/pages/Agent/AddRequestOrComment.tsx @@ -0,0 +1,293 @@ +// AddRequestOrComment.tsx +// This page allows an agent to add a request or comment for a property, with file upload support. +// Features: +// - Comment input and validation +// - File upload (drag/drop or browse), preview, and removal +// - Submits comment and files to backend +// - Uses localization for all labels and messages +// - Navigation to previous and home screens +// Used in: Agent workflow for property verification and feedback + +import React, { useRef, useState } from 'react'; +import { useNavigate, useParams } from 'react-router-dom'; +import ArrowBackIosNewIcon from '@mui/icons-material/ArrowBackIosNew'; +import HomeOutlinedIcon from '@mui/icons-material/HomeOutlined'; +import PictureAsPdfIcon from '@mui/icons-material/PictureAsPdf'; +import DownloadIcon from '@mui/icons-material/Download'; +import CloseIcon from '@mui/icons-material/Close'; +import '../../../styles/AddRequestOrComment.css'; +import { uploadFileToFilestore } from '../../../services/AgentLocalisation/fileService'; +import type { UploadResult } from '../../../services/AgentLocalisation/fileService'; +// import { submitCommentRequest } from '../../../services/addCommentService'; +import { useAddCommentLocalization } from '../../../services/AgentLocalisation/localisation-addcomment'; +// import { ApplicationApi } from '../../../redux/apis/ApplicationLog/getApplication'; +import { usePostApplicationLogMutation } from '../../../redux/apis/applicationApi'; + +// Update UploadedFile interface +interface UploadedFile { + name: string; + url: string; + filestoreId: string; + file?: File; +} + +export function AddRequestOrComment() { + // Get propertyId from route params + const { propertyId } = useParams<{ propertyId: string }>(); + const navigate = useNavigate(); + const fileInputRef = useRef(null); + + // Store files before upload + const [uploadedFiles, setUploadedFiles] = useState([]); + const [uploading, setUploading] = useState(false); + const [error, setError] = useState(null); + const [comment, setComment] = useState(""); + + // RTK Query mutation hook + const [postApplicationLog ] = usePostApplicationLogMutation(); + const applicationId = localStorage.getItem("applicationId") || ""; + + // Use localization hook + const { + addCommentTitleText, + addCommentSubtitleText, + previousText, + homeText, + enterRequestLabelText, + dragDropText, + browseSystemText, + uploadingText, + downloadText, + attachDocumentsText, + cancelText, + submitText, + fileUploadFailedText, + // propertyIdMissingText, + // pleaseEnterCommentText, + // failedToSubmitText + } = useAddCommentLocalization(); + + // Store file data in state on select + const handleFileChange = (e: React.ChangeEvent) => { + if (e.target.files && e.target.files.length > 0) { + const file = e.target.files[0]; + setUploadedFiles([ + ...uploadedFiles, + { + name: file.name, + url: URL.createObjectURL(file), + filestoreId: "", + file, + }, + ]); + e.target.value = ""; + } + }; + + // Store file data in state on drag-drop + const handleDrop = (e: React.DragEvent) => { + e.preventDefault(); + if (e.dataTransfer.files && e.dataTransfer.files.length > 0) { + const file = e.dataTransfer.files[0]; + setUploadedFiles([ + ...uploadedFiles, + { + name: file.name, + url: URL.createObjectURL(file), + filestoreId: "", + file, + }, + ]); + } + }; + const userName = localStorage.getItem("agentUsername")|| ""; + const actor = localStorage.getItem("agentRole")|| "AGENT"; + + // Remove file from state + const handleRemoveFile = (idx: number) => { + setUploadedFiles(uploadedFiles.filter((_, i) => i !== idx)); + if (fileInputRef.current) fileInputRef.current.value = ""; + }; + + // Upload files to filestore on submit + const handleSubmit = async () => { + setError(null); + setUploading(true); + try { + // Upload each file and get filestoreId + const uploadedFileResults = await Promise.all( + uploadedFiles.map(async (f) => { + if (f.file && !f.filestoreId) { + const result: UploadResult = await uploadFileToFilestore(f.file); + return { + ...f, + filestoreId: result.files[0].fileStoreId, + }; + } + return f; + }) + ); + setUploadedFiles(uploadedFileResults); + + // Now call postApplicationLog with filestoreIds + const payload: any = { + applicationId: applicationId, + comments: comment, + performedBy: userName, + metadata: {}, + performedDate: new Date().toISOString(), + action: "CREATE", + actor: actor + }; + + if (uploadedFileResults.length > 0 && uploadedFileResults[0].filestoreId) { + payload.fileStoreId = uploadedFileResults[0].filestoreId; + } + console.log("Payload for put :", payload); + + // Now send payload + await postApplicationLog(payload).unwrap(); + + // Clear states after successful submit + setComment(""); + setUploadedFiles([]); + if (fileInputRef.current) fileInputRef.current.value = ""; + + setUploading(false); + // Optionally navigate or show success + } catch (err) { + setError(fileUploadFailedText); + setUploading(false); + } +}; + + const handlePrevious = () => { + if (propertyId) { + navigate(`/verification/${propertyId}`); + } else { + navigate(-1); + } + }; + + // Navigate to home screen + const handleHome = () => { + navigate('/agent'); + }; + + + + // Render AddRequestOrComment page UI + return ( +
+ {/* Header Section */} +
+
{addCommentTitleText}
+
{addCommentSubtitleText}
+
+ {/* Navigation Section */} +
+
+ +
{previousText}
+
+
+ +
{homeText}
+
+
+ + {/* Form Section */} +
+ +