Compare commits

..

2 Commits

17 changed files with 116 additions and 107 deletions

View File

@ -10,7 +10,7 @@ import { SharedSummaryDetail } from '@/pages/SharedSummaries/SharedSummaryDetail
import { WorkNotes } from '@/pages/WorkNotes'; import { WorkNotes } from '@/pages/WorkNotes';
import { CreateRequest } from '@/pages/CreateRequest'; import { CreateRequest } from '@/pages/CreateRequest';
import { ClaimManagementWizard } from '@/dealer-claim/components/request-creation/ClaimManagementWizard'; import { ClaimManagementWizard } from '@/dealer-claim/components/request-creation/ClaimManagementWizard';
import { DealerDashboard } from '@/dealer-claim/pages/Dashboard'; // import { DealerDashboard } from '@/dealer-claim/pages/Dashboard';
import { MyRequests } from '@/pages/MyRequests'; import { MyRequests } from '@/pages/MyRequests';
import { Requests } from '@/pages/Requests/Requests'; import { Requests } from '@/pages/Requests/Requests';
import { UserAllRequests } from '@/pages/Requests/UserAllRequests'; import { UserAllRequests } from '@/pages/Requests/UserAllRequests';
@ -84,7 +84,8 @@ function DashboardRoute({ onNavigate, onNewRequest }: { onNavigate?: (page: stri
// Render dealer-specific dashboard if user is a dealer // Render dealer-specific dashboard if user is a dealer
if (isDealer) { if (isDealer) {
return <DealerDashboard onNavigate={onNavigate} onNewRequest={onNewRequest} />; console.log("isDealer", isDealer)
// return <DealerDashboard onNavigate={onNavigate} onNewRequest={onNewRequest} />;
} }
// Render regular dashboard for all other users // Render regular dashboard for all other users

View File

@ -72,14 +72,15 @@ export function PageLayout({ children, currentPage = 'dashboard', onNavigate, on
const items = [ const items = [
{ id: 'dashboard', label: 'Dashboard', icon: Home }, { id: 'dashboard', label: 'Dashboard', icon: Home },
// Add "All Requests" for all users (admin sees org-level, regular users see their participant requests) // Add "All Requests" for all users (admin sees org-level, regular users see their participant requests)
{ id: 'requests', label: 'All Requests', icon: List, adminOnly: false } { id: 'requests', label: 'All Requests', icon: List, adminOnly: false },
{ id: 'my-requests', label: 'My Requests', icon: User }
// { id: 'admin/templates', label: 'Admin Templates', icon: Plus, adminOnly: true }, // { id: 'admin/templates', label: 'Admin Templates', icon: Plus, adminOnly: true },
]; ];
// Add remaining menu items (exclude "My Requests" for dealers) // Add remaining menu items (exclude "My Requests" for dealers)
if (!isDealer) { // if (!isDealer) {
items.push({ id: 'my-requests', label: 'My Requests', icon: User }); // items.push({ id: 'my-requests', label: 'My Requests', icon: User });
} // }
items.push( items.push(
{ id: 'open-requests', label: 'Open Requests', icon: FileText }, { id: 'open-requests', label: 'Open Requests', icon: FileText },
@ -107,6 +108,20 @@ export function PageLayout({ children, currentPage = 'dashboard', onNavigate, on
// Navigate to the request if URL provided // Navigate to the request if URL provided
if (notification.actionUrl && onNavigate) { if (notification.actionUrl && onNavigate) {
// PRIORITY: For shared summaries or specific action URLs, use them directly
if (notification.actionUrl && (
notification.notificationType === 'summary_shared' ||
notification.actionUrl.includes('shared-summaries')
)) {
console.log('[PageLayout] Navigating to shared summary:', notification.actionUrl);
const targetUrl = notification.actionUrl.startsWith('/')
? notification.actionUrl.substring(1)
: notification.actionUrl;
onNavigate(targetUrl);
setNotificationsOpen(false);
return;
}
// Extract request number from URL (e.g., /request/REQ-2025-12345) // Extract request number from URL (e.g., /request/REQ-2025-12345)
const requestNumber = notification.metadata?.requestNumber; const requestNumber = notification.metadata?.requestNumber;
if (requestNumber) { if (requestNumber) {
@ -275,7 +290,7 @@ export function PageLayout({ children, currentPage = 'dashboard', onNavigate, on
</div> </div>
{/* Quick Action in Sidebar - Right below menu items */} {/* Quick Action in Sidebar - Right below menu items */}
{!isDealer && ( {/* {!isDealer && ( */}
<div className="mt-6 pt-6 border-t border-gray-800 px-3"> <div className="mt-6 pt-6 border-t border-gray-800 px-3">
<Button <Button
onClick={onNewRequest} onClick={onNewRequest}
@ -286,7 +301,7 @@ export function PageLayout({ children, currentPage = 'dashboard', onNavigate, on
Raise New Request Raise New Request
</Button> </Button>
</div> </div>
)} {/* )} */}
</div> </div>
</div> </div>
</aside> </aside>

View File

@ -79,10 +79,10 @@ interface WorkNoteChatProps {
skipSocketJoin?: boolean; // Set to true when embedded in RequestDetail (to avoid double join) skipSocketJoin?: boolean; // Set to true when embedded in RequestDetail (to avoid double join)
requestTitle?: string; // Optional title for display requestTitle?: string; // Optional title for display
onAttachmentsExtracted?: (attachments: any[]) => void; // Callback to pass attachments to parent onAttachmentsExtracted?: (attachments: any[]) => void; // Callback to pass attachments to parent
isInitiator?: boolean; // Whether current user is the initiator
isSpectator?: boolean; // Whether current user is a spectator (view-only) isSpectator?: boolean; // Whether current user is a spectator (view-only)
currentLevels?: any[]; // Current approval levels for add approver modal currentLevels?: any[]; // Current approval levels for add approver modal
onAddApprover?: (email: string, tatHours: number, level: number) => Promise<void>; // Callback to add approver onAddApprover?: (email: string, tatHours: number, level: number) => Promise<void>; // Callback to add approver
canAddApprover?: boolean; // Whether the current user can add approvers
maxApprovalLevels?: number; // Maximum allowed approval levels from system policy maxApprovalLevels?: number; // Maximum allowed approval levels from system policy
onPolicyViolation?: (violations: Array<{ type: string; message: string; currentValue?: number; maxValue?: number }>) => void; // Callback for policy violations onPolicyViolation?: (violations: Array<{ type: string; message: string; currentValue?: number; maxValue?: number }>) => void; // Callback for policy violations
} }
@ -145,7 +145,7 @@ const FileIcon = ({ type }: { type: string }) => {
return <Paperclip className={`${iconClass} text-gray-600`} />; return <Paperclip className={`${iconClass} text-gray-600`} />;
}; };
export function WorkNoteChat({ requestId, messages: externalMessages, onSend, skipSocketJoin = false, requestTitle, onAttachmentsExtracted, isInitiator = false, isSpectator = false, currentLevels = [], onAddApprover, maxApprovalLevels, onPolicyViolation }: WorkNoteChatProps) { export function WorkNoteChat({ requestId, messages: externalMessages, onSend, skipSocketJoin = false, requestTitle, onAttachmentsExtracted, isSpectator = false, currentLevels = [], onAddApprover, canAddApprover, maxApprovalLevels, onPolicyViolation }: WorkNoteChatProps) {
const routeParams = useParams<{ requestId: string }>(); const routeParams = useParams<{ requestId: string }>();
const effectiveRequestId = requestId || routeParams.requestId || ''; const effectiveRequestId = requestId || routeParams.requestId || '';
const [message, setMessage] = useState(''); const [message, setMessage] = useState('');
@ -1743,8 +1743,8 @@ export function WorkNoteChat({ requestId, messages: externalMessages, onSend, sk
<div className="p-4 sm:p-6 flex-shrink-0"> <div className="p-4 sm:p-6 flex-shrink-0">
<h4 className="font-semibold text-gray-900 mb-3 text-sm sm:text-base">Quick Actions</h4> <h4 className="font-semibold text-gray-900 mb-3 text-sm sm:text-base">Quick Actions</h4>
<div className="space-y-2"> <div className="space-y-2">
{/* Only initiator can add approvers */} {/* Only initiator or current approver can add approvers in custom flows */}
{isInitiator && ( {canAddApprover && (
<Button <Button
variant="outline" variant="outline"
size="sm" size="sm"
@ -1805,7 +1805,7 @@ export function WorkNoteChat({ requestId, messages: externalMessages, onSend, sk
)} )}
{/* Add Approver Modal - Hide for spectators */} {/* Add Approver Modal - Hide for spectators */}
{!effectiveIsSpectator && isInitiator && ( {!effectiveIsSpectator && canAddApprover && (
<AddApproverModal <AddApproverModal
open={showAddApproverModal} open={showAddApproverModal}
onClose={() => setShowAddApproverModal(false)} onClose={() => setShowAddApproverModal(false)}

View File

@ -56,7 +56,8 @@ export function ApprovalWorkflowStep({
email: '', email: '',
name: '', name: '',
level: i + 1, level: i + 1,
tat: '' as any tat: 8 as any,
tatType: 'hours'
}; };
} }
} }
@ -373,9 +374,9 @@ export function ApprovalWorkflowStep({
<Input <Input
id={`tat-${level}`} id={`tat-${level}`}
type="number" type="number"
placeholder={approver.tatType === 'days' ? '7' : '24'} placeholder={approver.tatType === 'days' ? '1' : '8'}
min="1" min="1"
max={approver.tatType === 'days' ? '30' : '720'} max={approver.tatType === 'days' ? '90' : '720'}
value={approver.tat || ''} value={approver.tat || ''}
onChange={(e) => { onChange={(e) => {
const newApprovers = [...formData.approvers]; const newApprovers = [...formData.approvers];
@ -446,28 +447,7 @@ export function ApprovalWorkflowStep({
<div className="flex-1"> <div className="flex-1">
<div className="flex items-center justify-between mb-2"> <div className="flex items-center justify-between mb-2">
<h4 className="font-semibold text-emerald-900">TAT Summary</h4> <h4 className="font-semibold text-emerald-900">TAT Summary</h4>
<div className="text-right"> <div>
{(() => {
// Calculate total calendar days (for display)
// Days: count as calendar days
// Hours: convert to calendar days (hours / 24)
const totalCalendarDays = formData.approvers?.reduce((sum: number, a: any) => {
const tat = Number(a.tat || 0);
const tatType = a.tatType || 'hours';
if (tatType === 'days') {
return sum + tat; // Calendar days
} else {
return sum + (tat / 24); // Convert hours to calendar days
}
}, 0) || 0;
const displayDays = Math.ceil(totalCalendarDays);
return (
<>
<div className="text-lg font-bold text-emerald-800">{displayDays} {displayDays === 1 ? 'Day' : 'Days'}</div>
<div className="text-xs text-emerald-600">Total Duration</div>
</>
);
})()}
</div> </div>
</div> </div>
<div className="space-y-3"> <div className="space-y-3">
@ -475,8 +455,7 @@ export function ApprovalWorkflowStep({
{formData.approvers?.map((approver: any, idx: number) => { {formData.approvers?.map((approver: any, idx: number) => {
const tat = Number(approver.tat || 0); const tat = Number(approver.tat || 0);
const tatType = approver.tatType || 'hours'; const tatType = approver.tatType || 'hours';
// Convert days to hours: 1 day = 24 hours const hours = tatType === 'days' ? tat * 8 : tat;
const hours = tatType === 'days' ? tat * 24 : tat;
if (!tat) return null; if (!tat) return null;
return ( return (
<div key={idx} className="bg-white/60 p-2 rounded border border-emerald-100"> <div key={idx} className="bg-white/60 p-2 rounded border border-emerald-100">
@ -489,15 +468,12 @@ export function ApprovalWorkflowStep({
})} })}
</div> </div>
{(() => { {(() => {
// Convert all TAT to hours first
// Days: 1 day = 24 hours
// Hours: already in hours
const totalHours = formData.approvers?.reduce((sum: number, a: any) => { const totalHours = formData.approvers?.reduce((sum: number, a: any) => {
const tat = Number(a.tat || 0); const tat = Number(a.tat || 0);
const tatType = a.tatType || 'hours'; const tatType = a.tatType || 'hours';
if (tatType === 'days') { if (tatType === 'days') {
// 1 day = 24 hours // 1 day = 8 working hours
return sum + (tat * 24); return sum + (tat * 8);
} else { } else {
return sum + tat; return sum + tat;
} }
@ -509,12 +485,12 @@ export function ApprovalWorkflowStep({
<div className="bg-white/80 p-3 rounded border border-emerald-200"> <div className="bg-white/80 p-3 rounded border border-emerald-200">
<div className="grid grid-cols-2 gap-4 text-center"> <div className="grid grid-cols-2 gap-4 text-center">
<div> <div>
<div className="text-lg font-bold text-emerald-800">{totalHours}{totalHours === 1 ? 'h' : 'h'}</div> <div className="text-lg font-bold text-emerald-800">{totalHours}h</div>
<div className="text-xs text-emerald-600">Total Hours</div> <div className="text-xs text-emerald-600">Total Hours</div>
</div> </div>
<div> <div>
<div className="text-lg font-bold text-emerald-800">{workingDays}</div> <div className="text-lg font-bold text-emerald-800">{workingDays} {workingDays === 1 ? 'Day' : 'Days'}</div>
<div className="text-xs text-emerald-600">Working Days*</div> <div className="text-xs text-emerald-600">Total Days*</div>
</div> </div>
</div> </div>
<p className="text-xs text-emerald-600 mt-2 text-center">*Based on 8-hour working days</p> <p className="text-xs text-emerald-600 mt-2 text-center">*Based on 8-hour working days</p>

View File

@ -107,8 +107,8 @@ export function TemplateSelectionStep({
<p>No admin templates available yet.</p> <p>No admin templates available yet.</p>
</div> </div>
) : ( ) : (
displayTemplates.map((template) => { displayTemplates.map((template, index) => {
const isComingSoon = false; const isComingSoon = index === 1;
const isDisabled = isComingSoon; const isDisabled = isComingSoon;
const isCategoryCard = template.id === 'admin-templates-category'; const isCategoryCard = template.id === 'admin-templates-category';
// const isCustomCard = template.id === 'custom'; // const isCustomCard = template.id === 'custom';
@ -124,7 +124,7 @@ export function TemplateSelectionStep({
> >
<Card <Card
className={`h-full transition-all duration-300 border-2 ${isDisabled className={`h-full transition-all duration-300 border-2 ${isDisabled
? 'border-gray-200 bg-gray-50/50 opacity-85 cursor-not-allowed' ? 'border-gray-200 bg-gray-50/50 opacity-50 cursor-not-allowed'
: isSelected : isSelected
? 'border-blue-500 shadow-xl bg-blue-50/50 ring-2 ring-blue-200 cursor-pointer' ? 'border-blue-500 shadow-xl bg-blue-50/50 ring-2 ring-blue-200 cursor-pointer'
: isCategoryCard : isCategoryCard

View File

@ -31,14 +31,14 @@ export function StandardClosedRequestsFilters({
searchTerm, searchTerm,
priorityFilter, priorityFilter,
statusFilter, statusFilter,
templateTypeFilter, templateTypeFilter: _templateTypeFilter,
sortBy, sortBy,
sortOrder, sortOrder,
activeFiltersCount, activeFiltersCount,
onSearchChange, onSearchChange,
onPriorityChange, onPriorityChange,
onStatusChange, onStatusChange,
onTemplateTypeChange, onTemplateTypeChange: _onTemplateTypeChange,
onSortByChange, onSortByChange,
onSortOrderChange, onSortOrderChange,
onClearFilters, onClearFilters,
@ -131,7 +131,7 @@ export function StandardClosedRequestsFilters({
</SelectContent> </SelectContent>
</Select> </Select>
<Select value={templateTypeFilter} onValueChange={onTemplateTypeChange}> {/* <Select value={_templateTypeFilter} onValueChange={_onTemplateTypeChange}>
<SelectTrigger className="h-9 sm:h-10 md:h-11 text-sm sm:text-base bg-gray-50 border-gray-200 focus:bg-white" data-testid="closed-requests-template-type-filter"> <SelectTrigger className="h-9 sm:h-10 md:h-11 text-sm sm:text-base bg-gray-50 border-gray-200 focus:bg-white" data-testid="closed-requests-template-type-filter">
<SelectValue placeholder="All Templates" /> <SelectValue placeholder="All Templates" />
</SelectTrigger> </SelectTrigger>
@ -140,7 +140,7 @@ export function StandardClosedRequestsFilters({
<SelectItem value="CUSTOM">Non-Templatized</SelectItem> <SelectItem value="CUSTOM">Non-Templatized</SelectItem>
<SelectItem value="DEALER CLAIM">Dealer Claim</SelectItem> <SelectItem value="DEALER CLAIM">Dealer Claim</SelectItem>
</SelectContent> </SelectContent>
</Select> </Select> */}
<div className="flex gap-2"> <div className="flex gap-2">
<Select value={sortBy} onValueChange={(value) => onSortByChange(value as 'created' | 'due' | 'priority')}> <Select value={sortBy} onValueChange={(value) => onSortByChange(value as 'created' | 'due' | 'priority')}>

View File

@ -31,13 +31,13 @@ export function StandardRequestsFilters({
searchTerm, searchTerm,
statusFilter, statusFilter,
priorityFilter, priorityFilter,
templateTypeFilter, templateTypeFilter: _templateTypeFilter,
sortBy, sortBy,
sortOrder, sortOrder,
onSearchChange, onSearchChange,
onStatusFilterChange, onStatusFilterChange,
onPriorityFilterChange, onPriorityFilterChange,
onTemplateTypeFilterChange, onTemplateTypeFilterChange: _onTemplateTypeFilterChange,
onSortByChange, onSortByChange,
onSortOrderChange, onSortOrderChange,
onClearFilters, onClearFilters,
@ -120,7 +120,7 @@ export function StandardRequestsFilters({
</SelectContent> </SelectContent>
</Select> </Select>
<Select value={templateTypeFilter} onValueChange={onTemplateTypeFilterChange}> {/* <Select value={templateTypeFilter} onValueChange={onTemplateTypeFilterChange}>
<SelectTrigger className="h-9 sm:h-10 md:h-11 text-sm sm:text-base bg-gray-50 border-gray-200 focus:bg-white focus:border-blue-400 focus:ring-1 focus:ring-blue-200"> <SelectTrigger className="h-9 sm:h-10 md:h-11 text-sm sm:text-base bg-gray-50 border-gray-200 focus:bg-white focus:border-blue-400 focus:ring-1 focus:ring-blue-200">
<SelectValue placeholder="All Templates" /> <SelectValue placeholder="All Templates" />
</SelectTrigger> </SelectTrigger>
@ -129,7 +129,7 @@ export function StandardRequestsFilters({
<SelectItem value="CUSTOM">Non-Templatized</SelectItem> <SelectItem value="CUSTOM">Non-Templatized</SelectItem>
<SelectItem value="DEALER CLAIM">Dealer Claim</SelectItem> <SelectItem value="DEALER CLAIM">Dealer Claim</SelectItem>
</SelectContent> </SelectContent>
</Select> </Select> */}
<div className="flex gap-2"> <div className="flex gap-2">
<Select value={sortBy} onValueChange={(value: any) => onSortByChange(value)}> <Select value={sortBy} onValueChange={(value: any) => onSortByChange(value)}>

View File

@ -87,7 +87,7 @@ export function StandardUserAllRequestsFilters({
searchTerm, searchTerm,
statusFilter, statusFilter,
priorityFilter, priorityFilter,
templateTypeFilter, templateTypeFilter: _templateTypeFilter,
departmentFilter, departmentFilter,
slaComplianceFilter, slaComplianceFilter,
initiatorFilter: _initiatorFilter, initiatorFilter: _initiatorFilter,
@ -104,7 +104,7 @@ export function StandardUserAllRequestsFilters({
onSearchChange, onSearchChange,
onStatusChange, onStatusChange,
onPriorityChange, onPriorityChange,
onTemplateTypeChange, onTemplateTypeChange: _onTemplateTypeChange,
onDepartmentChange, onDepartmentChange,
onSlaComplianceChange, onSlaComplianceChange,
onInitiatorChange: _onInitiatorChange, onInitiatorChange: _onInitiatorChange,
@ -180,7 +180,7 @@ export function StandardUserAllRequestsFilters({
</SelectContent> </SelectContent>
</Select> </Select>
<Select value={templateTypeFilter} onValueChange={onTemplateTypeChange}> {/* <Select value={_templateTypeFilter} onValueChange={_onTemplateTypeChange}>
<SelectTrigger className="h-10" data-testid="template-type-filter"> <SelectTrigger className="h-10" data-testid="template-type-filter">
<SelectValue placeholder="All Templates" /> <SelectValue placeholder="All Templates" />
</SelectTrigger> </SelectTrigger>
@ -189,7 +189,7 @@ export function StandardUserAllRequestsFilters({
<SelectItem value="CUSTOM">Custom</SelectItem> <SelectItem value="CUSTOM">Custom</SelectItem>
<SelectItem value="DEALER CLAIM">Dealer Claim</SelectItem> <SelectItem value="DEALER CLAIM">Dealer Claim</SelectItem>
</SelectContent> </SelectContent>
</Select> </Select> */}
<Select <Select
value={departmentFilter} value={departmentFilter}

View File

@ -47,6 +47,9 @@ import { CustomOverviewTab, CustomWorkflowTab } from '../index';
import { SharedComponents } from '@/shared/components'; import { SharedComponents } from '@/shared/components';
const { DocumentsTab, ActivityTab, WorkNotesTab, SummaryTab, RequestDetailHeader, QuickActionsSidebar, RequestDetailModals } = SharedComponents; const { DocumentsTab, ActivityTab, WorkNotesTab, SummaryTab, RequestDetailHeader, QuickActionsSidebar, RequestDetailModals } = SharedComponents;
// Utilities
import { isCustomRequest } from '@/utils/requestTypeUtils';
// Other components // Other components
import { ShareSummaryModal } from '@/components/modals/ShareSummaryModal'; import { ShareSummaryModal } from '@/components/modals/ShareSummaryModal';
import { getSummaryDetails, getSummaryByRequestId, type SummaryDetails } from '@/services/summaryApi'; import { getSummaryDetails, getSummaryByRequestId, type SummaryDetails } from '@/services/summaryApi';
@ -569,10 +572,10 @@ function CustomRequestDetailInner({ requestId: propRequestId, onBack, dynamicReq
requestTitle={request.title} requestTitle={request.title}
mergedMessages={mergedMessages} mergedMessages={mergedMessages}
setWorkNoteAttachments={setWorkNoteAttachments} setWorkNoteAttachments={setWorkNoteAttachments}
isInitiator={isInitiator}
isSpectator={isSpectator} isSpectator={isSpectator}
currentLevels={currentLevels} currentLevels={currentLevels}
onAddApprover={handleAddApprover} onAddApprover={handleAddApprover}
canAddApprover={(isInitiator || !!currentApprovalLevel) && isCustomRequest(apiRequest)}
maxApprovalLevels={systemPolicy.maxApprovalLevels} maxApprovalLevels={systemPolicy.maxApprovalLevels}
onPolicyViolation={(violations) => setPolicyViolationModal({ open: true, violations })} onPolicyViolation={(violations) => setPolicyViolationModal({ open: true, violations })}
/> />

View File

@ -661,10 +661,10 @@ function DealerClaimRequestDetailInner({ requestId: propRequestId, onBack, dynam
requestTitle={request.title} requestTitle={request.title}
mergedMessages={mergedMessages} mergedMessages={mergedMessages}
setWorkNoteAttachments={setWorkNoteAttachments} setWorkNoteAttachments={setWorkNoteAttachments}
isInitiator={isInitiator}
isSpectator={isSpectator} isSpectator={isSpectator}
currentLevels={currentLevels} currentLevels={currentLevels}
onAddApprover={handleAddApprover} onAddApprover={handleAddApprover}
canAddApprover={false} // Explicitly disabled for Dealer Claims
maxApprovalLevels={systemPolicy.maxApprovalLevels} maxApprovalLevels={systemPolicy.maxApprovalLevels}
onPolicyViolation={(violations) => setPolicyViolationModal({ open: true, violations })} onPolicyViolation={(violations) => setPolicyViolationModal({ open: true, violations })}
/> />

View File

@ -2,13 +2,13 @@ import { useState, useEffect } from 'react';
import { useAuth } from '@/contexts/AuthContext'; import { useAuth } from '@/contexts/AuthContext';
import { Button } from '@/components/ui/button'; import { Button } from '@/components/ui/button';
import { Card, CardContent, CardHeader } from '@/components/ui/card'; import { Card, CardContent, CardHeader } from '@/components/ui/card';
import { LogIn, Shield } from 'lucide-react'; import { LogIn } from 'lucide-react';
import { ReLogo, LandingPageImage } from '@/assets'; import { ReLogo, LandingPageImage } from '@/assets';
import { initiateTanflowLogin } from '@/services/tanflowAuth'; // import { initiateTanflowLogin } from '@/services/tanflowAuth';
export function Auth() { export function Auth() {
const { login, isLoading, error } = useAuth(); const { login, isLoading, error } = useAuth();
const [tanflowLoading, setTanflowLoading] = useState(false); const [tanflowLoading] = useState(false);
const [imageLoaded, setImageLoaded] = useState(false); const [imageLoaded, setImageLoaded] = useState(false);
// Preload the background image // Preload the background image
@ -41,21 +41,21 @@ export function Auth() {
} }
}; };
const handleTanflowLogin = () => { // const handleTanflowLogin = () => {
// Clear any existing session data // // Clear any existing session data
localStorage.clear(); // localStorage.clear();
sessionStorage.clear(); // sessionStorage.clear();
setTanflowLoading(true); // setTanflowLoading(true);
try { // try {
initiateTanflowLogin(); // initiateTanflowLogin();
} catch (loginError) { // } catch (loginError) {
console.error('========================================'); // console.error('========================================');
console.error('TANFLOW LOGIN ERROR'); // console.error('TANFLOW LOGIN ERROR');
console.error('Error details:', loginError); // console.error('Error details:', loginError);
setTanflowLoading(false); // setTanflowLoading(false);
} // }
}; // };
if (error) { if (error) {
console.error('Auth Error in Auth Component:', { console.error('Auth Error in Auth Component:', {
@ -124,7 +124,7 @@ export function Auth() {
)} )}
</Button> </Button>
<div className="relative"> {/* <div className="relative">
<div className="absolute inset-0 flex items-center"> <div className="absolute inset-0 flex items-center">
<span className="w-full border-t border-gray-700"></span> <span className="w-full border-t border-gray-700"></span>
</div> </div>
@ -152,7 +152,7 @@ export function Auth() {
Dealer Login Dealer Login
</> </>
)} )}
</Button> </Button> */}
</div> </div>
<div className="text-center text-sm text-gray-400 mt-4"> <div className="text-center text-sm text-gray-400 mt-4">

View File

@ -22,11 +22,11 @@ export function MyRequestsFilters({
searchTerm, searchTerm,
statusFilter, statusFilter,
priorityFilter, priorityFilter,
templateTypeFilter, templateTypeFilter: _templateTypeFilter,
onSearchChange, onSearchChange,
onStatusChange, onStatusChange,
onPriorityChange, onPriorityChange,
onTemplateTypeChange, onTemplateTypeChange: _onTemplateTypeChange,
}: MyRequestsFiltersProps) { }: MyRequestsFiltersProps) {
return ( return (
<Card className="border-gray-200" data-testid="my-requests-filters"> <Card className="border-gray-200" data-testid="my-requests-filters">
@ -76,7 +76,7 @@ export function MyRequestsFilters({
</SelectContent> </SelectContent>
</Select> </Select>
<Select value={templateTypeFilter} onValueChange={onTemplateTypeChange}> {/* <Select value={_templateTypeFilter} onValueChange={_onTemplateTypeChange}>
<SelectTrigger <SelectTrigger
className="flex-1 md:w-28 lg:w-32 text-xs sm:text-sm bg-white border-gray-300 hover:border-gray-400 focus:border-blue-400 focus:ring-1 focus:ring-blue-200 h-9 sm:h-10" className="flex-1 md:w-28 lg:w-32 text-xs sm:text-sm bg-white border-gray-300 hover:border-gray-400 focus:border-blue-400 focus:ring-1 focus:ring-blue-200 h-9 sm:h-10"
data-testid="template-type-filter" data-testid="template-type-filter"
@ -88,7 +88,7 @@ export function MyRequestsFilters({
<SelectItem value="CUSTOM">Non-Templatized</SelectItem> <SelectItem value="CUSTOM">Non-Templatized</SelectItem>
<SelectItem value="DEALER CLAIM">Dealer Claim</SelectItem> <SelectItem value="DEALER CLAIM">Dealer Claim</SelectItem>
</SelectContent> </SelectContent>
</Select> </Select> */}
</div> </div>
</div> </div>
</CardContent> </CardContent>

View File

@ -76,6 +76,19 @@ export function Notifications({ onNavigate }: NotificationsProps) {
// Navigate to the request if URL provided // Navigate to the request if URL provided
if (notification.actionUrl && onNavigate) { if (notification.actionUrl && onNavigate) {
// PRIORITY: For shared summaries or specific action URLs, use them directly
if (notification.actionUrl && (
notification.notificationType === 'summary_shared' ||
notification.actionUrl.includes('shared-summaries')
)) {
console.log('[Notifications] Navigating to shared summary:', notification.actionUrl);
const targetUrl = notification.actionUrl.startsWith('/')
? notification.actionUrl.substring(1)
: notification.actionUrl;
onNavigate(targetUrl);
return;
}
const requestNumber = notification.metadata?.requestNumber; const requestNumber = notification.metadata?.requestNumber;
if (requestNumber) { if (requestNumber) {
let navigationUrl = `request/${requestNumber}`; let navigationUrl = `request/${requestNumber}`;

View File

@ -13,6 +13,7 @@ import notificationApi, { type Notification } from '@/services/notificationApi';
import { ProcessDetailsCard } from '@/dealer-claim/components/request-detail/claim-cards'; import { ProcessDetailsCard } from '@/dealer-claim/components/request-detail/claim-cards';
import { isClaimManagementRequest } from '@/utils/claimRequestUtils'; import { isClaimManagementRequest } from '@/utils/claimRequestUtils';
import { determineUserRole, getRoleBasedVisibility, mapToClaimManagementRequest } from '@/utils/claimDataMapper'; import { determineUserRole, getRoleBasedVisibility, mapToClaimManagementRequest } from '@/utils/claimDataMapper';
import { isCustomRequest } from '@/utils/requestTypeUtils';
interface QuickActionsSidebarProps { interface QuickActionsSidebarProps {
request: any; request: any;
@ -145,8 +146,8 @@ export function QuickActionsSidebar({
<CardTitle className="text-sm sm:text-base">Quick Actions</CardTitle> <CardTitle className="text-sm sm:text-base">Quick Actions</CardTitle>
</CardHeader> </CardHeader>
<CardContent className="space-y-2"> <CardContent className="space-y-2">
{/* Add Approver */} {/* Add Approver - Only for Initiator or Current Approver in Custom Workflows */}
{isInitiator && request.status !== 'closed' && ( {(isInitiator || currentApprovalLevel) && isCustomRequest(request) && request.status !== 'closed' && (
<Button <Button
variant="outline" variant="outline"
className="w-full justify-start gap-2 bg-white text-gray-700 border-gray-300 hover:bg-gray-50 hover:text-gray-900 h-9 sm:h-10 text-xs sm:text-sm" className="w-full justify-start gap-2 bg-white text-gray-700 border-gray-300 hover:bg-gray-50 hover:text-gray-900 h-9 sm:h-10 text-xs sm:text-sm"

View File

@ -9,10 +9,10 @@ interface WorkNotesTabProps {
requestTitle: string; requestTitle: string;
mergedMessages: any[]; mergedMessages: any[];
setWorkNoteAttachments: (attachments: any[]) => void; setWorkNoteAttachments: (attachments: any[]) => void;
isInitiator: boolean;
isSpectator: boolean; isSpectator: boolean;
currentLevels: any[]; currentLevels: any[];
onAddApprover: (email: string, tatHours: number, level: number) => Promise<void>; onAddApprover: (email: string, tatHours: number, level: number) => Promise<void>;
canAddApprover?: boolean;
maxApprovalLevels?: number; maxApprovalLevels?: number;
onPolicyViolation?: (violations: Array<{ type: string; message: string; currentValue?: number; maxValue?: number }>) => void; onPolicyViolation?: (violations: Array<{ type: string; message: string; currentValue?: number; maxValue?: number }>) => void;
} }
@ -22,10 +22,10 @@ export function WorkNotesTab({
requestTitle, requestTitle,
mergedMessages, mergedMessages,
setWorkNoteAttachments, setWorkNoteAttachments,
isInitiator,
isSpectator, isSpectator,
currentLevels, currentLevels,
onAddApprover, onAddApprover,
canAddApprover,
maxApprovalLevels, maxApprovalLevels,
onPolicyViolation, onPolicyViolation,
}: WorkNotesTabProps) { }: WorkNotesTabProps) {
@ -37,10 +37,10 @@ export function WorkNotesTab({
skipSocketJoin={true} skipSocketJoin={true}
messages={mergedMessages} messages={mergedMessages}
onAttachmentsExtracted={setWorkNoteAttachments} onAttachmentsExtracted={setWorkNoteAttachments}
isInitiator={isInitiator}
isSpectator={isSpectator} isSpectator={isSpectator}
currentLevels={currentLevels} currentLevels={currentLevels}
onAddApprover={onAddApprover} onAddApprover={onAddApprover}
canAddApprover={canAddApprover}
maxApprovalLevels={maxApprovalLevels} maxApprovalLevels={maxApprovalLevels}
onPolicyViolation={onPolicyViolation} onPolicyViolation={onPolicyViolation}
/> />

View File

@ -574,7 +574,7 @@ export function Requests({ onViewRequest }: RequestsProps) {
</SelectContent> </SelectContent>
</Select> </Select>
<Select value={filters.templateTypeFilter} onValueChange={filters.setTemplateTypeFilter}> {/* <Select value={filters.templateTypeFilter} onValueChange={filters.setTemplateTypeFilter}>
<SelectTrigger className="h-10" data-testid="template-type-filter"> <SelectTrigger className="h-10" data-testid="template-type-filter">
<SelectValue placeholder="All Templates" /> <SelectValue placeholder="All Templates" />
</SelectTrigger> </SelectTrigger>
@ -583,7 +583,7 @@ export function Requests({ onViewRequest }: RequestsProps) {
<SelectItem value="CUSTOM">Non-Templatized</SelectItem> <SelectItem value="CUSTOM">Non-Templatized</SelectItem>
<SelectItem value="DEALER CLAIM">Dealer Claim</SelectItem> <SelectItem value="DEALER CLAIM">Dealer Claim</SelectItem>
</SelectContent> </SelectContent>
</Select> </Select> */}
<Select <Select
value={filters.departmentFilter} value={filters.departmentFilter}

View File

@ -200,14 +200,14 @@ export function Settings() {
<span className="hidden sm:inline">Holidays</span> <span className="hidden sm:inline">Holidays</span>
<span className="sm:hidden">Holidays</span> <span className="sm:hidden">Holidays</span>
</TabsTrigger> </TabsTrigger>
<TabsTrigger {/* <TabsTrigger
value="templates" value="templates"
className="flex items-center justify-center gap-2 py-3 rounded-lg data-[state=active]:bg-white data-[state=active]:shadow-md transition-all" className="flex items-center justify-center gap-2 py-3 rounded-lg data-[state=active]:bg-white data-[state=active]:shadow-md transition-all"
> >
<FileText className="w-4 h-4" /> <FileText className="w-4 h-4" />
<span className="hidden sm:inline">Templates</span> <span className="hidden sm:inline">Templates</span>
<span className="sm:hidden">Templates</span> <span className="sm:hidden">Templates</span>
</TabsTrigger> </TabsTrigger> */}
</TabsList> </TabsList>
{/* Fixed width container to prevent layout shifts */} {/* Fixed width container to prevent layout shifts */}