diff --git a/package.json b/package.json index fc4eaba..aceaf61 100644 --- a/package.json +++ b/package.json @@ -6,6 +6,7 @@ "scripts": { "dev": "vite", "build": "tsc && vite build", + "build:deploy": "vite build", "lint": "eslint . --report-unused-disable-directives --max-warnings 0", "preview": "vite preview", "test": "jest", diff --git a/src/api/API.ts b/src/api/API.ts index 4ac30ba..88d0472 100644 --- a/src/api/API.ts +++ b/src/api/API.ts @@ -2,6 +2,8 @@ import client from './client'; import axios from 'axios'; import type { ConstitutionalChangeAction } from '@/lib/offboarding-actions'; +const PUBLIC_API_BASE_URL = (import.meta as any).env?.VITE_API_URL || '/api'; + export const API = { // Auth routes login: (data: any) => client.post('/auth/login', data), @@ -70,8 +72,8 @@ export const API = { deleteDocumentConfig: (id: string) => client.delete(`/onboarding/document-configs/${id}`), // Public Questionnaire - getPublicQuestionnaire: (appId: string) => axios.get(`http://localhost:5000/api/questionnaire/public/${appId}`), // Direct axios to bypass interceptors if client has auth - submitPublicResponse: (data: any) => axios.post('http://localhost:5000/api/questionnaire/public/submit', data), + getPublicQuestionnaire: (appId: string) => axios.get(`${PUBLIC_API_BASE_URL}/questionnaire/public/${appId}`), // Direct axios to bypass interceptors if client has auth + submitPublicResponse: (data: any) => axios.post(`${PUBLIC_API_BASE_URL}/questionnaire/public/submit`, data), // Assessment & Interviews getAiSummary: (appId: string) => client.get(`/assessment/ai-summary/${appId}`), diff --git a/src/api/client.ts b/src/api/client.ts index a95c3d1..5ce2be1 100644 --- a/src/api/client.ts +++ b/src/api/client.ts @@ -1,6 +1,6 @@ import { create } from 'apisauce'; -const API_BASE_URL = (import.meta as any).env?.VITE_API_URL || 'http://localhost:5000/api'; +const API_BASE_URL = (import.meta as any).env?.VITE_API_URL || '/api'; const client = create({ baseURL: API_BASE_URL, diff --git a/src/components/dealer/QuestionnaireForm.tsx b/src/components/dealer/QuestionnaireForm.tsx index 421509d..3a5b85a 100644 --- a/src/components/dealer/QuestionnaireForm.tsx +++ b/src/components/dealer/QuestionnaireForm.tsx @@ -59,9 +59,9 @@ const QuestionnaireForm: React.FC = ({ return; } - const res = await API.getLatestQuestionnaire(); + const res: any = await API.getLatestQuestionnaire(); - if (res.data && res.data.data && res.data.data.questions) { + if (res?.data?.data?.questions) { // Normalize questions const normalized = res.data.data.questions.map((q: any) => ({ ...q, diff --git a/src/components/ui/DocumentPreviewModal.tsx b/src/components/ui/DocumentPreviewModal.tsx index d380208..42e7131 100644 --- a/src/components/ui/DocumentPreviewModal.tsx +++ b/src/components/ui/DocumentPreviewModal.tsx @@ -1,20 +1,13 @@ -import React, { useState } from 'react'; +import React from 'react'; import { Dialog, DialogContent, - DialogHeader, DialogTitle, - DialogDescription, } from './dialog'; import { Button } from './button'; import { Eye, Download, - RotateCw, - RefreshCw, - Plus, - Minus, - FileText } from 'lucide-react'; import { WIDE_DIALOG_CLASS } from '../../lib/dialogStyles'; @@ -35,9 +28,6 @@ export const DocumentPreviewModal: React.FC = ({ onClose, document }) => { - const [zoomScale, setZoomScale] = useState(1); - const [rotation, setRotation] = useState(0); - const baseUrl = 'http://localhost:5000'; const fileUrl = document ? `${baseUrl}${document.filePath.startsWith('/') ? '' : '/'}${document.filePath}` : ''; diff --git a/src/features/dashboard/pages/ProspectiveDashboardPage.tsx b/src/features/dashboard/pages/ProspectiveDashboardPage.tsx index 94818b7..d660900 100644 --- a/src/features/dashboard/pages/ProspectiveDashboardPage.tsx +++ b/src/features/dashboard/pages/ProspectiveDashboardPage.tsx @@ -1,20 +1,11 @@ import { useState, useEffect } from 'react'; import { - LayoutDashboard, - Calendar, FileText, - UserMinus, - RefreshCcw, - MapPin, LogOut, - Search, ChevronLeft, ChevronRight, - Bell, User, RefreshCw, - HelpCircle, - X } from 'lucide-react'; import { useDispatch, useSelector } from 'react-redux'; import { useNavigate, Routes, Route, useParams } from 'react-router-dom'; diff --git a/src/features/fnf/pages/FnFDetails.tsx b/src/features/fnf/pages/FnFDetails.tsx index 8278703..b2792c1 100644 --- a/src/features/fnf/pages/FnFDetails.tsx +++ b/src/features/fnf/pages/FnFDetails.tsx @@ -423,12 +423,6 @@ export function FnFDetails({ fnfId, onBack, currentUser }: FnFDetailsProps) { const fnfAge = calculateAge(fnfCase.submittedOn); - const canSendToStakeholders = - currentUser && - ["DD Lead", "DD Head", "NBH", "DD Admin", "Super Admin"].includes( - currentUser.role, - ); - const canRespondToDepartment = (dept: any) => { if (!fnfCase || !dept) return false; const role = String(currentUser?.role || "").toLowerCase(); diff --git a/src/features/fnf/pages/FnFPage.tsx b/src/features/fnf/pages/FnFPage.tsx index b2de3be..7655bc5 100644 --- a/src/features/fnf/pages/FnFPage.tsx +++ b/src/features/fnf/pages/FnFPage.tsx @@ -1,5 +1,5 @@ import { useState, useEffect } from 'react'; -import { IndianRupee, Calendar, Eye, Send, FileCheck, Loader2 } from 'lucide-react'; +import { IndianRupee, Calendar, Eye, FileCheck, Loader2 } from 'lucide-react'; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'; import { Badge } from '@/components/ui/badge'; import { Button } from '@/components/ui/button'; @@ -42,9 +42,6 @@ export function FnFPage({ currentUser, onViewDetails }: FnFPageProps) { const [settlements, setSettlements] = useState([]); const [loading, setLoading] = useState(true); - const canSendToStakeholders = currentUser && - ['DD Lead', 'DD Head', 'NBH', 'DD Admin', 'Super Admin'].includes(currentUser.role); - useEffect(() => { fetchSettlements(); }, []); @@ -65,11 +62,6 @@ export function FnFPage({ currentUser, onViewDetails }: FnFPageProps) { } }; - const handleSendToStakeholders = (caseId: string) => { - console.log('Sending to stakeholders for case:', caseId); - toast.success('Notifications sent to all stakeholders'); - }; - if (loading) { return (
diff --git a/src/features/master/components/ASMDialog.tsx b/src/features/master/components/ASMDialog.tsx index 34e5872..3d59f51 100644 --- a/src/features/master/components/ASMDialog.tsx +++ b/src/features/master/components/ASMDialog.tsx @@ -37,7 +37,7 @@ export const ASMDialog: React.FC = ({ asmStatus, setAsmStatus, selectedASMZone, setSelectedASMZone, selectedASMRegion, setSelectedASMRegion, selectedASMStates, setSelectedASMStates, selectedASMDistricts, setSelectedASMDistricts, onSave, - asmRoleCode, setAsmRoleCode, + asmRoleCode, userAssignedData, districtsAssignedToOthers, getDistrictsForSelectedState }) => { const { zones, regionalOffices } = useSelector((state: RootState) => state.master); diff --git a/src/features/onboarding/__tests__/AllApplicationsPage.test.tsx b/src/features/onboarding/__tests__/AllApplicationsPage.test.tsx index 74b64ea..795e042 100644 --- a/src/features/onboarding/__tests__/AllApplicationsPage.test.tsx +++ b/src/features/onboarding/__tests__/AllApplicationsPage.test.tsx @@ -1,4 +1,4 @@ -import { render, screen } from "@testing-library/react" +import { screen } from "@testing-library/react" import userEvent from "@testing-library/user-event" import { AllApplicationsPage } from "../pages/AllApplicationsPage" import { renderWithProviders } from "./test-utils" @@ -10,12 +10,12 @@ describe("AllApplicationsPage - Robust Admin Verification", () => { jest.clearAllMocks() }) - const renderPage = (apps = []) => { + const renderPage = (apps: any[] = []) => { ;(mockOnboardingService.getApplications as jest.Mock).mockResolvedValue({ success: true, data: apps }) - return renderWithProviders(, { + return renderWithProviders(, { preloadedState: { auth: { user: { id: "admin-1", role: "DD Admin" } as any, diff --git a/src/features/onboarding/__tests__/ApplicationReviewWorkflow.test.tsx b/src/features/onboarding/__tests__/ApplicationReviewWorkflow.test.tsx index ad5393a..bf1e496 100644 --- a/src/features/onboarding/__tests__/ApplicationReviewWorkflow.test.tsx +++ b/src/features/onboarding/__tests__/ApplicationReviewWorkflow.test.tsx @@ -1,4 +1,4 @@ -import { render, screen, waitFor } from "@testing-library/react" +import { screen, waitFor } from "@testing-library/react" import userEvent from "@testing-library/user-event" import { ApplicationDetails } from "../pages/ApplicationDetails" import { renderWithProvidersAndRoute } from "./test-utils" diff --git a/src/features/onboarding/__tests__/ApplicationsPage.test.tsx b/src/features/onboarding/__tests__/ApplicationsPage.test.tsx index 7501d48..16a5d9c 100644 --- a/src/features/onboarding/__tests__/ApplicationsPage.test.tsx +++ b/src/features/onboarding/__tests__/ApplicationsPage.test.tsx @@ -1,4 +1,4 @@ -import { render, screen, waitFor } from "@testing-library/react" +import { screen } from "@testing-library/react" import userEvent from "@testing-library/user-event" import { ApplicationsPage } from "../pages/ApplicationsPage" import { renderWithProviders } from "./test-utils" @@ -10,7 +10,7 @@ describe("ApplicationsPage - Robust Feature Verification", () => { jest.clearAllMocks() }) - const renderPage = (apps = []) => { + const renderPage = (apps: any[] = []) => { ;(mockOnboardingService.getApplications as jest.Mock).mockResolvedValue({ success: true, data: apps diff --git a/src/features/onboarding/__tests__/DeepOnboardingStages.test.tsx b/src/features/onboarding/__tests__/DeepOnboardingStages.test.tsx index 90d8e9f..b2a353e 100644 --- a/src/features/onboarding/__tests__/DeepOnboardingStages.test.tsx +++ b/src/features/onboarding/__tests__/DeepOnboardingStages.test.tsx @@ -1,4 +1,4 @@ -import { render, screen, waitFor } from "@testing-library/react" +import { screen, waitFor } from "@testing-library/react" import userEvent from "@testing-library/user-event" import { ApplicationDetails } from "../pages/ApplicationDetails" import { renderWithProvidersAndRoute } from "./test-utils" diff --git a/src/features/onboarding/__tests__/FddAgencyFlow.test.tsx b/src/features/onboarding/__tests__/FddAgencyFlow.test.tsx index da08d54..3bd2a1b 100644 --- a/src/features/onboarding/__tests__/FddAgencyFlow.test.tsx +++ b/src/features/onboarding/__tests__/FddAgencyFlow.test.tsx @@ -1,4 +1,4 @@ -import { render, screen, waitFor } from "@testing-library/react" +import { screen, waitFor } from "@testing-library/react" import userEvent from "@testing-library/user-event" import { FDDApplicationDetails } from "../pages/FDDApplicationDetails" import { renderWithProvidersAndRoute } from "./test-utils" diff --git a/src/features/onboarding/__tests__/NonOpportunitiesPage.test.tsx b/src/features/onboarding/__tests__/NonOpportunitiesPage.test.tsx index 1e67b3c..e102765 100644 --- a/src/features/onboarding/__tests__/NonOpportunitiesPage.test.tsx +++ b/src/features/onboarding/__tests__/NonOpportunitiesPage.test.tsx @@ -1,4 +1,4 @@ -import { render, screen } from "@testing-library/react" +import { screen } from "@testing-library/react" import userEvent from "@testing-library/user-event" import { NonOpportunitiesPage } from "../pages/NonOpportunitiesPage" import { renderWithProviders } from "./test-utils" @@ -10,7 +10,7 @@ describe("NonOpportunitiesPage - Lead generation filtering", () => { jest.clearAllMocks() }) - const renderPage = (apps = []) => { + const renderPage = (apps: any[] = []) => { ;(mockOnboardingService.getApplications as jest.Mock).mockResolvedValue({ success: true, data: apps, diff --git a/src/features/onboarding/__tests__/OpportunityRequestsFlow.test.tsx b/src/features/onboarding/__tests__/OpportunityRequestsFlow.test.tsx index c28eff4..dbfec5f 100644 --- a/src/features/onboarding/__tests__/OpportunityRequestsFlow.test.tsx +++ b/src/features/onboarding/__tests__/OpportunityRequestsFlow.test.tsx @@ -1,4 +1,4 @@ -import { render, screen, waitFor } from "@testing-library/react" +import { screen, waitFor } from "@testing-library/react" import userEvent from "@testing-library/user-event" import { OpportunityRequestsPage } from "../pages/OpportunityRequestsPage" import { renderWithProviders } from "./test-utils" @@ -14,12 +14,12 @@ describe("OpportunityRequestsFlow - Lead Triage Verification", () => { jest.clearAllMocks() }) - const renderPage = (apps = []) => { + const renderPage = (apps: any[] = []) => { ;(mockOnboardingService.getApplications as jest.Mock).mockResolvedValue({ success: true, data: apps }) - return renderWithProviders(, { + return renderWithProviders(, { preloadedState: { auth: { user: { id: "admin-1", role: "DD Admin" } as any, diff --git a/src/features/onboarding/__tests__/shared/constants.ts b/src/features/onboarding/__tests__/shared/constants.ts index d4e37e4..5affdfd 100644 --- a/src/features/onboarding/__tests__/shared/constants.ts +++ b/src/features/onboarding/__tests__/shared/constants.ts @@ -1 +1 @@ -export const SHARED_APP_STATUSES = { SUBMITTED: "Submitted" }; +export { TEST_STRINGS, GLOBAL_MOCK_IDS, SHARED_APP_STATUSES } from "@/testing/constants"; diff --git a/src/features/onboarding/__tests__/shared/mocks.ts b/src/features/onboarding/__tests__/shared/mocks.ts index 1fb7274..69c5c54 100644 --- a/src/features/onboarding/__tests__/shared/mocks.ts +++ b/src/features/onboarding/__tests__/shared/mocks.ts @@ -49,19 +49,18 @@ export const globalMockAdminService = { * Helper to prepare global mocks in any test file. */ export const setupUnifiedMocks = () => { - jest.mock("@/services/onboarding.service", () => ({ onboardingService: globalMockOnboardingService })); - jest.mock("@/services/collaboration.service", () => ({ collaborationService: globalMockCollaborationService })); - // Mapping worknoteService to collaborationService as they share logic in this codebase - jest.mock("@/services/worknote.service", () => ({ worknoteService: globalMockCollaborationService })); - jest.mock("@/services/eor.service", () => ({ eorService: globalMockEORService })); - jest.mock("@/services/admin.service", () => ({ adminService: globalMockAdminService })); - jest.mock("@/api/API", () => ({ + return { + onboardingService: globalMockOnboardingService, + collaborationService: globalMockCollaborationService, + worknoteService: globalMockCollaborationService, + eorService: globalMockEORService, + adminService: globalMockAdminService, API: { ...globalMockOnboardingService, getFddAssignment: jest.fn().mockResolvedValue({ success: true, data: {} }), uploadDocument: jest.fn().mockResolvedValue({ success: true }), submitFddReport: jest.fn().mockResolvedValue({ success: true }), flagNonResponsive: jest.fn().mockResolvedValue({ success: true }), - } - })); + }, + }; }; diff --git a/src/features/onboarding/__tests__/test-utils.tsx b/src/features/onboarding/__tests__/test-utils.tsx index 11b8bce..99effbb 100644 --- a/src/features/onboarding/__tests__/test-utils.tsx +++ b/src/features/onboarding/__tests__/test-utils.tsx @@ -2,7 +2,6 @@ import React, { PropsWithChildren } from 'react' import { render } from '@testing-library/react' import type { RenderOptions } from '@testing-library/react' import { configureStore } from '@reduxjs/toolkit' -import type { PreloadedState } from '@reduxjs/toolkit' import { Provider } from 'react-redux' import { MemoryRouter, Routes, Route } from 'react-router-dom' @@ -14,7 +13,7 @@ import { MEMORY_ROUTER_TEST_FUTURE } from '@/testing/reactRouterTest' // This type interface extends the default options for render from RTL, as well // as allows the user to specify other things such as initialState, store. interface ExtendedRenderOptions extends Omit { - preloadedState?: PreloadedState + preloadedState?: Partial store?: ReturnType } @@ -24,13 +23,13 @@ interface ProvidersAndRouteOptions extends ExtendedRenderOptions { routePath: string } -export function setupStore(preloadedState?: PreloadedState) { +export function setupStore(preloadedState?: Partial) { return configureStore({ reducer: { auth: authReducer, master: masterReducer, - }, - preloadedState + } as any, + preloadedState: preloadedState as any }) } diff --git a/src/features/relocation/pages/DealerRelocationPage.tsx b/src/features/relocation/pages/DealerRelocationPage.tsx index 6ed64e3..3f35768 100644 --- a/src/features/relocation/pages/DealerRelocationPage.tsx +++ b/src/features/relocation/pages/DealerRelocationPage.tsx @@ -30,7 +30,7 @@ const getStatusColor = (status: string) => { const getApiErrorMessage = (error: any, fallback: string) => error?.response?.data?.message || error?.data?.message || error?.message || fallback; -export function DealerRelocationPage({ currentUser, onViewDetails }: DealerRelocationPageProps) { +export function DealerRelocationPage({ onViewDetails }: DealerRelocationPageProps) { const [isDialogOpen, setIsDialogOpen] = useState(false); const [selectedOutlet, setSelectedOutlet] = useState(null); const [newCity, setNewCity] = useState(''); @@ -54,7 +54,6 @@ export function DealerRelocationPage({ currentUser, onViewDetails }: DealerReloc const [requests, setRequests] = useState([]); const [loading, setLoading] = useState(true); const [submitting, setSubmitting] = useState(false); - const [profile, setProfile] = useState(null); useEffect(() => { fetchData(); @@ -73,7 +72,6 @@ export function DealerRelocationPage({ currentUser, onViewDetails }: DealerReloc const relocationRes = await dealerService.getRelocationRequests(); setOutlets(dashboard.outlets || []); - setProfile(dashboard.profile); setRequests(relocationRes.requests || []); } catch (error) { console.error('Fetch relocation data error:', error); @@ -121,11 +119,6 @@ export function DealerRelocationPage({ currentUser, onViewDetails }: DealerReloc } }; - const handleOpenRelocationDialog = (outlet: any) => { - setSelectedOutlet(outlet); - setIsDialogOpen(true); - }; - const handleSubmitRequest = async (e: React.FormEvent) => { e.preventDefault(); diff --git a/src/features/resignation/pages/DealerResignationPage.tsx b/src/features/resignation/pages/DealerResignationPage.tsx index d09220a..dc6f10d 100644 --- a/src/features/resignation/pages/DealerResignationPage.tsx +++ b/src/features/resignation/pages/DealerResignationPage.tsx @@ -1,9 +1,9 @@ -import { FileText, Plus, Eye, Calendar, User, Building2, Store, MapPin, CheckCircle, Clock, RefreshCcw, Loader2 } from 'lucide-react'; +import { FileText, Eye, Calendar, Building2, Store, MapPin, CheckCircle, Clock, Loader2 } from 'lucide-react'; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'; import { Badge } from '@/components/ui/badge'; import { Button } from '@/components/ui/button'; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table'; -import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, DialogTrigger } from '@/components/ui/dialog'; +import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from '@/components/ui/dialog'; import { Input } from '@/components/ui/input'; import { Label } from '@/components/ui/label'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'; @@ -27,7 +27,7 @@ const getStatusColor = (status: string) => { return 'bg-slate-100 text-slate-700 border-slate-300'; }; -export function DealerResignationPage({ currentUser, onViewDetails }: DealerResignationPageProps) { +export function DealerResignationPage({ onViewDetails }: DealerResignationPageProps) { const [isDialogOpen, setIsDialogOpen] = useState(false); const [selectedOutlet, setSelectedOutlet] = useState(null); const [resignationType, setResignationType] = useState(''); diff --git a/src/features/resignation/pages/ResignationPage.tsx b/src/features/resignation/pages/ResignationPage.tsx index f990cd6..041a066 100644 --- a/src/features/resignation/pages/ResignationPage.tsx +++ b/src/features/resignation/pages/ResignationPage.tsx @@ -30,7 +30,7 @@ const getStatusColor = (status: string) => { return 'bg-blue-100 text-blue-700 border-blue-300'; }; -export function ResignationPage({ currentUser, onViewDetails }: ResignationPageProps) { +export function ResignationPage({ onViewDetails }: ResignationPageProps) { const [resignations, setResignations] = useState([]); const [loading, setLoading] = useState(true); const [currentPage, setCurrentPage] = useState(1); diff --git a/src/pages/NotificationsPage.tsx b/src/pages/NotificationsPage.tsx index c32114a..b3e71c5 100644 --- a/src/pages/NotificationsPage.tsx +++ b/src/pages/NotificationsPage.tsx @@ -1,7 +1,6 @@ import React, { useState, useEffect } from 'react'; -import { Card, CardHeader, CardTitle, CardContent } from '@/components/ui/card'; +import { Card, CardContent } from '@/components/ui/card'; import { Button } from '@/components/ui/button'; -import { Badge } from '@/components/ui/badge'; import { Bell, Check, Clock, ChevronLeft, ChevronRight } from 'lucide-react'; import { notificationService, Notification } from '@/services/notification.service'; import { useNavigate } from 'react-router-dom'; diff --git a/vite.config.ts b/vite.config.ts index 399ccab..ba0d165 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -4,6 +4,10 @@ import { defineConfig } from "vite" export default defineConfig({ plugins: [react()], + build: { + outDir: "../backend/build", + emptyOutDir: true, + }, resolve: { alias: { "@": path.resolve(__dirname, "./src"),