Bladeren bron

video files

Bernt Christian Egeland 7 maanden geleden
bovenliggende
commit
657550f3a1
1 gewijzigde bestanden met toevoegingen van 113 en 24 verwijderingen
  1. 113 24
      src/features/vehicles/Components/service-detail/ServiceAttachments.tsx

+ 113 - 24
src/features/vehicles/Components/service-detail/ServiceAttachments.tsx

@@ -1,6 +1,7 @@
-"use client";
+'use client'
 
 
-import { Button } from "@/components/ui/button";
+import { useState } from 'react'
+import { Button } from '@/components/ui/button'
 import {
 import {
   Camera,
   Camera,
   Download,
   Download,
@@ -8,15 +9,18 @@ import {
   Image as ImageIcon,
   Image as ImageIcon,
   Loader2,
   Loader2,
   Paperclip,
   Paperclip,
+  Play,
   Trash2,
   Trash2,
-} from "lucide-react";
-import { formatFileSize } from "./types";
-import type { Attachment } from "./types";
+  Video,
+  X,
+} from 'lucide-react'
+import { formatFileSize } from './types'
+import type { Attachment } from './types'
 
 
 function getFileIcon(type: string) {
 function getFileIcon(type: string) {
-  if (type === "application/pdf") return <FileText className="h-5 w-5 text-red-500" />;
-  if (type.startsWith("image/")) return <ImageIcon className="h-5 w-5 text-blue-500" />;
-  return <Paperclip className="h-5 w-5 text-muted-foreground" />;
+  if (type === 'application/pdf') return <FileText className="h-5 w-5 text-red-500" />
+  if (type.startsWith('image/')) return <ImageIcon className="h-5 w-5 text-blue-500" />
+  return <Paperclip className="h-5 w-5 text-muted-foreground" />
 }
 }
 
 
 function AttachmentRow({
 function AttachmentRow({
@@ -24,9 +28,9 @@ function AttachmentRow({
   onDelete,
   onDelete,
   deleting,
   deleting,
 }: {
 }: {
-  attachment: Attachment;
-  onDelete: (id: string) => void;
-  deleting: boolean;
+  attachment: Attachment
+  onDelete: (id: string) => void
+  deleting: boolean
 }) {
 }) {
   return (
   return (
     <div className="grid grid-cols-[2rem_1fr_auto] items-center gap-2 rounded border p-2">
     <div className="grid grid-cols-[2rem_1fr_auto] items-center gap-2 rounded border p-2">
@@ -34,7 +38,9 @@ function AttachmentRow({
         {getFileIcon(attachment.fileType)}
         {getFileIcon(attachment.fileType)}
       </div>
       </div>
       <div className="overflow-hidden">
       <div className="overflow-hidden">
-        <p className="truncate text-xs font-medium" title={attachment.fileName}>{attachment.fileName}</p>
+        <p className="truncate text-xs font-medium" title={attachment.fileName}>
+          {attachment.fileName}
+        </p>
         <p className="text-xs text-muted-foreground">{formatFileSize(attachment.fileSize)}</p>
         <p className="text-xs text-muted-foreground">{formatFileSize(attachment.fileSize)}</p>
       </div>
       </div>
       <div className="flex items-center gap-0.5">
       <div className="flex items-center gap-0.5">
@@ -54,15 +60,15 @@ function AttachmentRow({
         </Button>
         </Button>
       </div>
       </div>
     </div>
     </div>
-  );
+  )
 }
 }
 
 
 interface ServiceAttachmentsProps {
 interface ServiceAttachmentsProps {
-  attachments: Attachment[];
-  imageAttachments: Attachment[];
-  onImageClick: (index: number) => void;
-  onDeleteAttachment: (id: string) => void;
-  deletingAttachment: string | null;
+  attachments: Attachment[]
+  imageAttachments: Attachment[]
+  onImageClick: (index: number) => void
+  onDeleteAttachment: (id: string) => void
+  deletingAttachment: string | null
 }
 }
 
 
 export function ServiceAttachments({
 export function ServiceAttachments({
@@ -72,8 +78,10 @@ export function ServiceAttachments({
   onDeleteAttachment,
   onDeleteAttachment,
   deletingAttachment,
   deletingAttachment,
 }: ServiceAttachmentsProps) {
 }: ServiceAttachmentsProps) {
-  const diagnostics = attachments.filter((a) => a.category === "diagnostic");
-  const documents = attachments.filter((a) => a.category === "document");
+  const diagnostics = attachments.filter((a) => a.category === 'diagnostic')
+  const documents = attachments.filter((a) => a.category === 'document')
+  const videos = attachments.filter((a) => a.category === 'video')
+  const [activeVideo, setActiveVideo] = useState<Attachment | null>(null)
 
 
   return (
   return (
     <>
     <>
@@ -111,9 +119,11 @@ export function ServiceAttachments({
                       disabled={deletingAttachment === attachment.id}
                       disabled={deletingAttachment === attachment.id}
                       onClick={() => onDeleteAttachment(attachment.id)}
                       onClick={() => onDeleteAttachment(attachment.id)}
                     >
                     >
-                      {deletingAttachment === attachment.id
-                        ? <Loader2 className="h-2.5 w-2.5 animate-spin" />
-                        : <Trash2 className="h-2.5 w-2.5" />}
+                      {deletingAttachment === attachment.id ? (
+                        <Loader2 className="h-2.5 w-2.5 animate-spin" />
+                      ) : (
+                        <Trash2 className="h-2.5 w-2.5" />
+                      )}
                     </Button>
                     </Button>
                   </div>
                   </div>
                 </div>
                 </div>
@@ -123,6 +133,61 @@ export function ServiceAttachments({
         </div>
         </div>
       )}
       )}
 
 
+      {videos.length > 0 && (
+        <div className="min-w-0 overflow-hidden rounded-lg border p-3">
+          <h3 className="mb-2 flex items-center gap-2 text-sm font-semibold">
+            <Video className="h-3.5 w-3.5" />
+            Videos ({videos.length})
+          </h3>
+          <div className="space-y-1.5">
+            {videos.map((a) => (
+              <div
+                key={a.id}
+                className="grid grid-cols-[2rem_1fr_auto] items-center gap-2 rounded border p-2"
+              >
+                <button
+                  type="button"
+                  onClick={() => setActiveVideo(a)}
+                  className="flex h-8 w-8 items-center justify-center rounded bg-muted/50 transition-colors hover:bg-muted"
+                >
+                  <Play className="h-4 w-4 text-primary" />
+                </button>
+                <button
+                  type="button"
+                  onClick={() => setActiveVideo(a)}
+                  className="overflow-hidden text-left"
+                >
+                  <p className="truncate text-xs font-medium" title={a.fileName}>
+                    {a.fileName}
+                  </p>
+                  <p className="text-xs text-muted-foreground">{formatFileSize(a.fileSize)}</p>
+                </button>
+                <div className="flex items-center gap-0.5">
+                  <Button variant="ghost" size="icon" className="h-6 w-6" asChild>
+                    <a href={a.fileUrl} download={a.fileName}>
+                      <Download className="h-3 w-3" />
+                    </a>
+                  </Button>
+                  <Button
+                    variant="ghost"
+                    size="icon"
+                    className="h-6 w-6 text-muted-foreground hover:text-destructive"
+                    disabled={deletingAttachment === a.id}
+                    onClick={() => onDeleteAttachment(a.id)}
+                  >
+                    {deletingAttachment === a.id ? (
+                      <Loader2 className="h-3 w-3 animate-spin" />
+                    ) : (
+                      <Trash2 className="h-3 w-3" />
+                    )}
+                  </Button>
+                </div>
+              </div>
+            ))}
+          </div>
+        </div>
+      )}
+
       {diagnostics.length > 0 && (
       {diagnostics.length > 0 && (
         <div className="min-w-0 overflow-hidden rounded-lg border p-3">
         <div className="min-w-0 overflow-hidden rounded-lg border p-3">
           <h3 className="mb-2 flex items-center gap-2 text-sm font-semibold">
           <h3 className="mb-2 flex items-center gap-2 text-sm font-semibold">
@@ -160,6 +225,30 @@ export function ServiceAttachments({
           </div>
           </div>
         </div>
         </div>
       )}
       )}
+
+      {/* Fullscreen video player */}
+      {activeVideo && (
+        <div
+          className="fixed inset-0 z-50 flex items-center justify-center bg-black/90"
+          onClick={() => setActiveVideo(null)}
+        >
+          <Button
+            variant="ghost"
+            size="icon"
+            className="absolute right-4 top-4 h-10 w-10 text-white hover:bg-white/10"
+            onClick={() => setActiveVideo(null)}
+          >
+            <X className="h-6 w-6" />
+          </Button>
+          <video
+            src={activeVideo.fileUrl}
+            controls
+            autoPlay
+            className="max-h-[90vh] max-w-[90vw] rounded-lg"
+            onClick={(e) => e.stopPropagation()}
+          />
+        </div>
+      )}
     </>
     </>
-  );
+  )
 }
 }