Spaces:
Runtime error
Runtime error
feat: Introduce a product request system allowing viewers to submit requests and creators to manage them via a new dashboard page.
271988a | 'use server'; | |
| import { db } from '@/lib/db'; | |
| import { productRequests } from '@/lib/db/schema'; | |
| import { eq } from 'drizzle-orm'; | |
| import { revalidatePath } from 'next/cache'; | |
| import { uploadThumbnail } from '@/features/discovery/services/storage.service'; | |
| export async function uploadRequestImage(formData: FormData) { | |
| try { | |
| const file = formData.get('file') as File; | |
| if (!file) { | |
| return { success: false, error: 'No file uploaded' }; | |
| } | |
| // Validate file type | |
| if (!file.type.startsWith('image/')) { | |
| return { success: false, error: 'File must be an image' }; | |
| } | |
| // Convert File to Buffer | |
| const arrayBuffer = await file.arrayBuffer(); | |
| const buffer = Buffer.from(arrayBuffer); | |
| const safeName = (file.name || 'request.png').replace(/[^a-zA-Z0-9.]/g, '_'); | |
| const fileName = `viewer-requests/${Date.now()}-${safeName}`; | |
| const publicUrl = await uploadThumbnail(buffer, fileName, file.type); | |
| if (!publicUrl) { | |
| return { success: false, error: 'Failed to upload to storage' }; | |
| } | |
| return { success: true, url: publicUrl }; | |
| } catch (error: any) { | |
| console.error('uploadRequestImage error:', error); | |
| return { success: false, error: error.message || 'Upload failed' }; | |
| } | |
| } | |
| export async function submitProductRequest(data: { | |
| videoId: string; | |
| creatorId: string; | |
| viewerName?: string; | |
| viewerEmail?: string; | |
| note: string; | |
| imageUrl?: string; | |
| frameTimestamp?: number; | |
| }) { | |
| try { | |
| const [request] = await db.insert(productRequests).values({ | |
| videoId: data.videoId, | |
| creatorId: data.creatorId, | |
| viewerName: data.viewerName, | |
| viewerEmail: data.viewerEmail, | |
| note: data.note, | |
| imageUrl: data.imageUrl, | |
| frameTimestamp: data.frameTimestamp, | |
| status: 'PENDING', | |
| }).returning(); | |
| revalidatePath('/dashboard/requests'); | |
| return { success: true, id: request.id }; | |
| } catch (error: any) { | |
| console.error('Failed to submit product request:', error); | |
| return { success: false, error: error.message }; | |
| } | |
| } | |
| export async function updateRequestStatus(requestId: string, status: 'PENDING' | 'FULFILLED' | 'DISMISSED') { | |
| try { | |
| await db.update(productRequests) | |
| .set({ status }) | |
| .where(eq(productRequests.id, requestId)); | |
| revalidatePath('/dashboard/requests'); | |
| return { success: true }; | |
| } catch (error: any) { | |
| console.error('Failed to update request status:', error); | |
| return { success: false, error: error.message }; | |
| } | |
| } | |