feat: enhance AttachmentPreviewDialog integration; add icon variant and improve file display in material cards

This commit is contained in:
Yoga Pangestu 2026-09-04 11:51:27 +07:00
parent 19397d3b5b
commit facf7ab177
3 changed files with 68 additions and 59 deletions

View File

@ -1,11 +1,17 @@
import { Paperclip } from 'lucide-react'; import { Eye, Paperclip } from 'lucide-react';
import { useState } from 'react'; import { useState } from 'react';
import { Button } from '@/components/ui/button';
import { import {
Dialog, Dialog,
DialogContent, DialogContent,
DialogHeader, DialogHeader,
DialogTitle, DialogTitle,
} from '@/components/ui/dialog'; } from '@/components/ui/dialog';
import {
Tooltip,
TooltipContent,
TooltipTrigger,
} from '@/components/ui/tooltip';
import { cn } from '@/lib/utils'; import { cn } from '@/lib/utils';
const IMAGE_EXTENSIONS = ['jpg', 'jpeg', 'png', 'gif', 'webp']; const IMAGE_EXTENSIONS = ['jpg', 'jpeg', 'png', 'gif', 'webp'];
@ -19,12 +25,14 @@ type AttachmentPreviewDialogProps = {
fileUrl: string; fileUrl: string;
fileName: string; fileName: string;
className?: string; className?: string;
variant?: 'link' | 'icon';
}; };
export function AttachmentPreviewDialog({ export function AttachmentPreviewDialog({
fileUrl, fileUrl,
fileName, fileName,
className, className,
variant = 'link',
}: AttachmentPreviewDialogProps) { }: AttachmentPreviewDialogProps) {
const [open, setOpen] = useState(false); const [open, setOpen] = useState(false);
const extension = fileExtension(fileName); const extension = fileExtension(fileName);
@ -34,6 +42,22 @@ export function AttachmentPreviewDialog({
return ( return (
<> <>
{variant === 'icon' ? (
<Tooltip>
<TooltipTrigger asChild>
<Button
type="button"
variant="ghost"
size="icon"
className={className}
onClick={() => setOpen(true)}
>
<Eye className="h-4 w-4" />
</Button>
</TooltipTrigger>
<TooltipContent side="top">Lihat</TooltipContent>
</Tooltip>
) : (
<button <button
type="button" type="button"
onClick={() => setOpen(true)} onClick={() => setOpen(true)}
@ -45,6 +69,7 @@ export function AttachmentPreviewDialog({
<Paperclip className="h-3.5 w-3.5 shrink-0" /> <Paperclip className="h-3.5 w-3.5 shrink-0" />
<span className="truncate">{fileName}</span> <span className="truncate">{fileName}</span>
</button> </button>
)}
<Dialog open={open} onOpenChange={setOpen}> <Dialog open={open} onOpenChange={setOpen}>
<DialogContent <DialogContent

View File

@ -27,7 +27,14 @@ export function createMaterialCard(params: CreateCardParams) {
</Badge> </Badge>
)} )}
</div> </div>
{(canUpdate || canDelete) && ( <div className="flex items-center">
{material.file_url && material.file_name && (
<AttachmentPreviewDialog
fileUrl={material.file_url}
fileName={material.file_name}
variant="icon"
/>
)}
<RowActions <RowActions
actions={[ actions={[
{ {
@ -46,7 +53,7 @@ export function createMaterialCard(params: CreateCardParams) {
}, },
]} ]}
/> />
)} </div>
</div> </div>
<div> <div>
@ -63,18 +70,6 @@ export function createMaterialCard(params: CreateCardParams) {
? `${courseClass.course?.code ?? ''} ${courseClass.course?.name ?? ''}` ? `${courseClass.course?.code ?? ''} ${courseClass.course?.name ?? ''}`
: '-'} : '-'}
</p> </p>
{material.files.length > 0 && (
<div className="flex flex-col gap-1">
{material.files.map((file) => (
<AttachmentPreviewDialog
key={file.id}
fileUrl={file.url}
fileName={file.name}
/>
))}
</div>
)}
</div> </div>
); );
}; };

View File

@ -64,38 +64,27 @@ export function createMaterialColumns(
return `${courseClass.course?.code ?? ''} ${courseClass.course?.name ?? ''}`; return `${courseClass.course?.code ?? ''} ${courseClass.course?.name ?? ''}`;
}, },
}, },
{
accessorKey: 'file_name',
header: () => <span>File</span>,
cell: ({ row }) => {
const material = row.original;
if (!material.file_url || !material.file_name) {
return <span className="text-muted-foreground">-</span>;
}
return (
<AttachmentPreviewDialog
fileUrl={material.file_url}
fileName={material.file_name}
/>
);
},
},
]; ];
if (canUpdate || canDelete) {
columns.push({ columns.push({
id: 'actions', id: 'actions',
header: () => <span className="block text-center">Aksi</span>, header: () => <span className="block text-center">Aksi</span>,
meta: { meta: {
className: 'w-[100px] text-center', className: 'w-[130px] text-center',
headerClassName: 'w-[100px] text-center', headerClassName: 'w-[130px] text-center',
}, },
cell: ({ row }) => { cell: ({ row }) => {
const material = row.original; const material = row.original;
return ( return (
<div className="flex items-center justify-center">
{material.file_url && material.file_name && (
<AttachmentPreviewDialog
fileUrl={material.file_url}
fileName={material.file_name}
variant="icon"
/>
)}
<RowActions <RowActions
actions={[ actions={[
{ {
@ -114,10 +103,10 @@ export function createMaterialColumns(
}, },
]} ]}
/> />
</div>
); );
}, },
}); });
}
return columns; return columns;
} }