diff --git a/src/components/applications/ApplicationDetails.tsx b/src/components/applications/ApplicationDetails.tsx index 23dc554..294b2a4 100644 --- a/src/components/applications/ApplicationDetails.tsx +++ b/src/components/applications/ApplicationDetails.tsx @@ -354,6 +354,8 @@ export const ApplicationDetails = () => { stageApprovals: data.stageApprovals || [], fddAssignments: data.fddAssignments || [], constitutionType: data.constitutionType, + architectureStatus: data.architectureStatus, + statutoryStatus: data.statutoryStatus, }; setApplication(mappedApp); if (data.uploadedDocuments) { @@ -1202,7 +1204,7 @@ export const ApplicationDetails = () => { id: 12, name: 'LOA', status: getStageStatus('LOA', () => ['EOR In Progress', 'EOR Complete', 'Inauguration', 'Approved', 'Onboarded'].includes(application.status) ? 'completed' : application.status === 'LOA Pending' ? 'active' : 'pending'), - isLocked: application.status === 'LOA Pending' && getDeposit('FINAL')?.status !== 'Verified', + isLocked: application.status === 'LOA Pending' && getDeposit('FIRST_FILL')?.status !== 'Verified', lockMessage: 'First Fill (₹15L) must be verified by Finance before LOA Approval.', evaluators: Array.from(new Set((application.participants || []) .filter((p: any) => p.metadata?.stageCode === 'LOA_APPROVAL' || p.metadata?.allAssignments?.includes('LOA_APPROVAL')) @@ -1682,7 +1684,7 @@ export const ApplicationDetails = () => { 'LOA Pending', 'EOR In Progress', 'EOR Complete', 'Inauguration' ].includes(application.status); - const finalDepositVerified = getDeposit('FINAL')?.status === 'Verified'; + const finalDepositVerified = getDeposit('FIRST_FILL')?.status === 'Verified'; const isLoaLocked = application.status === 'LOA Pending' && !finalDepositVerified; // Sequential Enforcement for LOI APPROVAL (SRS 6.16.3.5) @@ -2024,21 +2026,7 @@ export const ApplicationDetails = () => {
-
- -
-
- {report.recommendation?.toUpperCase()} -
-
+ {/* Auditor Recommendation Hidden as per request */}
@@ -2093,16 +2081,23 @@ export const ApplicationDetails = () => {
)} -
+
+
+
+ + Submitted by: {report.submitter?.fullName || 'Auditor'} +
+
+ {report.verifiedAt ? ( -
+
- Audit Verified by Finance + Verified by {report.verifier?.fullName || 'Admin'}
) : ( -
+
- Pending Finance Review + Pending Review
)}
@@ -3169,7 +3164,7 @@ export const ApplicationDetails = () => {
{/* Initial Security Deposit */} {(() => { - const deposit = getDeposit('INITIAL'); + const deposit = getDeposit('SECURITY_DEPOSIT'); const config = paymentConfigs.SECURITY_DEPOSIT; const expectedAmount = config?.amount || 500000; @@ -3252,7 +3247,7 @@ export const ApplicationDetails = () => { {/* Final Security Deposit */} {(() => { - const deposit = getDeposit('FINAL'); + const deposit = getDeposit('FIRST_FILL'); const config = paymentConfigs.FIRST_FILL; const expectedAmount = config?.amount || 1500000; @@ -4856,26 +4851,28 @@ export const ApplicationDetails = () => {
-
- -
- {['Recommended', 'Qualified with Observations', 'Not Recommended'].map((rec) => ( - - ))} + {(currentUser?.role !== 'FDD' && currentUser?.roleCode !== 'FDD') && ( +
+ +
+ {['Recommended', 'Qualified with Observations', 'Not Recommended'].map((rec) => ( + + ))} +
-
+ )}
@@ -4914,7 +4911,9 @@ export const ApplicationDetails = () => { applicationId: application!.id, stageCode: 'FDD_VERIFICATION', decision: 'Approved', - remarks: `[RECOMMENDATION: ${fddAuditRecommendation}] \nFindings: ${fddAuditFindings}`, + remarks: (currentUser?.role === 'FDD' || currentUser?.roleCode === 'FDD') + ? `Findings: ${fddAuditFindings}` + : `[RECOMMENDATION: ${fddAuditRecommendation}] \nFindings: ${fddAuditFindings}`, nextStatus: 'LOI In Progress', nextProgress: 65 }); diff --git a/src/components/applications/ConstitutionalChangeDetails.tsx b/src/components/applications/ConstitutionalChangeDetails.tsx index f510b83..f812630 100644 --- a/src/components/applications/ConstitutionalChangeDetails.tsx +++ b/src/components/applications/ConstitutionalChangeDetails.tsx @@ -252,6 +252,45 @@ export function ConstitutionalChangeDetails({ requestId, onBack }: Constitutiona + {/* Establishment Details */} + + + Establishment & Dealer Codes + + +
+
+

Sales Code

+

{request.dealer?.dealerProfile?.dealerCode?.salesCode || 'N/A'}

+
+
+

Service Code

+

{request.dealer?.dealerProfile?.dealerCode?.serviceCode || 'N/A'}

+
+
+

GMA Code

+

{request.dealer?.dealerProfile?.dealerCode?.gmaCode || 'N/A'}

+
+
+

Gear Code

+

{request.dealer?.dealerProfile?.dealerCode?.gearCode || 'N/A'}

+
+
+

Inauguration Date

+

{request.dealer?.dealerProfile?.onboardedAt ? formatDateTime(request.dealer.dealerProfile.onboardedAt, 'date') : 'N/A'}

+
+
+

LOI Date

+

{request.dealer?.dealerProfile?.loiDate ? formatDateTime(request.dealer.dealerProfile.loiDate, 'date') : 'N/A'}

+
+
+

LOA Date

+

{request.dealer?.dealerProfile?.loaDate ? formatDateTime(request.dealer.dealerProfile.loaDate, 'date') : 'N/A'}

+
+
+
+
+
{/* Main Content */}
diff --git a/src/components/applications/FDDApplicationDetails.tsx b/src/components/applications/FDDApplicationDetails.tsx index 8cc6968..7662725 100644 --- a/src/components/applications/FDDApplicationDetails.tsx +++ b/src/components/applications/FDDApplicationDetails.tsx @@ -17,7 +17,7 @@ import { import { WorkNotesPage } from './WorkNotesPage'; import { toast } from 'sonner'; import { DocumentPreviewModal } from '../ui/DocumentPreviewModal'; -import { formatDateTime, cn } from '@/components/ui/utils'; +import { formatDateTime } from '@/components/ui/utils'; import { Dialog, DialogContent, @@ -45,10 +45,9 @@ export function FDDApplicationDetails() { const [selectedPreviewDoc, setSelectedPreviewDoc] = useState(null); const [showFinalizeModal, setShowFinalizeModal] = useState(false); const [showFlagModal, setShowFlagModal] = useState(false); - const [fddAuditRecommendation, setFddAuditRecommendation] = useState('Recommended'); const [fddAuditFindings, setFddAuditFindings] = useState(''); const user = useSelector((state: RootState) => state.auth.user); - const isFddRole = user?.role === 'FDD' || user?.role === 'FDD Auditor'; + const isFddRole = user?.role === 'FDD'; useEffect(() => { if (id) fetchApplication(); @@ -202,6 +201,14 @@ export function FDDApplicationDetails() { {uploading ? 'Uploading...' : 'Upload Report'} +
-
- -
- {['Recommended', 'Qualified with Observations', 'Not Recommended'].map((rec) => ( - - ))} -
-
@@ -594,16 +581,12 @@ export function FDDApplicationDetails() { toast.error('Please provide findings.'); return; } - if (!assignment?.id) { - toast.error('Assignment not found.'); - return; - } - setUploading(true); const res: any = await API.submitFddReport({ - assignmentId: assignment.id, + assignmentId: assignment?.id, + applicationId: id, findings: fddAuditFindings, - recommendation: fddAuditRecommendation + recommendation: null }); if (res.data?.success) { diff --git a/src/components/applications/FinanceOnboardingPage.tsx b/src/components/applications/FinanceOnboardingPage.tsx index a54fdde..fa7836c 100644 --- a/src/components/applications/FinanceOnboardingPage.tsx +++ b/src/components/applications/FinanceOnboardingPage.tsx @@ -49,7 +49,7 @@ export function FinanceOnboardingPage({ onViewPaymentDetails }: FinanceOnboardin const getRelevantPaymentStatus = (app: any) => { if (!app.securityDeposits || app.securityDeposits.length === 0) return 'Awaiting Payment'; const s = app.overallStatus || app.status; - const relevantType = (s.includes('LOI') || s === 'PAYMENT_VERIFICATION' || s === 'Security Details') ? 'INITIAL' : 'FINAL'; + const relevantType = (s.includes('LOI') || s === 'PAYMENT_VERIFICATION' || s === 'Security Details') ? 'SECURITY_DEPOSIT' : 'FIRST_FILL'; const deposit = app.securityDeposits.find((d: any) => d.depositType === relevantType); return deposit ? deposit.status : 'Awaiting Payment'; }; diff --git a/src/components/applications/FinancePaymentDetailsPage.tsx b/src/components/applications/FinancePaymentDetailsPage.tsx index 6218ccc..c1f3807 100644 --- a/src/components/applications/FinancePaymentDetailsPage.tsx +++ b/src/components/applications/FinancePaymentDetailsPage.tsx @@ -33,7 +33,7 @@ interface FinancePaymentDetailsPageProps { export function FinancePaymentDetailsPage({ applicationId, onBack }: FinancePaymentDetailsPageProps) { const [application, setApplication] = useState(null); const [deposits, setDeposits] = useState([]); - const [activeType, setActiveType] = useState<'INITIAL' | 'FINAL'>('INITIAL'); + const [activeType, setActiveType] = useState<'SECURITY_DEPOSIT' | 'FIRST_FILL'>('SECURITY_DEPOSIT'); const [loading, setLoading] = useState(true); const [isSubmitting, setIsSubmitting] = useState(false); const [configs, setConfigs] = useState({}); @@ -68,7 +68,7 @@ export function FinancePaymentDetailsPage({ applicationId, onBack }: FinancePaym setPaymentDetails({ verificationTransactionId: '', - receivedAmount: activeType === 'INITIAL' ? initialDefault.toString() : finalDefault.toString(), + receivedAmount: activeType === 'SECURITY_DEPOSIT' ? initialDefault.toString() : finalDefault.toString(), receivedDate: new Date().toISOString().split('T')[0], verificationRemarks: '' }); @@ -110,7 +110,7 @@ export function FinancePaymentDetailsPage({ applicationId, onBack }: FinancePaym status: 'Verified' }); - toast.success(`${activeType === 'INITIAL' ? 'Security Deposit' : 'First Fill'} verified and approved`); + toast.success(`${activeType === 'SECURITY_DEPOSIT' ? 'Security Deposit' : 'First Fill'} verified and approved`); await fetchData(); } catch (error) { toast.error('Failed to verify payment'); @@ -134,7 +134,7 @@ export function FinancePaymentDetailsPage({ applicationId, onBack }: FinancePaym remarks: paymentDetails.verificationRemarks }); - toast.error(`${activeType === 'INITIAL' ? 'Security Deposit' : 'First Fill'} rejected`); + toast.error(`${activeType === 'SECURITY_DEPOSIT' ? 'Security Deposit' : 'First Fill'} rejected`); await fetchData(); } catch (error) { toast.error('Failed to reject payment'); @@ -167,17 +167,17 @@ export function FinancePaymentDetailsPage({ applicationId, onBack }: FinancePaym
@@ -210,7 +210,7 @@ export function FinancePaymentDetailsPage({ applicationId, onBack }: FinancePaym

- {activeType === 'INITIAL' ? 'Security Deposit' : 'First Fill'} + {activeType === 'SECURITY_DEPOSIT' ? 'Security Deposit' : 'First Fill'}

{activeDeposit?.status === 'Verified' @@ -274,7 +274,7 @@ export function FinancePaymentDetailsPage({ applicationId, onBack }: FinancePaym

- ₹{(activeType === 'INITIAL' + ₹{(activeType === 'SECURITY_DEPOSIT' ? (configs.SECURITY_DEPOSIT?.amount || 500000) : (configs.FIRST_FILL?.amount || 1500000) ).toLocaleString()} @@ -319,13 +319,13 @@ export function FinancePaymentDetailsPage({ applicationId, onBack }: FinancePaym {application.uploadedDocuments?.filter((d: any) => - activeType === 'INITIAL' + activeType === 'SECURITY_DEPOSIT' ? d.documentType?.toLowerCase().includes('security') && d.documentType?.toLowerCase().includes('deposit') : d.documentType?.toLowerCase().includes('first') && d.documentType?.toLowerCase().includes('fill') ).length > 0 ? (

{application.uploadedDocuments.filter((d: any) => - activeType === 'INITIAL' + activeType === 'SECURITY_DEPOSIT' ? d.documentType?.toLowerCase().includes('security') && d.documentType?.toLowerCase().includes('deposit') : d.documentType?.toLowerCase().includes('first') && d.documentType?.toLowerCase().includes('fill') ).map((doc: any, index: number) => ( @@ -393,7 +393,7 @@ export function FinancePaymentDetailsPage({ applicationId, onBack }: FinancePaym

Once verified, the following will occur:

    -
  • Applicant status will advance to {activeType === 'INITIAL' ? 'LOI Issuance' : 'LOA Approval'}
  • +
  • Applicant status will advance to {activeType === 'SECURITY_DEPOSIT' ? 'LOI Issuance' : 'LOA Approval'}
  • Email notification will be sent to Applicant
  • -
  • Digital {activeType === 'INITIAL' ? 'LOI' : 'LOA'} generation will be unlocked
  • -
  • This payment confirms the {activeType === 'INITIAL' ? 'Security Deposit' : 'First Fill'}
  • +
  • Digital {activeType === 'SECURITY_DEPOSIT' ? 'LOI' : 'LOA'} generation will be unlocked
  • +
  • This payment confirms the {activeType === 'SECURITY_DEPOSIT' ? 'Security Deposit' : 'First Fill'}
diff --git a/src/components/applications/ResignationDetails.tsx b/src/components/applications/ResignationDetails.tsx index 42b9f32..7f9abe1 100644 --- a/src/components/applications/ResignationDetails.tsx +++ b/src/components/applications/ResignationDetails.tsx @@ -313,33 +313,33 @@ export function ResignationDetails({ resignationId, onBack, currentUser }: Resig
-
- -

{resignationData?.outlet?.code}

-
-

{resignationData?.outlet?.name}

+

{resignationData?.dealer?.fullName || resignationData?.outlet?.name}

-

{resignationData?.outlet?.gstNumber || 'N/A'}

+

{resignationData?.dealer?.dealerProfile?.gstNumber || resignationData?.outlet?.gstNumber || 'N/A'}

+
+
+ +

{resignationData?.dealer?.dealerProfile?.dealerCode?.salesCode || 'N/A'}

+
+
+ +

{resignationData?.dealer?.dealerProfile?.dealerCode?.serviceCode || 'N/A'}

+
+
+ +

{resignationData?.dealer?.dealerProfile?.dealerCode?.gmaCode || 'N/A'}

+
+
+ +

{resignationData?.dealer?.dealerProfile?.dealerCode?.gearCode || 'N/A'}

-

{resignationData?.outlet?.address}

-
-
- -

{resignationData?.outlet?.city}

-
-
- -

{resignationData?.outlet?.state}

-
-
- -

{resignationData?.outlet?.region}

+

{resignationData?.dealer?.dealerProfile?.registeredAddress || resignationData?.outlet?.address}

@@ -353,11 +353,19 @@ export function ResignationDetails({ resignationId, onBack, currentUser }: Resig
-

{resignationData?.outlet?.inaugurationDate ? new Date(resignationData.outlet.inaugurationDate).toLocaleDateString() : 'N/A'}

+

{resignationData?.dealer?.dealerProfile?.onboardedAt ? formatDateTime(resignationData.dealer.dealerProfile.onboardedAt, 'date') : (resignationData?.outlet?.inaugurationDate ? new Date(resignationData.outlet.inaugurationDate).toLocaleDateString() : 'N/A')}

+
+
+ +

{resignationData?.dealer?.dealerProfile?.loaDate ? formatDateTime(resignationData.dealer.dealerProfile.loaDate, 'date') : 'N/A'}

+
+
+ +

{resignationData?.dealer?.dealerProfile?.loiDate ? formatDateTime(resignationData.dealer.dealerProfile.loiDate, 'date') : 'N/A'}

-

{resignationData?.outlet?.type || 'N/A'}

+

{resignationData?.dealer?.dealerProfile?.application?.businessType || resignationData?.outlet?.type || 'N/A'}

diff --git a/src/components/applications/TerminationDetails.tsx b/src/components/applications/TerminationDetails.tsx index 3aaae9a..2f08247 100644 --- a/src/components/applications/TerminationDetails.tsx +++ b/src/components/applications/TerminationDetails.tsx @@ -10,7 +10,7 @@ import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '. import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '../ui/table'; import { Alert, AlertDescription, AlertTitle } from '../ui/alert'; import { useState, useEffect } from 'react'; -import { User, mockWorkNotes } from '../../lib/mock-data'; +import { User } from '../../lib/mock-data'; import { toast } from 'sonner'; import { terminationService } from '../../services/termination.service'; import { useNavigate } from 'react-router-dom'; @@ -305,7 +305,7 @@ export function TerminationDetails({ terminationId, onBack, currentUser }: Termi } }; - const workNotesCount = mockWorkNotes.length; + const workNotesCount = (request.worknotes || []).length; return (
@@ -326,7 +326,7 @@ export function TerminationDetails({ terminationId, onBack, currentUser }: Termi

{request.requestId || terminationId}

-

{request.dealer?.businessName || request.dealerName}

+

{request.dealer?.businessName || request.dealer?.legalName || 'Termination'}

{request.severity} @@ -438,9 +438,9 @@ export function TerminationDetails({ terminationId, onBack, currentUser }: Termi className="relative hover:bg-red-50 hover:border-red-300 hover:text-red-700 transition-all shadow-sm" onClick={() => navigate(`/worknotes/termination/${terminationId}`, { state: { - applicationName: terminationData?.dealerName || 'Termination', + applicationName: request?.dealer?.businessName || 'Termination', registrationNumber: terminationId || '', - participants: terminationData?.participants || [] + participants: request?.participants || [] } })} > @@ -516,7 +516,11 @@ export function TerminationDetails({ terminationId, onBack, currentUser }: Termi
-

{request.dealer?.dealerCode?.gmaCode || request.gmaCode || 'N/A'}

+

{request.dealer?.dealerCode?.gmaCode || 'N/A'}

+
+
+ +

{request.dealer?.dealerCode?.gearCode || 'N/A'}

@@ -533,12 +537,12 @@ export function TerminationDetails({ terminationId, onBack, currentUser }: Termi

{request.dealer?.onboardedAt ? formatDateTime(request.dealer.onboardedAt, 'date') : (request.inauguration || 'N/A')}

- -

{request.loa || 'N/A'}

+ +

{request.dealer?.loaDate ? formatDateTime(request.dealer.loaDate, 'date') : 'N/A'}

- -

{request.loi || 'N/A'}

+ +

{request.dealer?.loiDate ? formatDateTime(request.dealer.loiDate, 'date') : 'N/A'}

diff --git a/src/components/applications/WorkNotesPage.tsx b/src/components/applications/WorkNotesPage.tsx index 837ec03..a4f20d7 100644 --- a/src/components/applications/WorkNotesPage.tsx +++ b/src/components/applications/WorkNotesPage.tsx @@ -253,32 +253,55 @@ export function WorkNotesPage(props: Partial) { } }, [requestId, requestType, socket]); - // Fetch application details if metadata or participants are missing (e.g. on refresh) + // Fetch details if metadata or participants are missing (e.g. on refresh) useEffect(() => { - if (requestId && requestType === 'application') { - const fetchApplicationDetails = async () => { - try { - const appData = await onboardingService.getApplicationById(requestId); - if (appData) { - // Update participants if not provided - if (externalParticipants.length === 0 && appData.participants) { - setExternalParticipants(appData.participants); - } - // Update metadata if not provided via props/state - if (!props.applicationName && !location.state?.applicationName && appData.companyName) { - setAppName(appData.companyName); - } - if (!props.registrationNumber && !location.state?.registrationNumber && appData.registrationNumber) { - setRegNumber(appData.registrationNumber); - } + if (!requestId || !requestType) return; + + const fetchDetails = async () => { + try { + let data: any = null; + if (requestType === 'application') { + data = await onboardingService.getApplicationById(requestId); + if (data) { + if (externalParticipants.length === 0 && data.participants) setExternalParticipants(data.participants); + if (!appName || appName === 'Application') setAppName(data.companyName || 'Application'); + if (!regNumber) setRegNumber(data.registrationNumber || ''); + } + } else if (requestType === 'termination') { + const { API } = await import('../../api/API'); + const res: any = await API.getTerminationById(requestId); + if (res.data?.success) { + data = res.data.termination; + if (externalParticipants.length === 0 && data.participants) setExternalParticipants(data.participants); + if (!appName || appName === 'Application' || appName === 'Termination') setAppName(data.dealer?.businessName || 'Termination'); + if (!regNumber) setRegNumber(data.requestId || ''); + } + } else if (requestType === 'constitutional' || requestType === 'constitutional-change') { + const { API } = await import('../../api/API'); + const res: any = await API.getConstitutionalChangeById(requestId); + if (res.data?.success) { + data = res.data.request; + if (externalParticipants.length === 0 && data.participants) setExternalParticipants(data.participants); + if (!appName || appName === 'Application' || appName === 'Constitutional Change') setAppName(data.outlet?.name || 'Constitutional Change'); + if (!regNumber) setRegNumber(data.requestId || ''); + } + } else if (requestType === 'resignation') { + const { API } = await import('../../api/API'); + const res: any = await API.getResignationById(requestId); + if (res.data?.success) { + data = res.data.resignation; + if (externalParticipants.length === 0 && data.participants) setExternalParticipants(data.participants); + if (!appName || appName === 'Application' || appName === 'Resignation') setAppName(data.dealer?.businessName || 'Resignation'); + if (!regNumber) setRegNumber(data.resignationId || ''); } - } catch (error) { - console.error('Failed to fetch application details:', error); } - }; - fetchApplicationDetails(); - } - }, [requestId, requestType, externalParticipants.length, props.applicationName, props.registrationNumber, location.state]); + } catch (error) { + console.error(`Failed to fetch ${requestType} details:`, error); + } + }; + + fetchDetails(); + }, [requestId, requestType, externalParticipants.length, appName, regNumber]); // Auto-scroll logic const messagesEndRef = useRef(null); diff --git a/src/components/dashboard/FinanceDashboard.tsx b/src/components/dashboard/FinanceDashboard.tsx index 540c403..044d219 100644 --- a/src/components/dashboard/FinanceDashboard.tsx +++ b/src/components/dashboard/FinanceDashboard.tsx @@ -311,7 +311,11 @@ export function FinanceDashboard({ onNavigate, onViewPaymentDetails, onViewAudit

Type

-

{app.paymentType}

+

+ {app.paymentType === 'SECURITY_DEPOSIT' ? 'Security Deposit' : + app.paymentType === 'FIRST_FILL' ? 'First Fill' : + app.paymentType} +

Amount

@@ -384,7 +388,11 @@ export function FinanceDashboard({ onNavigate, onViewPaymentDetails, onViewAudit

Type

-

{app.paymentType}

+

+ {app.paymentType === 'SECURITY_DEPOSIT' ? 'Security Deposit' : + app.paymentType === 'FIRST_FILL' ? 'First Fill' : + app.paymentType} +

Amount

diff --git a/src/lib/mock-data.ts b/src/lib/mock-data.ts index dd18c38..6710968 100644 --- a/src/lib/mock-data.ts +++ b/src/lib/mock-data.ts @@ -137,6 +137,7 @@ export interface Application { areaId?: string; districtId?: string; fddAssignments?: any[]; + statutoryStatus?: string; } export interface Participant { @@ -157,6 +158,7 @@ export interface User { email: string; password: string; role: UserRole; + roleCode?: string; avatar?: string; } diff --git a/src/store/slices/authSlice.ts b/src/store/slices/authSlice.ts index 83ca560..15a524a 100644 --- a/src/store/slices/authSlice.ts +++ b/src/store/slices/authSlice.ts @@ -36,7 +36,8 @@ export const initializeAuth = createAsyncThunk( name: user.fullName || user.email.split('@')[0], email: user.email, password: '', - role: typeof user.role === 'string' ? user.role : (user.roleCode || 'User') + role: typeof user.role === 'string' ? user.role : (user.roleCode || 'User'), + roleCode: user.roleCode || (typeof user.role === 'string' ? user.role : 'User') } as User, token };