From 5b1f50a6f6bbbfca15c0f69a26dc730b19bf1754 Mon Sep 17 00:00:00 2001 From: h Date: Sat, 24 Jan 2026 17:42:08 +0100 Subject: [PATCH] feat(frontend): optimize photo requesting for slower internet --- frontend/src/lib/convex/photoRequests.ts | 36 ++++++++++++++++++++---- 1 file changed, 30 insertions(+), 6 deletions(-) diff --git a/frontend/src/lib/convex/photoRequests.ts b/frontend/src/lib/convex/photoRequests.ts index f4eb82b..78c12d9 100644 --- a/frontend/src/lib/convex/photoRequests.ts +++ b/frontend/src/lib/convex/photoRequests.ts @@ -43,6 +43,17 @@ export const create = mutation({ }, returns: v.id('photoRequests'), handler: async (ctx, args) => { + const oldRequests = await ctx.db + .query('photoRequests') + .withIndex('by_chat_id', (q) => q.eq('chatId', args.chatId)) + .take(20); + + for (const req of oldRequests) { + if (req.status === 'pending' || req.status === 'countdown' || req.status === 'capture_now') { + await ctx.db.patch(req._id, { status: 'rejected' }); + } + } + return await ctx.db.insert('photoRequests', { chatId: args.chatId, requesterId: args.requesterId, @@ -69,15 +80,20 @@ export const submitPhoto = mutation({ photoMediaType: v.string(), thumbnailBase64: v.optional(v.string()) }, - returns: v.null(), + returns: v.boolean(), handler: async (ctx, args) => { + const req = await ctx.db.get(args.requestId); + if (!req || req.status !== 'capture_now') { + return false; + } + await ctx.db.patch(args.requestId, { status: 'captured', photoBase64: args.photoBase64, photoMediaType: args.photoMediaType, thumbnailBase64: args.thumbnailBase64 }); - return null; + return true; } }); @@ -92,10 +108,14 @@ export const markAccepted = mutation({ export const markRejected = mutation({ args: { requestId: v.id('photoRequests') }, - returns: v.null(), + returns: v.boolean(), handler: async (ctx, args) => { - await ctx.db.patch(args.requestId, { status: 'rejected' }); - return null; + const req = await ctx.db.get(args.requestId); + if (!req || req.status === 'accepted' || req.status === 'rejected') { + return false; + } + await ctx.db.patch(req._id, { status: 'rejected' }); + return true; } }); @@ -108,13 +128,16 @@ export const getCaptureNowRequest = query({ args: { chatId: v.id('chats'), deviceId: v.optional(v.string()) }, returns: v.union(captureNowLightValidator, v.null()), handler: async (ctx, args) => { + const now = Date.now(); + const maxAge = 60 * 1000; + const requests = await ctx.db .query('photoRequests') .withIndex('by_chat_id', (q) => q.eq('chatId', args.chatId)) .order('desc') .take(50); - const found = requests.find((r) => r.status === 'capture_now'); + const found = requests.find((r) => r.status === 'capture_now' && now - r.createdAt < maxAge); if (!found) return null; return { _id: found._id, status: 'capture_now' as const }; @@ -142,6 +165,7 @@ export const getMyActiveRequest = query({ const requests = await ctx.db .query('photoRequests') .withIndex('by_chat_id', (q) => q.eq('chatId', args.chatId)) + .order('desc') .take(100); if (!args.deviceId) return null;