5
5
CardHeader ,
6
6
CardTitle ,
7
7
} from "@/components/ui/card" ;
8
+ import { Avatar , AvatarFallback , AvatarImage } from "@/components/ui/avatar" ;
9
+ import { format , formatDistance , formatRelative , subDays } from "date-fns" ;
8
10
9
11
import { Doc , Id } from "../../../../convex/_generated/dataModel" ;
10
12
import { Button } from "@/components/ui/button" ;
@@ -16,13 +18,15 @@ import {
16
18
DropdownMenuTrigger ,
17
19
} from "@/components/ui/dropdown-menu" ;
18
20
import {
21
+ FileIcon ,
19
22
FileTextIcon ,
20
23
GanttChartIcon ,
21
24
ImageIcon ,
22
25
MoreVertical ,
23
26
StarHalf ,
24
27
StarIcon ,
25
28
TrashIcon ,
29
+ UndoIcon ,
26
30
} from "lucide-react" ;
27
31
import {
28
32
AlertDialog ,
@@ -35,7 +39,7 @@ import {
35
39
AlertDialogTitle ,
36
40
} from "@/components/ui/alert-dialog" ;
37
41
import { ReactNode , useState } from "react" ;
38
- import { useMutation } from "convex/react" ;
42
+ import { useMutation , useQuery } from "convex/react" ;
39
43
import { api } from "../../../../convex/_generated/api" ;
40
44
import { useToast } from "@/components/ui/use-toast" ;
41
45
import Image from "next/image" ;
@@ -49,6 +53,7 @@ function FileCardActions({
49
53
isFavorited : boolean ;
50
54
} ) {
51
55
const deleteFile = useMutation ( api . files . deleteFile ) ;
56
+ const restoreFile = useMutation ( api . files . restoreFile ) ;
52
57
const toggleFavorite = useMutation ( api . files . toggleFavorite ) ;
53
58
const { toast } = useToast ( ) ;
54
59
@@ -61,8 +66,8 @@ function FileCardActions({
61
66
< AlertDialogHeader >
62
67
< AlertDialogTitle > Are you absolutely sure?</ AlertDialogTitle >
63
68
< AlertDialogDescription >
64
- This action cannot be undone. This will permanently delete your
65
- account and remove your data from our servers.
69
+ This action will mark the file for our deletion process. Files are
70
+ deleted periodically
66
71
</ AlertDialogDescription >
67
72
</ AlertDialogHeader >
68
73
< AlertDialogFooter >
@@ -74,8 +79,8 @@ function FileCardActions({
74
79
} ) ;
75
80
toast ( {
76
81
variant : "default" ,
77
- title : "File deleted " ,
78
- description : "Your file is now gone from the system " ,
82
+ title : "File marked for deletion " ,
83
+ description : "Your file will be deleted soon " ,
79
84
} ) ;
80
85
} }
81
86
>
@@ -90,6 +95,15 @@ function FileCardActions({
90
95
< MoreVertical />
91
96
</ DropdownMenuTrigger >
92
97
< DropdownMenuContent >
98
+ < DropdownMenuItem
99
+ onClick = { ( ) => {
100
+ window . open ( getFileUrl ( file . fileId ) , "_blank" ) ;
101
+ } }
102
+ className = "flex gap-1 items-center cursor-pointer"
103
+ >
104
+ < FileIcon className = "w-4 h-4" /> Download
105
+ </ DropdownMenuItem >
106
+
93
107
< DropdownMenuItem
94
108
onClick = { ( ) => {
95
109
toggleFavorite ( {
@@ -108,15 +122,32 @@ function FileCardActions({
108
122
</ div >
109
123
) }
110
124
</ DropdownMenuItem >
111
- { /* <Protect role="org:admin" fallback={<></>}> */ }
112
- < DropdownMenuSeparator />
113
- < DropdownMenuItem
114
- onClick = { ( ) => setIsConfirmOpen ( true ) }
115
- className = "flex gap-1 text-red-600 items-center cursor-pointer"
116
- >
117
- < TrashIcon className = "w-4 h-4" /> Delete
118
- </ DropdownMenuItem >
119
- { /* </Protect> */ }
125
+
126
+ < Protect role = "org:admin" fallback = { < > </ > } >
127
+ < DropdownMenuSeparator />
128
+ < DropdownMenuItem
129
+ onClick = { ( ) => {
130
+ if ( file . shouldDelete ) {
131
+ restoreFile ( {
132
+ fileId : file . _id ,
133
+ } ) ;
134
+ } else {
135
+ setIsConfirmOpen ( true ) ;
136
+ }
137
+ } }
138
+ className = "flex gap-1 items-center cursor-pointer"
139
+ >
140
+ { file . shouldDelete ? (
141
+ < div className = "flex gap-1 text-green-600 items-center cursor-pointer" >
142
+ < UndoIcon className = "w-4 h-4" /> Restore
143
+ </ div >
144
+ ) : (
145
+ < div className = "flex gap-1 text-red-600 items-center cursor-pointer" >
146
+ < TrashIcon className = "w-4 h-4" /> Delete
147
+ </ div >
148
+ ) }
149
+ </ DropdownMenuItem >
150
+ </ Protect >
120
151
</ DropdownMenuContent >
121
152
</ DropdownMenu >
122
153
</ >
@@ -134,6 +165,10 @@ export function FileCard({
134
165
file : Doc < "files" > ;
135
166
favorites : Doc < "favorites" > [ ] ;
136
167
} ) {
168
+ const userProfile = useQuery ( api . users . getUserProfile , {
169
+ userId : file . userId ,
170
+ } ) ;
171
+
137
172
const typeIcons = {
138
173
image : < ImageIcon /> ,
139
174
pdf : < FileTextIcon /> ,
@@ -147,7 +182,7 @@ export function FileCard({
147
182
return (
148
183
< Card >
149
184
< CardHeader className = "relative" >
150
- < CardTitle className = "flex gap-2" >
185
+ < CardTitle className = "flex gap-2 text-base font-normal " >
151
186
< div className = "flex justify-center" > { typeIcons [ file . type ] } </ div > { " " }
152
187
{ file . name }
153
188
</ CardTitle >
@@ -168,14 +203,17 @@ export function FileCard({
168
203
{ file . type === "csv" && < GanttChartIcon className = "w-20 h-20" /> }
169
204
{ file . type === "pdf" && < FileTextIcon className = "w-20 h-20" /> }
170
205
</ CardContent >
171
- < CardFooter className = "flex justify-center" >
172
- < Button
173
- onClick = { ( ) => {
174
- window . open ( getFileUrl ( file . fileId ) , "_blank" ) ;
175
- } }
176
- >
177
- Download
178
- </ Button >
206
+ < CardFooter className = "flex justify-between" >
207
+ < div className = "flex gap-2 text-xs text-gray-700 w-40 items-center" >
208
+ < Avatar className = "w-6 h-6" >
209
+ < AvatarImage src = { userProfile ?. image } />
210
+ < AvatarFallback > CN</ AvatarFallback >
211
+ </ Avatar >
212
+ { userProfile ?. name }
213
+ </ div >
214
+ < div className = "text-xs text-gray-700" >
215
+ Uploaded on { formatRelative ( new Date ( file . _creationTime ) , new Date ( ) ) }
216
+ </ div >
179
217
</ CardFooter >
180
218
</ Card >
181
219
) ;
0 commit comments