diff --git a/src/app/dashboard/actions.ts b/src/app/dashboard/actions.ts index e409bd0..392149f 100644 --- a/src/app/dashboard/actions.ts +++ b/src/app/dashboard/actions.ts @@ -59,15 +59,16 @@ export const getDownloadsSeriesAll = async ({ days = 30 }: { days?: number }): P // Get hacks owned by user const { data: ownedHacks } = await supa .from("hacks") - .select("slug,created_by,current_patch,original_author,permission_from") + .select("slug,created_by,current_patch,original_author,permission_from,is_archive") + .is("is_archive", false) .eq("created_by", user.id); const ownedSlugs = (ownedHacks ?? []).map((h) => h.slug); // Get archive hacks that user can edit as archiver const { data: allArchiveHacks } = await supa .from("hacks") - .select("slug,created_by,current_patch,original_author,permission_from") - .not("original_author", "is", null); + .select("slug,created_by,current_patch,original_author,permission_from,is_archive") + .eq("is_archive", true); const accessibleArchiveSlugs: string[] = []; if (allArchiveHacks) { @@ -167,7 +168,7 @@ export const getHackInsights = async ({ slug }: { slug: string }): Promise t.trim()).filter(Boolean) || []; const original_author = (formData.get("original_author") as string)?.trim() || null; const permission_from = (formData.get("permission_from") as string)?.trim() || null; - const isArchive = formData.get("isArchive") === "true"; + const is_archive = formData.get("is_archive") === "true"; // For archives, version is not required; for regular hacks, it is - if (!title || !summary || !description || !base_rom || !language || (!isArchive && !version)) { + if (!title || !summary || !description || !base_rom || !language || (!is_archive && !version)) { return { ok: false, error: "Missing required fields" } as const; } // For archives, original_author is required - if (isArchive && !original_author) { + if (is_archive && !original_author) { return { ok: false, error: "Original author is required for Archive hacks" } as const; } @@ -86,7 +86,8 @@ export async function prepareSubmission(formData: FormData) { downloads: 0, box_art, social_links, - approved: isArchive, // Auto-approve archives + approved: is_archive, // Auto-approve archives + is_archive, patch_url: "", original_author: original_author || null, permission_from: permission_from || null, @@ -143,7 +144,7 @@ export async function saveHackCovers(args: { slug: string; coverUrls: string[] } // Ensure hack exists and user has permission const { data: hack, error: hErr } = await supabase .from("hacks") - .select("slug, created_by, current_patch, original_author, permission_from") + .select("slug, created_by, current_patch, original_author, permission_from, is_archive") .eq("slug", args.slug) .maybeSingle(); if (hErr) return { ok: false, error: hErr.message } as const; @@ -182,7 +183,7 @@ export async function presignPatchAndSaveCovers(args: { // Ensure hack exists and user has permission const { data: hack, error: hErr } = await supabase .from("hacks") - .select("slug, created_by, current_patch, original_author, permission_from") + .select("slug, created_by, current_patch, original_author, permission_from, is_archive") .eq("slug", args.slug) .maybeSingle(); if (hErr) return { ok: false, error: hErr.message } as const; @@ -224,7 +225,7 @@ export async function confirmPatchUpload(args: { slug: string; objectKey: string const { data: hack, error: hErr } = await supabase .from("hacks") - .select("slug, created_by, title, current_patch, original_author, permission_from") + .select("slug, created_by, title, current_patch, original_author, permission_from, is_archive") .eq("slug", args.slug) .maybeSingle(); if (hErr) return { ok: false, error: hErr.message } as const; diff --git a/src/components/Dashboard/ArchivesList.tsx b/src/components/Dashboard/ArchivesList.tsx index dde0afc..85f8a47 100644 --- a/src/components/Dashboard/ArchivesList.tsx +++ b/src/components/Dashboard/ArchivesList.tsx @@ -18,6 +18,7 @@ type Archive = { creator_username: string | null; approved: boolean; current_patch: number | null; + is_archive: boolean; }; type ArchivesData = diff --git a/src/components/Hack/HackSubmitForm.tsx b/src/components/Hack/HackSubmitForm.tsx index 80d4a24..4018f0b 100644 --- a/src/components/Hack/HackSubmitForm.tsx +++ b/src/components/Hack/HackSubmitForm.tsx @@ -436,7 +436,7 @@ export default function HackSubmitForm({ if (github) fd.set('github', github); if (tags.length) fd.set('tags', tags.join(',')); if (isArchive) { - fd.set('isArchive', 'true'); + fd.set('is_archive', 'true'); } if (originalAuthor) { fd.set('original_author', originalAuthor); @@ -632,6 +632,7 @@ export default function HackSubmitForm({ : undefined, createdAt: new Date().toISOString(), patchUrl: "", + is_archive: isArchive, }; const hasBaseRom = !!baseRom.trim(); diff --git a/src/components/HackCard.tsx b/src/components/HackCard.tsx index a114f40..e819989 100644 --- a/src/components/HackCard.tsx +++ b/src/components/HackCard.tsx @@ -24,11 +24,11 @@ export interface HackCardAttributes { version: string; summary?: string; description?: string; - isArchive?: boolean; + is_archive: boolean; }; export default function HackCard({ hack, clickable = true, className = "" }: { hack: HackCardAttributes; clickable?: boolean; className?: string }) { - const isArchive = !!hack.isArchive; + const isArchive = hack.is_archive; const { isLinked, hasPermission, hasCached } = useBaseRoms(); const match = baseRoms.find((r) => r.id === hack.baseRomId); const baseId = match?.id ?? undefined; diff --git a/src/utils/hack.ts b/src/utils/hack.ts index 2658042..4002010 100644 --- a/src/utils/hack.ts +++ b/src/utils/hack.ts @@ -2,6 +2,7 @@ import type { SupabaseClient } from "@supabase/supabase-js"; import { checkUserRoles } from "@/utils/user"; type HackWithArchiveFields = { + is_archive: boolean; original_author: string | null; current_patch: number | null; permission_from?: string | null; @@ -9,24 +10,24 @@ type HackWithArchiveFields = { }; /** - * Check if a hack is an informational archive (has original_author but no patch) + * Check if a hack is an informational archive (archive flag set, no patch) */ export function isInformationalArchiveHack(hack: HackWithArchiveFields): boolean { - return hack.original_author != null && hack.current_patch === null; + return hack.is_archive === true && hack.current_patch === null; } /** - * Check if a hack is a downloadable archive (has original_author, patch, and permission_from) + * Check if a hack is a downloadable archive (archive flag set with patch and permission) */ export function isDownloadableArchiveHack(hack: HackWithArchiveFields): boolean { - return hack.original_author != null && hack.current_patch !== null && hack.permission_from != null; + return hack.is_archive === true && hack.current_patch !== null && hack.permission_from != null; } /** * Check if a hack is any type of archive (informational or downloadable) */ export function isArchiveHack(hack: HackWithArchiveFields): boolean { - return isInformationalArchiveHack(hack) || isDownloadableArchiveHack(hack); + return hack.is_archive === true; } /**