diff --git a/src/api/API.ts b/src/api/API.ts index 87126e8..2674529 100644 --- a/src/api/API.ts +++ b/src/api/API.ts @@ -80,6 +80,7 @@ export const API = { createDealer: (data: any) => client.post('/dealer', data), getDealerById: (id: string) => client.get(`/dealer/${id}`), updateDealer: (id: string, data: any) => client.put(`/dealer/${id}`, data), + getDealerDashboard: () => client.get('/dealer/dashboard'), // Email Templates getEmailTemplates: () => client.get('/admin/email-templates'), @@ -91,13 +92,14 @@ export const API = { // Audit Trail getAuditLogs: (entityType: string, entityId: string, page: number = 1, limit: number = 50) => - client.get('/audit/logs', { entityType, entityId, page, limit }), + client.get('/audit/logs', { params: { entityType, entityId, page, limit } }), getAuditSummary: (entityType: string, entityId: string) => - client.get('/audit/summary', { entityType, entityId }), + client.get('/audit/summary', { params: { entityType, entityId } }), // Prospective Login sendOtp: (phone: string) => client.post('/prospective-login/send-otp', { phone }), verifyOtp: (phone: string, otp: string) => client.post('/prospective-login/verify-otp', { phone, otp }), + // Resignation getResignationById: (id: string) => client.get(`/resignation/${id}`), updateClearance: (id: string, data: any) => client.post(`/resignation/${id}/clearance`, data), diff --git a/src/components/applications/ApplicationDetails.tsx b/src/components/applications/ApplicationDetails.tsx index 618e09c..65c6097 100644 --- a/src/components/applications/ApplicationDetails.tsx +++ b/src/components/applications/ApplicationDetails.tsx @@ -2409,14 +2409,14 @@ export function ApplicationDetails() { )} {/* Dedicated Onboarding Button - Appears when logic is ready to onboard as a dealer */} - {isAdmin && ['Dealer Code Generation', 'Architecture Team Completion', 'LOA Pending', 'EOR Complete', 'Inauguration'].includes(application.status) && ( + {isAdmin && ['Dealer Code Generation', 'Architecture Team Completion', 'LOA Pending', 'EOR Complete', 'Inauguration', 'Approved'].includes(application.status) && !application.dealer && ( )} + {/* Dealer Onboarded Status & Link */} + {application.dealer && ( +
+
+ + Dealer Profile Active +
+
+ This application has been successfully onboarded as a dealer. A user account has been created for the dealer. +
+ {application.dealerCode && ( +
+ Dealer Code: + {application.dealerCode.code} +
+ )} + +
+ )} + {currentUser && ['DD Admin', 'Super Admin'].includes(currentUser.role) && ( diff --git a/src/components/dashboard/DealerDashboard.tsx b/src/components/dashboard/DealerDashboard.tsx index e905bc3..740366a 100644 --- a/src/components/dashboard/DealerDashboard.tsx +++ b/src/components/dashboard/DealerDashboard.tsx @@ -1,8 +1,10 @@ -import { FileText, RefreshCcw, MapPin, Users, TrendingUp, Clock, CheckCircle, AlertCircle } from 'lucide-react'; +import { useState, useEffect } from 'react'; +import { RefreshCcw, MapPin, Users, TrendingUp, Clock, CheckCircle, AlertCircle, ShoppingBag, Loader2 } from 'lucide-react'; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '../ui/card'; import { Button } from '../ui/button'; import { Badge } from '../ui/badge'; import { User } from '../../lib/mock-data'; +import { dealerService } from '../../services/dealer.service'; interface DealerDashboardProps { currentUser: User | null; @@ -10,27 +12,67 @@ interface DealerDashboardProps { } export function DealerDashboard({ currentUser, onNavigate }: DealerDashboardProps) { - // Dealer stats - showing their own requests + const [loading, setLoading] = useState(true); + const [data, setData] = useState(null); + + useEffect(() => { + const fetchDashboard = async () => { + try { + const dashboardData = await dealerService.getDashboardData(); + setData(dashboardData); + } catch (error) { + console.error('Failed to fetch dashboard:', error); + } finally { + setLoading(false); + } + }; + fetchDashboard(); + }, []); + + if (loading) { + return ( +
+ +

Loading your dashboard...

+
+ ); + } + + const dashboardData = data || {}; + const profile = dashboardData.profile || {}; + const statsSummary = dashboardData.stats || { constitutional: 0, relocation: 0, resignation: 0, total: 0 }; + const recentRequests = dashboardData.recentRequests || []; + const primaryOutlet = dashboardData.outlets?.[0] || {}; + + // Dealer stats const stats = [ { title: 'Constitutional Changes', - value: 1, + value: statsSummary.constitutional, icon: RefreshCcw, color: 'bg-blue-500', - change: 'In Review', + change: 'Active Requests', onClick: () => onNavigate('dealer-constitutional') }, { title: 'Relocation Requests', - value: 1, + value: statsSummary.relocation, icon: MapPin, color: 'bg-amber-500', - change: 'Pending Approval', + change: 'Active Requests', onClick: () => onNavigate('dealer-relocation') }, + { + title: 'My Outlets', + value: dashboardData.outlets?.length || 0, + icon: ShoppingBag, + color: 'bg-purple-500', + change: 'Registered', + onClick: () => {} + }, { title: 'Total Requests', - value: 2, + value: statsSummary.total, icon: TrendingUp, color: 'bg-green-500', change: 'All time', @@ -39,24 +81,6 @@ export function DealerDashboard({ currentUser, onNavigate }: DealerDashboardProp ]; // Recent requests by the dealer - const recentRequests = [ - { - id: 'CON-001', - type: 'Constitutional Change', - title: 'Change from Proprietorship to Partnership', - status: 'RBM Review', - date: '2025-12-15', - color: 'bg-blue-100 text-blue-700 border-blue-300' - }, - { - id: 'RLO-001', - type: 'Relocation', - title: 'Moving to Andheri East, Mumbai', - status: 'DD ZM Review', - date: '2025-12-10', - color: 'bg-amber-100 text-amber-700 border-amber-300' - }, - ]; // Quick actions for dealer const quickActions = [ @@ -84,12 +108,12 @@ export function DealerDashboard({ currentUser, onNavigate }: DealerDashboardProp
-

Welcome back, {currentUser?.name}!

+

Welcome back, {profile.name || currentUser?.name}!

- Dealer Code: DL-MH-001 • Royal Enfield Mumbai + Dealer Code: {profile.dealerCode} • {profile.businessName}

- Bandra West, Mumbai, Maharashtra + {primaryOutlet.name} • {primaryOutlet.location}

@@ -167,7 +191,7 @@ export function DealerDashboard({ currentUser, onNavigate }: DealerDashboardProp
- {recentRequests.map((request) => ( + {recentRequests.map((request: any) => (
void; } -// Mock constitutional change requests for this dealer -const mockDealerConstitutionalChanges = [ - { - id: 'CON-001', - dealerCode: 'DL-MH-001', - dealerName: 'Amit Sharma Motors', - currentConstitution: 'Proprietorship', - proposedConstitution: 'Partnership', - reason: 'Adding family members as partners', - status: 'RBM Review', - submittedOn: '2025-12-15', - currentStage: 'RBM', - progressPercentage: 25 - }, -]; - const getStatusColor = (status: string) => { if (status === 'Completed') return 'bg-green-100 text-green-700 border-green-300'; if (status.includes('Review') || status.includes('Pending')) return 'bg-yellow-100 text-yellow-700 border-yellow-300'; @@ -44,13 +29,39 @@ const constitutionTypes = ['Proprietorship', 'Partnership', 'LLP', 'Pvt Ltd']; export function DealerConstitutionalChangePage({ currentUser, onViewDetails }: DealerConstitutionalChangePageProps) { const [isDialogOpen, setIsDialogOpen] = useState(false); - const [currentConstitution, setCurrentConstitution] = useState('Proprietorship'); // Pre-filled + const [currentConstitution, setCurrentConstitution] = useState(''); const [proposedConstitution, setProposedConstitution] = useState(''); const [reason, setReason] = useState(''); const [newPartners, setNewPartners] = useState(''); const [shareholdingPattern, setShareholdingPattern] = useState(''); + + const [requests, setRequests] = useState([]); + const [loading, setLoading] = useState(true); + const [submitting, setSubmitting] = useState(false); + const [profile, setProfile] = useState(null); - const handleSubmitRequest = (e: React.FormEvent) => { + useEffect(() => { + fetchData(); + }, []); + + const fetchData = async () => { + try { + setLoading(true); + const dashboard = await dealerService.getDashboardData(); + const constitutionalRes = await dealerService.getConstitutionalChanges(); + + setProfile(dashboard.profile); + setCurrentConstitution(dashboard.profile?.constitutionType || 'Proprietorship'); + setRequests(constitutionalRes.requests || []); + } catch (error) { + console.error('Fetch constitutional data error:', error); + toast.error('Failed to load requests'); + } finally { + setLoading(false); + } + }; + + const handleSubmitRequest = async (e: React.FormEvent) => { e.preventDefault(); if (!proposedConstitution) { @@ -68,32 +79,50 @@ export function DealerConstitutionalChangePage({ currentUser, onViewDetails }: D return; } - toast.success('Constitutional change request submitted successfully'); - setIsDialogOpen(false); - - // Reset form - setProposedConstitution(''); - setReason(''); - setNewPartners(''); - setShareholdingPattern(''); + try { + setSubmitting(true); + const payload = { + currentConstitution, + changeType: proposedConstitution, + reason, + newPartnersDetails: newPartners, + shareholdingPattern + }; + + await dealerService.submitConstitutionalChange(payload); + toast.success('Constitutional change request submitted successfully'); + setIsDialogOpen(false); + fetchData(); // Refresh list + + // Reset form + setProposedConstitution(''); + setReason(''); + setNewPartners(''); + setShareholdingPattern(''); + } catch (error) { + console.error('Submit constitutional change error:', error); + toast.error('Failed to submit constitutional change request'); + } finally { + setSubmitting(false); + } }; const stats = [ { title: 'Total Requests', - value: mockDealerConstitutionalChanges.length, + value: requests.length, icon: RefreshCcw, color: 'bg-blue-500', }, { title: 'Pending', - value: mockDealerConstitutionalChanges.filter(r => r.status !== 'Completed' && r.status !== 'Rejected').length, + value: requests.filter(r => r.status !== 'Completed' && r.status !== 'Rejected').length, icon: Calendar, color: 'bg-yellow-500', }, { title: 'Completed', - value: mockDealerConstitutionalChanges.filter(r => r.status === 'Completed').length, + value: requests.filter(r => r.status === 'Completed').length, icon: FileText, color: 'bg-green-500', }, @@ -101,244 +130,271 @@ export function DealerConstitutionalChangePage({ currentUser, onViewDetails }: D return (
- {/* Header */} -
-
-

My Constitutional Change Requests

-

- Submit and track requests for changing your business constitution -

+ {/* Loading Overlay */} + {loading && ( +
+
- - - - - - - - Submit Constitutional Change Request - - Request to change your dealership's business constitution structure - - + )} + + {!loading && ( + <> + {/* Header */} +
+
+

My Constitutional Change Requests

+

+ Submit and track requests for changing your business constitution +

+
-
- {/* Dealer Info */} -
-

Current Dealership Information

-
-
- Dealer Code: -

DL-MH-001

-
-
- Dealer Name: -

Amit Sharma Motors

-
-
- Current Constitution: -

Proprietorship

-
-
-
- - {/* Constitution Change */} -
-
- - -
-
- - -
-
- - {/* Reason */} -
- -