feat: enhance session management with sharing capabilities, real-time event synchronization, and UI updates for session display
This commit is contained in:
136
src/components/collaboration/SessionLiveWrapper.tsx
Normal file
136
src/components/collaboration/SessionLiveWrapper.tsx
Normal file
@@ -0,0 +1,136 @@
|
||||
'use client';
|
||||
|
||||
import { useState, useCallback } from 'react';
|
||||
import { useSessionLive, type LiveEvent } from '@/hooks/useSessionLive';
|
||||
import { LiveIndicator } from './LiveIndicator';
|
||||
import { ShareModal } from './ShareModal';
|
||||
import { Button } from '@/components/ui/Button';
|
||||
import type { ShareRole } from '@prisma/client';
|
||||
|
||||
interface ShareUser {
|
||||
id: string;
|
||||
name: string | null;
|
||||
email: string;
|
||||
}
|
||||
|
||||
interface Share {
|
||||
id: string;
|
||||
role: ShareRole;
|
||||
user: ShareUser;
|
||||
createdAt: Date;
|
||||
}
|
||||
|
||||
interface SessionLiveWrapperProps {
|
||||
sessionId: string;
|
||||
sessionTitle: string;
|
||||
shares: Share[];
|
||||
isOwner: boolean;
|
||||
canEdit: boolean;
|
||||
children: React.ReactNode;
|
||||
}
|
||||
|
||||
export function SessionLiveWrapper({
|
||||
sessionId,
|
||||
sessionTitle,
|
||||
shares,
|
||||
isOwner,
|
||||
canEdit,
|
||||
children,
|
||||
}: SessionLiveWrapperProps) {
|
||||
const [shareModalOpen, setShareModalOpen] = useState(false);
|
||||
const [lastEventUser, setLastEventUser] = useState<string | null>(null);
|
||||
|
||||
const handleEvent = useCallback((event: LiveEvent) => {
|
||||
// Show who made the last change
|
||||
if (event.user?.name || event.user?.email) {
|
||||
setLastEventUser(event.user.name || event.user.email);
|
||||
// Clear after 3 seconds
|
||||
setTimeout(() => setLastEventUser(null), 3000);
|
||||
}
|
||||
}, []);
|
||||
|
||||
const { isConnected, error } = useSessionLive({
|
||||
sessionId,
|
||||
onEvent: handleEvent,
|
||||
});
|
||||
|
||||
return (
|
||||
<>
|
||||
{/* Header toolbar */}
|
||||
<div className="mb-4 flex items-center justify-between rounded-lg border border-border bg-card p-3">
|
||||
<div className="flex items-center gap-4">
|
||||
<LiveIndicator isConnected={isConnected} error={error} />
|
||||
|
||||
{lastEventUser && (
|
||||
<div className="flex items-center gap-2 text-sm text-muted animate-pulse">
|
||||
<span>✏️</span>
|
||||
<span>{lastEventUser} édite...</span>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{!canEdit && (
|
||||
<div className="flex items-center gap-2 rounded-full bg-yellow/10 px-3 py-1.5 text-sm text-yellow">
|
||||
<span>👁️</span>
|
||||
<span>Mode lecture</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="flex items-center gap-2">
|
||||
{/* Collaborators avatars */}
|
||||
{shares.length > 0 && (
|
||||
<div className="flex -space-x-2">
|
||||
{shares.slice(0, 3).map((share) => (
|
||||
<div
|
||||
key={share.id}
|
||||
className="flex h-8 w-8 items-center justify-center rounded-full border-2 border-card bg-primary/10 text-xs font-medium text-primary"
|
||||
title={share.user.name || share.user.email}
|
||||
>
|
||||
{share.user.name?.[0]?.toUpperCase() || share.user.email[0].toUpperCase()}
|
||||
</div>
|
||||
))}
|
||||
{shares.length > 3 && (
|
||||
<div className="flex h-8 w-8 items-center justify-center rounded-full border-2 border-card bg-muted/20 text-xs font-medium text-muted">
|
||||
+{shares.length - 3}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={() => setShareModalOpen(true)}
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 20 20"
|
||||
fill="currentColor"
|
||||
className="mr-2 h-4 w-4"
|
||||
>
|
||||
<path d="M13 4.5a2.5 2.5 0 11.702 1.737L6.97 9.604a2.518 2.518 0 010 .792l6.733 3.367a2.5 2.5 0 11-.671 1.341l-6.733-3.367a2.5 2.5 0 110-3.475l6.733-3.366A2.52 2.52 0 0113 4.5z" />
|
||||
</svg>
|
||||
Partager
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Content */}
|
||||
<div className={!canEdit ? 'pointer-events-none opacity-90' : ''}>
|
||||
{children}
|
||||
</div>
|
||||
|
||||
{/* Share Modal */}
|
||||
<ShareModal
|
||||
isOpen={shareModalOpen}
|
||||
onClose={() => setShareModalOpen(false)}
|
||||
sessionId={sessionId}
|
||||
sessionTitle={sessionTitle}
|
||||
shares={shares}
|
||||
isOwner={isOwner}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user