dvijaykrishnan commited on
Commit
939e209
·
1 Parent(s): 271988a

feat: Enable guest users to add product detections and upload images, enhance the product request dialog UI, and update .gitignore.

Browse files
.gitignore CHANGED
@@ -39,3 +39,10 @@ yarn-error.log*
39
  # typescript
40
  *.tsbuildinfo
41
  next-env.d.ts
 
 
 
 
 
 
 
 
39
  # typescript
40
  *.tsbuildinfo
41
  next-env.d.ts
42
+
43
+ # drizzle migrations (use drizzle-kit generate/push only)
44
+ drizzle-backup/
45
+ *_drizzle-backup.sql
46
+
47
+ # utility scripts (keep local only)
48
+ scripts/
src/features/moderation/actions/add-detection.ts CHANGED
@@ -54,11 +54,14 @@ export async function addDetection(data: AddDetectionData) {
54
  return { success: false, error: 'Video not found' };
55
  }
56
 
57
- // Verify ownership OR if it's a demo video (allow testing)
 
58
  const isOwner = currentUserId && videoData.creatorId === currentUserId;
59
  const isDemo = videoData.creatorId === DEMO_USER_ID;
 
60
 
61
- if (!isOwner && !isDemo) {
 
62
  return { success: false, error: 'Unauthorized' };
63
  }
64
 
 
54
  return { success: false, error: 'Video not found' };
55
  }
56
 
57
+ // Verify ownership for logged-in users (optional check)
58
+ // Guests can always add products (they'll be attributed to DEMO_USER_ID initially)
59
  const isOwner = currentUserId && videoData.creatorId === currentUserId;
60
  const isDemo = videoData.creatorId === DEMO_USER_ID;
61
+ const isGuest = !currentUserId;
62
 
63
+ // Allow: owners, demo videos, or guests (showcase mode)
64
+ if (!isOwner && !isDemo && !isGuest) {
65
  return { success: false, error: 'Unauthorized' };
66
  }
67
 
src/features/moderation/actions/upload-product-image.ts CHANGED
@@ -10,9 +10,8 @@ export async function uploadProductImage(formData: FormData) {
10
  headers: await headers(),
11
  });
12
 
13
- if (!session?.user) {
14
- return { success: false, error: 'Unauthorized' };
15
- }
16
 
17
  const file = formData.get('file') as File;
18
  if (!file) {
@@ -29,7 +28,7 @@ export async function uploadProductImage(formData: FormData) {
29
  const buffer = Buffer.from(arrayBuffer);
30
 
31
  const safeName = (file.name || 'image.png').replace(/[^a-zA-Z0-9.]/g, '_');
32
- const fileName = `manual/${session.user.id}-${Date.now()}-${safeName}`;
33
 
34
  const publicUrl = await uploadThumbnail(buffer, fileName, file.type);
35
 
 
10
  headers: await headers(),
11
  });
12
 
13
+ // Allow guests to upload (for showcase mode)
14
+ const userId = session?.user?.id || 'guest';
 
15
 
16
  const file = formData.get('file') as File;
17
  if (!file) {
 
28
  const buffer = Buffer.from(arrayBuffer);
29
 
30
  const safeName = (file.name || 'image.png').replace(/[^a-zA-Z0-9.]/g, '_');
31
+ const fileName = `manual/${userId}-${Date.now()}-${safeName}`;
32
 
33
  const publicUrl = await uploadThumbnail(buffer, fileName, file.type);
34
 
src/features/vault/components/product-request-dialog.tsx CHANGED
@@ -156,14 +156,14 @@ export function ProductRequestDialog({ videoId: initialVideoId, creatorId, video
156
  Can't find a product?
157
  </Button>
158
  </DialogTrigger>
159
- <DialogContent className="sm:max-w-[425px] glass border-white/10 text-white">
160
  <DialogHeader>
161
  <DialogTitle className="text-xl font-bold tracking-tight">Request a Product</DialogTitle>
162
  <DialogDescription className="text-muted-foreground">
163
  Saw something in a video that's not listed? Let the creator know!
164
  </DialogDescription>
165
  </DialogHeader>
166
- <form onSubmit={handleSubmit} className="space-y-4 py-4">
167
  {!initialVideoId && videos.length > 0 && (
168
  <div className="space-y-2">
169
  <Label htmlFor="video-select" className="text-sm font-medium">Which video did you see it in?*</Label>
@@ -190,8 +190,7 @@ export function ProductRequestDialog({ videoId: initialVideoId, creatorId, video
190
  required
191
  />
192
  </div>
193
- {/* ... (rest unchanged) ... */}
194
- <div className="grid grid-cols-2 gap-4">
195
  <div className="space-y-2">
196
  <Label htmlFor="name" className="text-sm font-medium">Name (Optional)</Label>
197
  <Input
@@ -214,7 +213,7 @@ export function ProductRequestDialog({ videoId: initialVideoId, creatorId, video
214
  />
215
  </div>
216
  </div>
217
- <div className="space-y-4">
218
  <ImageUploadField
219
  label="Product Image (Optional)"
220
  icon={<PlaySquare className="h-4 w-4 text-primary" />}
 
156
  Can't find a product?
157
  </Button>
158
  </DialogTrigger>
159
+ <DialogContent className="sm:max-w-[540px] glass border-white/10 text-white">
160
  <DialogHeader>
161
  <DialogTitle className="text-xl font-bold tracking-tight">Request a Product</DialogTitle>
162
  <DialogDescription className="text-muted-foreground">
163
  Saw something in a video that's not listed? Let the creator know!
164
  </DialogDescription>
165
  </DialogHeader>
166
+ <form onSubmit={handleSubmit} className="space-y-5 py-4 max-h-[60vh] overflow-y-auto pr-2">
167
  {!initialVideoId && videos.length > 0 && (
168
  <div className="space-y-2">
169
  <Label htmlFor="video-select" className="text-sm font-medium">Which video did you see it in?*</Label>
 
190
  required
191
  />
192
  </div>
193
+ <div className="space-y-4">
 
194
  <div className="space-y-2">
195
  <Label htmlFor="name" className="text-sm font-medium">Name (Optional)</Label>
196
  <Input
 
213
  />
214
  </div>
215
  </div>
216
+ <div className="space-y-2">
217
  <ImageUploadField
218
  label="Product Image (Optional)"
219
  icon={<PlaySquare className="h-4 w-4 text-primary" />}
src/features/vault/services/showcase.service.ts CHANGED
@@ -602,8 +602,7 @@ export class ShowcaseService {
602
  await db.update(youtubeChannels)
603
  .set({
604
  subscriberCount: subscriberCount > 0 ? subscriberCount : channel.subscriberCount,
605
- thumbnailUrl: betterThumbnailUrl || channel.thumbnailUrl,
606
- creatorSlug: expectedSlug
607
  })
608
  .where(eq(youtubeChannels.id, channel.id));
609
  } else {
 
602
  await db.update(youtubeChannels)
603
  .set({
604
  subscriberCount: subscriberCount > 0 ? subscriberCount : channel.subscriberCount,
605
+ thumbnailUrl: betterThumbnailUrl || channel.thumbnailUrl
 
606
  })
607
  .where(eq(youtubeChannels.id, channel.id));
608
  } else {