mirror of
https://github.com/jjbrunton/Sauci.git
synced 2026-10-31 18:19:43 +00:00
Update mobile app UI with premium design system
- Add design guidelines to CLAUDE.md - Redesign navigation with boutique styling - Add video support to chat with compression - Update matches/dares/quiz screens with gold/rose accents - Improve packs browsing with category tabs - Add SwipeCardPremium component - Update theme with premium color palette - Add video cleanup edge function and migration 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
feb7657562
commit
cac7a2a31d
31 files changed
+6638
-1827
No files matched your search
@@ -0,0 +1,91 @@
|
||||
import "jsr:@supabase/functions-js/edge-runtime.d.ts";
|
||||
import { createClient } from "jsr:@supabase/supabase-js@2";
|
||||
|
||||
/**
|
||||
* Cleanup expired videos from storage.
|
||||
* This function is called by pg_cron daily at 3 AM UTC.
|
||||
* It finds videos where media_expires_at has passed, deletes the files from storage,
|
||||
* and marks the messages as expired.
|
||||
*/
|
||||
Deno.serve(async (req) => {
|
||||
// Only allow POST requests (from cron) or GET (for manual testing)
|
||||
if (req.method !== "POST" && req.method !== "GET") {
|
||||
return new Response("Method not allowed", { status: 405 });
|
||||
}
|
||||
|
||||
const supabase = createClient(
|
||||
Deno.env.get("SUPABASE_URL")!,
|
||||
Deno.env.get("SUPABASE_SERVICE_ROLE_KEY")!
|
||||
);
|
||||
|
||||
try {
|
||||
// Get expired videos that still have files
|
||||
const { data: expiredVideos, error: fetchError } = await supabase
|
||||
.from("messages")
|
||||
.select("id, media_path")
|
||||
.eq("media_type", "video")
|
||||
.eq("media_expired", false)
|
||||
.not("media_path", "is", null)
|
||||
.lt("media_expires_at", new Date().toISOString());
|
||||
|
||||
if (fetchError) {
|
||||
console.error("Error fetching expired videos:", fetchError);
|
||||
return new Response(
|
||||
JSON.stringify({ error: fetchError.message }),
|
||||
{ status: 500, headers: { "Content-Type": "application/json" } }
|
||||
);
|
||||
}
|
||||
|
||||
if (!expiredVideos || expiredVideos.length === 0) {
|
||||
return new Response(
|
||||
JSON.stringify({ deleted: 0, message: "No expired videos found" }),
|
||||
{ headers: { "Content-Type": "application/json" } }
|
||||
);
|
||||
}
|
||||
|
||||
// Delete files from storage
|
||||
const paths = expiredVideos.map((v) => v.media_path).filter(Boolean) as string[];
|
||||
|
||||
if (paths.length > 0) {
|
||||
const { error: storageError } = await supabase.storage
|
||||
.from("chat-media")
|
||||
.remove(paths);
|
||||
|
||||
if (storageError) {
|
||||
console.error("Error deleting from storage:", storageError);
|
||||
// Continue anyway to mark as expired - files may already be deleted
|
||||
}
|
||||
}
|
||||
|
||||
// Mark messages as expired
|
||||
const ids = expiredVideos.map((v) => v.id);
|
||||
const { error: updateError } = await supabase
|
||||
.from("messages")
|
||||
.update({ media_expired: true, media_path: null })
|
||||
.in("id", ids);
|
||||
|
||||
if (updateError) {
|
||||
console.error("Error marking messages as expired:", updateError);
|
||||
return new Response(
|
||||
JSON.stringify({ error: updateError.message }),
|
||||
{ status: 500, headers: { "Content-Type": "application/json" } }
|
||||
);
|
||||
}
|
||||
|
||||
console.log(`Cleaned up ${expiredVideos.length} expired videos`);
|
||||
|
||||
return new Response(
|
||||
JSON.stringify({
|
||||
deleted: expiredVideos.length,
|
||||
paths: paths,
|
||||
}),
|
||||
{ headers: { "Content-Type": "application/json" } }
|
||||
);
|
||||
} catch (err) {
|
||||
console.error("Unexpected error:", err);
|
||||
return new Response(
|
||||
JSON.stringify({ error: "Internal server error" }),
|
||||
{ status: 500, headers: { "Content-Type": "application/json" } }
|
||||
);
|
||||
}
|
||||
});
|
||||
Reference in new issue
Block a user