From 058ab976005670af548a1cbbe7797e2a56aa94a2 Mon Sep 17 00:00:00 2001 From: laxmanhalaki Date: Wed, 24 Dec 2025 20:40:29 +0530 Subject: [PATCH] dealer dropdwn addd wit io remark mandatory in io tab --- .../ClaimManagementWizard.tsx | 312 ++++++++++-------- .../components/request-detail/IOTab.tsx | 32 +- .../modals/CreditNoteSAPModal.tsx | 2 +- .../request-detail/modals/DMSPushModal.css | 26 +- .../modals/DealerCompletionDocumentsModal.css | 26 +- .../modals/DealerProposalModal.css | 26 +- .../modals/DeptLeadIOApprovalModal.css | 26 +- .../modals/EditClaimAmountModal.tsx | 2 +- .../modals/EmailNotificationTemplateModal.tsx | 2 +- src/services/dealerApi.ts | 57 +++- src/services/workflowApi.ts | 36 +- 11 files changed, 347 insertions(+), 200 deletions(-) diff --git a/src/dealer-claim/components/request-creation/ClaimManagementWizard.tsx b/src/dealer-claim/components/request-creation/ClaimManagementWizard.tsx index daa5266..9bd3c5e 100644 --- a/src/dealer-claim/components/request-creation/ClaimManagementWizard.tsx +++ b/src/dealer-claim/components/request-creation/ClaimManagementWizard.tsx @@ -1,4 +1,4 @@ -import { useState, useEffect } from 'react'; +import { useState, useEffect, useRef } from 'react'; import { useNavigate } from 'react-router-dom'; import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'; import { Button } from '@/components/ui/button'; @@ -24,11 +24,10 @@ import { Info, FileText, Users, - AlertCircle, } from 'lucide-react'; import { format } from 'date-fns'; import { toast } from 'sonner'; -import { getAllDealers as fetchDealersFromAPI, getDealerByCode, type DealerInfo } from '@/services/dealerApi'; +import { getAllDealers as fetchDealersFromAPI, verifyDealerLogin, type DealerInfo } from '@/services/dealerApi'; import { ClaimApproverSelectionStep } from './ClaimApproverSelectionStep'; import { useAuth } from '@/contexts/AuthContext'; @@ -77,7 +76,12 @@ export function ClaimManagementWizard({ onBack, onSubmit }: ClaimManagementWizar const [currentStep, setCurrentStep] = useState(1); const [dealers, setDealers] = useState([]); const [loadingDealers, setLoadingDealers] = useState(true); - const [isDealerUser, setIsDealerUser] = useState(false); + const [searchTerm, setSearchTerm] = useState(''); + const [verifyingDealer, setVerifyingDealer] = useState(false); + const [dealerSearchResults, setDealerSearchResults] = useState([]); + const [dealerSearchLoading, setDealerSearchLoading] = useState(false); + const [dealerSearchInput, setDealerSearchInput] = useState(''); + const dealerSearchTimer = useRef(null); const [formData, setFormData] = useState({ activityName: '', @@ -110,42 +114,12 @@ export function ClaimManagementWizard({ onBack, onSubmit }: ClaimManagementWizar const totalSteps = STEP_NAMES.length; - // Check if user is a Dealer and prevent access - useEffect(() => { - const userDesignation = (user as any)?.designation?.toLowerCase() || ''; - const isDealer = userDesignation === 'dealer' || userDesignation.includes('dealer'); - - if (isDealer) { - setIsDealerUser(true); - toast.error('Dealers are not allowed to create claim requests. Please contact your administrator.'); - console.warn('Dealer user attempted to create claim request:', { - userId: (user as any)?.userId, - email: (user as any)?.email, - designation: (user as any)?.designation, - }); - - // Redirect back after a short delay - setTimeout(() => { - if (onBack) { - onBack(); - } else { - navigate('/'); - } - }, 2000); - } - }, [user, navigate, onBack]); - // Fetch dealers from API on component mount useEffect(() => { - // Don't fetch dealers if user is a Dealer - if (isDealerUser) { - return; - } - const fetchDealers = async () => { setLoadingDealers(true); try { - const fetchedDealers = await fetchDealersFromAPI(); + const fetchedDealers = await fetchDealersFromAPI(undefined, 10); // Limit to 10 records setDealers(fetchedDealers); } catch (error) { toast.error('Failed to load dealer list.'); @@ -155,7 +129,40 @@ export function ClaimManagementWizard({ onBack, onSubmit }: ClaimManagementWizar } }; fetchDealers(); - }, [isDealerUser]); + }, []); + + // Handle dealer search input with debouncing + const handleDealerSearchInputChange = (value: string) => { + setDealerSearchInput(value); + + // Clear previous timer + if (dealerSearchTimer.current) { + clearTimeout(dealerSearchTimer.current); + } + + // If input is empty, clear results + if (!value || value.trim().length < 2) { + setDealerSearchResults([]); + setDealerSearchLoading(false); + return; + } + + // Set loading state + setDealerSearchLoading(true); + + // Debounce search + dealerSearchTimer.current = setTimeout(async () => { + try { + const results = await fetchDealersFromAPI(value, 10); // Limit to 10 results + setDealerSearchResults(results); + } catch (error) { + console.error('Error searching dealers:', error); + setDealerSearchResults([]); + } finally { + setDealerSearchLoading(false); + } + }, 300); + }; const updateFormData = (field: string, value: any) => { setFormData(prev => { @@ -244,26 +251,54 @@ export function ClaimManagementWizard({ onBack, onSubmit }: ClaimManagementWizar } }; - const handleDealerChange = async (dealerCode: string) => { - const selectedDealer = dealers.find(d => d.dealerCode === dealerCode); - if (selectedDealer) { - updateFormData('dealerCode', dealerCode); - updateFormData('dealerName', selectedDealer.dealerName); - updateFormData('dealerEmail', selectedDealer.email || ''); - updateFormData('dealerPhone', selectedDealer.phone || ''); + const handleDealerSelect = async (selectedDealer: DealerInfo) => { + // Verify dealer is logged in + setVerifyingDealer(true); + try { + const verifiedDealer = await verifyDealerLogin(selectedDealer.dealerCode); + + if (!verifiedDealer.isLoggedIn) { + toast.error( + `Dealer "${verifiedDealer.dealerName || verifiedDealer.displayName}" (${verifiedDealer.dealerCode}) has not logged in to the system. Please ask them to log in first.`, + { duration: 5000 } + ); + // Clear the selection + setDealerSearchInput(''); + setDealerSearchResults([]); + updateFormData('dealerCode', ''); + updateFormData('dealerName', ''); + updateFormData('dealerEmail', ''); + updateFormData('dealerPhone', ''); + updateFormData('dealerAddress', ''); + setVerifyingDealer(false); + return; + } + + // Dealer is logged in, update form data + updateFormData('dealerCode', verifiedDealer.dealerCode); + updateFormData('dealerName', verifiedDealer.dealerName || verifiedDealer.displayName); + updateFormData('dealerEmail', verifiedDealer.email || ''); + updateFormData('dealerPhone', verifiedDealer.phone || ''); updateFormData('dealerAddress', ''); // Address not available in API response - // Try to fetch full dealer info from API - try { - const fullDealerInfo = await getDealerByCode(dealerCode); - if (fullDealerInfo) { - updateFormData('dealerEmail', fullDealerInfo.email || selectedDealer.email || ''); - updateFormData('dealerPhone', fullDealerInfo.phone || selectedDealer.phone || ''); - } - } catch (error) { - // Ignore error, use basic info from list - console.debug('Could not fetch full dealer info:', error); - } + // Clear search input and results + setDealerSearchInput(verifiedDealer.dealerName || verifiedDealer.displayName); + setDealerSearchResults([]); + + toast.success(`Dealer "${verifiedDealer.dealerName || verifiedDealer.displayName}" verified and logged in`); + } catch (error: any) { + const errorMessage = error.message || 'Failed to verify dealer login'; + toast.error(errorMessage, { duration: 5000 }); + // Clear the selection + setDealerSearchInput(''); + setDealerSearchResults([]); + updateFormData('dealerCode', ''); + updateFormData('dealerName', ''); + updateFormData('dealerEmail', ''); + updateFormData('dealerPhone', ''); + updateFormData('dealerAddress', ''); + } finally { + setVerifyingDealer(false); } }; @@ -386,38 +421,102 @@ export function ClaimManagementWizard({ onBack, onSubmit }: ClaimManagementWizar {/* Dealer Selection */}
- { + if (formData.dealerCode) { + // If dealer is already selected, clear selection first + updateFormData('dealerCode', ''); + updateFormData('dealerName', ''); + updateFormData('dealerEmail', ''); + updateFormData('dealerPhone', ''); + updateFormData('dealerAddress', ''); + setDealerSearchInput(e.target.value); + } else { + handleDealerSearchInputChange(e.target.value); + } + }} + onFocus={() => { + // When input is focused, show search results if input has value + if (dealerSearchInput && dealerSearchInput.length >= 2) { + handleDealerSearchInputChange(dealerSearchInput); + } + }} + className="h-12 border-2 border-gray-300 focus:border-blue-500" + disabled={verifyingDealer} + /> + {formData.dealerCode && ( +
+ + + Verified + +
)} - - + {/* Search suggestions dropdown */} + {(dealerSearchLoading || dealerSearchResults.length > 0) && !formData.dealerCode && ( +
+ {dealerSearchLoading ? ( +
Searching...
+ ) : ( +
    + {dealerSearchResults.map((dealer) => ( +
  • handleDealerSelect(dealer)} + > +
    +
    +
    + {dealer.dealerName || dealer.displayName} +
    +
    + {dealer.dealerCode} + {dealer.email && ( + <> + + {dealer.email} + + )} +
    + {dealer.city && dealer.state && ( +
    + {dealer.city}, {dealer.state} +
    + )} +
    +
    + {dealer.isLoggedIn ? ( + + + Logged In + + ) : ( + Not Logged In + )} +
    +
    +
  • + ))} +
+ )} +
+ )} +
+ {formData.dealerCode && ( -

- Selected: {formData.dealerName} ({formData.dealerCode}) -

+
+

+ Selected: {formData.dealerName} ({formData.dealerCode}) +

+ {formData.dealerEmail && ( +

Email: {formData.dealerEmail}

+ )} +
)} @@ -821,51 +920,6 @@ export function ClaimManagementWizard({ onBack, onSubmit }: ClaimManagementWizar } }; - // Show access denied message if user is a Dealer - if (isDealerUser) { - return ( -
-
-
- -
- - - -
-
- -
-

Access Denied

-

- Dealers are not allowed to create claim requests. Only internal employees can initiate claim requests. -

-

- If you believe this is an error, please contact your administrator. -

- -
-
-
-
-
- ); - } - return (
diff --git a/src/dealer-claim/components/request-detail/IOTab.tsx b/src/dealer-claim/components/request-detail/IOTab.tsx index 2d166c6..2fc07a6 100644 --- a/src/dealer-claim/components/request-detail/IOTab.tsx +++ b/src/dealer-claim/components/request-detail/IOTab.tsx @@ -193,6 +193,11 @@ export function IOTab({ request, apiRequest, onRefresh }: IOTabProps) { return; } + if (!ioRemark.trim()) { + toast.error('Please enter IO remark before blocking the amount'); + return; + } + if (!requestId) { toast.error('Request ID not found'); return; @@ -348,10 +353,13 @@ export function IOTab({ request, apiRequest, onRefresh }: IOTabProps) {