File size: 6,995 Bytes
d988ae4
 
 
 
 
 
 
3bbb98d
d988ae4
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3bbb98d
d988ae4
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
'use client';

import { useState, useEffect } from 'react';
import { FileIcon, Image, FileText, Download, Trash2, Eye, AlertCircle } from 'lucide-react';
import { apiUrl } from '@/lib/constants';
import FilePreview from './FilePreview';
import { isPreviewable, formatFileSize } from '@/lib/utils/fileUtils';
import { appendTokenToUrl } from '@/lib/adminAuth';

interface FileEntry {
  id: string;
  filename: string;
  mimetype: string;
  size: number;
  createdAt: string;
  createdBy: string;
}

interface FileListProps {
  files: FileEntry[];
  onDeleteFile: (fileId: string) => void;
  roomCode: string;
}

export default function FileList({ files, onDeleteFile, roomCode }: FileListProps) {
  const [deletingFile, setDeletingFile] = useState<string | null>(null);
  const [previewFile, setPreviewFile] = useState<FileEntry | null>(null);

  // Clear preview if the previewed file is deleted
  useEffect(() => {
    if (previewFile && !files.some(file => file.id === previewFile.id)) {
      setPreviewFile(null);
    }
  }, [files, previewFile]);

  if (files.length === 0) {
    return null;
  }

  const getFileIcon = (mimetype: string) => {
    if (mimetype.startsWith('image/')) {
      return <Image className="h-5 w-5 text-blue-500" />;
    } else if (mimetype.includes('pdf')) {
      return <FileText className="h-5 w-5 text-red-500" />;
    } else {
      return <FileIcon className="h-5 w-5 text-gray-500" />;
    }
  };

  // Check if a file is previewable
  const canPreview = (file: FileEntry) => {
    return isPreviewable(file.mimetype);
  };

  return (
    <div className="mt-6 sm:mt-8">
      <div className="flex items-center justify-between mb-4 sticky top-0 bg-background/90 backdrop-blur-sm py-2 z-10">
        <div className="flex-1"></div>
        <div className="flex items-center gap-2">
        </div>
      </div>

      {previewFile && (
        <FilePreview
          fileId={previewFile.id}
          filename={previewFile.filename}
          mimetype={previewFile.mimetype}
          roomCode={roomCode}
          onClose={() => setPreviewFile(null)}
        />
      )}

      <div className="space-y-2">
        {files.length === 0 ? (
          <div className="border border-dashed border-surface-hover rounded-lg flex flex-col items-center justify-center py-12 mt-4">
            <div className="w-16 h-16 bg-surface-hover rounded-full flex items-center justify-center mb-4">
              <FileIcon className="h-8 w-8 text-text-secondary/50" />
            </div>
            <p className="text-text-secondary mb-2">No files yet</p>
            <p className="text-text-secondary/70 text-sm">Upload your first file using the form above</p>
          </div>
        ) : (
          files.map((file) => (
            <div
              key={file.id}
              className={`flex items-center p-3 bg-surface/80 rounded-lg border border-surface-hover hover:border-primary/30 transition-colors relative ${canPreview(file) ? 'cursor-pointer' : ''}`}
              onClick={() => canPreview(file) ? setPreviewFile(file) : null}
            >
              <div className="mr-3">
                {getFileIcon(file.mimetype)}
              </div>
              <div className="flex-grow min-w-0">
                <p className="text-text-primary font-medium truncate">{file.filename}</p>
                <p className="text-text-tertiary text-xs">
                  {formatFileSize(file.size)} • {new Date(file.createdAt).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })}
                </p>
              </div>
              <div className="flex space-x-2" onClick={(e) => e.stopPropagation()}>
                {canPreview(file) ? (
                  <button
                    onClick={() => setPreviewFile(file)}
                    className="p-1.5 text-text-secondary hover:text-primary rounded-md hover:bg-primary/10 transition-colors"
                    title="Preview"
                  >
                    <Eye className="h-4 w-4" />
                  </button>
                ) : (
                  <span
                    className="p-1.5 text-text-tertiary cursor-not-allowed flex items-center"
                    title="Preview not available for this file type"
                  >
                    <AlertCircle className="h-4 w-4" />
                  </span>
                )}
                <a
                  onClick={(e) => e.stopPropagation()}
                  href={appendTokenToUrl(`${apiUrl}/clipboard/${roomCode}/files/${file.id}?filename=${encodeURIComponent(file.filename)}`)}
                  download={file.filename}
                  className="p-1.5 text-text-secondary hover:text-primary rounded-md hover:bg-primary/10 transition-colors"
                  title="Download"
                >
                  <Download className="h-4 w-4" />
                </a>
                <button
                  onClick={(e) => {
                    e.stopPropagation();
                    setDeletingFile(file.id)
                  }}
                  className="p-1.5 text-text-secondary hover:text-error rounded-md hover:bg-error/10 transition-colors"
                  title="Delete"
                >
                  <Trash2 className="h-4 w-4" />
                </button>
              </div>

              {/* Delete confirmation */}
              {deletingFile === file.id && (
                <div className="absolute inset-0 bg-background/80 backdrop-blur-sm flex items-center justify-center z-10 rounded-lg">
                  <div className="bg-surface p-4 rounded-lg shadow-lg max-w-xs w-full">
                    <h4 className="text-text-primary font-medium mb-2">Delete file?</h4>
                    <p className="text-text-secondary text-sm mb-4">This action cannot be undone.</p>
                    <div className="flex justify-end space-x-2">
                      <button
                        onClick={() => setDeletingFile(null)}
                        className="px-3 py-1.5 text-text-secondary hover:text-text-primary bg-surface-hover rounded-md"
                      >
                        Cancel
                      </button>
                      <button
                        onClick={() => {
                          // If this file is being previewed, close the preview first
                          if (previewFile && previewFile.id === file.id) {
                            setPreviewFile(null);
                          }
                          // Then delete the file
                          onDeleteFile(file.id);
                          setDeletingFile(null);
                        }}
                        className="px-3 py-1.5 text-white bg-error hover:bg-error/90 rounded-md"
                      >
                        Delete
                      </button>
                    </div>
                  </div>
                </div>
              )}
            </div>
          ))
        )}
      </div>
    </div>
  );
}