summary shared to implemented
This commit is contained in:
parent
f883bd34d8
commit
3dbe5e6900
@ -228,7 +228,7 @@ export function PageLayout({ children, currentPage = 'dashboard', onNavigate, on
|
|||||||
alt="Royal Enfield Logo"
|
alt="Royal Enfield Logo"
|
||||||
className="h-10 w-auto max-w-[168px] object-contain"
|
className="h-10 w-auto max-w-[168px] object-contain"
|
||||||
/>
|
/>
|
||||||
<p className="text-xs text-gray-400 text-center mt-1 truncate">Approval Portal</p>
|
<p className="text-xs text-gray-400 text-center mt-1 truncate">RE Flow</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="p-3 flex-1 overflow-y-auto">
|
<div className="p-3 flex-1 overflow-y-auto">
|
||||||
|
|||||||
@ -104,6 +104,7 @@ function RequestDetailInner({ requestId: propRequestId, onBack, dynamicRequests
|
|||||||
const [summaryId, setSummaryId] = useState<string | null>(null);
|
const [summaryId, setSummaryId] = useState<string | null>(null);
|
||||||
const [summaryDetails, setSummaryDetails] = useState<SummaryDetails | null>(null);
|
const [summaryDetails, setSummaryDetails] = useState<SummaryDetails | null>(null);
|
||||||
const [loadingSummary, setLoadingSummary] = useState(false);
|
const [loadingSummary, setLoadingSummary] = useState(false);
|
||||||
|
const [sharedRecipientsRefreshTrigger, setSharedRecipientsRefreshTrigger] = useState(0);
|
||||||
const { user } = useAuth();
|
const { user } = useAuth();
|
||||||
|
|
||||||
// Custom hooks
|
// Custom hooks
|
||||||
@ -468,6 +469,8 @@ function RequestDetailInner({ requestId: propRequestId, onBack, dynamicRequests
|
|||||||
onAddSpectator={() => setShowAddSpectatorModal(true)}
|
onAddSpectator={() => setShowAddSpectatorModal(true)}
|
||||||
onApprove={() => setShowApproveModal(true)}
|
onApprove={() => setShowApproveModal(true)}
|
||||||
onReject={() => setShowRejectModal(true)}
|
onReject={() => setShowRejectModal(true)}
|
||||||
|
summaryId={summaryId}
|
||||||
|
refreshTrigger={sharedRecipientsRefreshTrigger}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
@ -484,6 +487,8 @@ function RequestDetailInner({ requestId: propRequestId, onBack, dynamicRequests
|
|||||||
requestTitle={request?.title || 'N/A'}
|
requestTitle={request?.title || 'N/A'}
|
||||||
onSuccess={() => {
|
onSuccess={() => {
|
||||||
refreshDetails();
|
refreshDetails();
|
||||||
|
// Trigger refresh of shared recipients list
|
||||||
|
setSharedRecipientsRefreshTrigger(prev => prev + 1);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@ -2,10 +2,12 @@
|
|||||||
* Quick Actions Sidebar Component
|
* Quick Actions Sidebar Component
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import { useEffect, useState } from 'react';
|
||||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
|
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
|
||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
import { Avatar, AvatarFallback } from '@/components/ui/avatar';
|
import { Avatar, AvatarFallback } from '@/components/ui/avatar';
|
||||||
import { UserPlus, Eye, CheckCircle, XCircle } from 'lucide-react';
|
import { UserPlus, Eye, CheckCircle, XCircle, Share2 } from 'lucide-react';
|
||||||
|
import { getSharedRecipients, type SharedRecipient } from '@/services/summaryApi';
|
||||||
|
|
||||||
interface QuickActionsSidebarProps {
|
interface QuickActionsSidebarProps {
|
||||||
request: any;
|
request: any;
|
||||||
@ -16,6 +18,8 @@ interface QuickActionsSidebarProps {
|
|||||||
onAddSpectator: () => void;
|
onAddSpectator: () => void;
|
||||||
onApprove: () => void;
|
onApprove: () => void;
|
||||||
onReject: () => void;
|
onReject: () => void;
|
||||||
|
summaryId?: string | null;
|
||||||
|
refreshTrigger?: number; // Trigger to refresh shared recipients list
|
||||||
}
|
}
|
||||||
|
|
||||||
export function QuickActionsSidebar({
|
export function QuickActionsSidebar({
|
||||||
@ -27,7 +31,36 @@ export function QuickActionsSidebar({
|
|||||||
onAddSpectator,
|
onAddSpectator,
|
||||||
onApprove,
|
onApprove,
|
||||||
onReject,
|
onReject,
|
||||||
|
summaryId,
|
||||||
|
refreshTrigger,
|
||||||
}: QuickActionsSidebarProps) {
|
}: QuickActionsSidebarProps) {
|
||||||
|
const [sharedRecipients, setSharedRecipients] = useState<SharedRecipient[]>([]);
|
||||||
|
const [loadingRecipients, setLoadingRecipients] = useState(false);
|
||||||
|
const isClosed = request?.status === 'closed';
|
||||||
|
|
||||||
|
// Fetch shared recipients when request is closed and summaryId is available
|
||||||
|
useEffect(() => {
|
||||||
|
const fetchSharedRecipients = async () => {
|
||||||
|
if (!isClosed || !summaryId || !isInitiator) {
|
||||||
|
setSharedRecipients([]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
setLoadingRecipients(true);
|
||||||
|
const recipients = await getSharedRecipients(summaryId);
|
||||||
|
setSharedRecipients(recipients);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Failed to fetch shared recipients:', error);
|
||||||
|
setSharedRecipients([]);
|
||||||
|
} finally {
|
||||||
|
setLoadingRecipients(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
fetchSharedRecipients();
|
||||||
|
}, [isClosed, summaryId, isInitiator, refreshTrigger]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="space-y-4 sm:space-y-6">
|
<div className="space-y-4 sm:space-y-6">
|
||||||
{/* Quick Actions Card - Hide entire card for spectators and closed requests */}
|
{/* Quick Actions Card - Hide entire card for spectators and closed requests */}
|
||||||
@ -118,6 +151,55 @@ export function QuickActionsSidebar({
|
|||||||
)}
|
)}
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
|
{/* Shared Recipients Card - Only for closed requests */}
|
||||||
|
{isClosed && isInitiator && (
|
||||||
|
<Card data-testid="shared-recipients-card">
|
||||||
|
<CardHeader className="pb-2">
|
||||||
|
<CardTitle className="text-sm sm:text-base flex items-center gap-2">
|
||||||
|
<Share2 className="w-4 h-4" />
|
||||||
|
Summary Shared With
|
||||||
|
</CardTitle>
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent className="space-y-3">
|
||||||
|
{loadingRecipients ? (
|
||||||
|
<div className="py-4 text-center">
|
||||||
|
<p className="text-sm text-gray-500">Loading...</p>
|
||||||
|
</div>
|
||||||
|
) : sharedRecipients.length > 0 ? (
|
||||||
|
sharedRecipients.map((recipient, index) => {
|
||||||
|
const avatar = (recipient.displayName || 'NA')
|
||||||
|
.split(' ')
|
||||||
|
.map((s: string) => s[0])
|
||||||
|
.join('')
|
||||||
|
.slice(0, 2)
|
||||||
|
.toUpperCase();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div key={recipient.userId || index} className="flex items-center gap-3" data-testid={`shared-recipient-${index}`}>
|
||||||
|
<Avatar className="h-8 w-8">
|
||||||
|
<AvatarFallback className="bg-green-100 text-green-800 text-xs font-semibold">
|
||||||
|
{avatar}
|
||||||
|
</AvatarFallback>
|
||||||
|
</Avatar>
|
||||||
|
<div className="flex-1 min-w-0">
|
||||||
|
<p className="text-sm font-medium text-gray-900">{recipient.displayName}</p>
|
||||||
|
<p className="text-xs text-gray-500 truncate">{recipient.email}</p>
|
||||||
|
{recipient.isRead && (
|
||||||
|
<p className="text-xs text-green-600 mt-0.5">Viewed</p>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})
|
||||||
|
) : (
|
||||||
|
<div className="py-4 text-center">
|
||||||
|
<p className="text-sm text-gray-500">Summary not shared yet</p>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -143,3 +143,22 @@ export async function getSummaryByRequestId(requestId: string): Promise<RequestS
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface SharedRecipient {
|
||||||
|
userId: string;
|
||||||
|
email: string;
|
||||||
|
displayName: string;
|
||||||
|
designation: string | null;
|
||||||
|
department: string | null;
|
||||||
|
sharedAt: string;
|
||||||
|
viewedAt: string | null;
|
||||||
|
isRead: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get list of users who received shared summary for a specific summary
|
||||||
|
*/
|
||||||
|
export async function getSharedRecipients(summaryId: string): Promise<SharedRecipient[]> {
|
||||||
|
const res = await apiClient.get(`/summaries/${summaryId}/recipients`);
|
||||||
|
return res.data.data || [];
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user