From 4ab34c8f0f9b4e1f636a26012f2a75863b471c51 Mon Sep 17 00:00:00 2001
From: yyamashita <yyamashita@mosquit.one>
Date: Fri, 15 May 2026 00:22:37 +0900
Subject: Fix build: merge detail/update into existing API routes
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Parametric resource routes cause a React Router prod build error
(commonjs--resolver server-only module conflict). Merged the GET?id=
and PATCH logic into the existing api-bands.tsx and api-artists.tsx
instead of creating separate :uuid route files.

- GET /api/bands?id=UUID  → band detail with links/members
- PATCH /api/bands        → partial update (append_links, append_members)
- Same pattern for /api/artists

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
---
 app/routes/api-bands.tsx | 76 +++++++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 68 insertions(+), 8 deletions(-)

(limited to 'app/routes/api-bands.tsx')

diff --git a/app/routes/api-bands.tsx b/app/routes/api-bands.tsx
index 1bcaae2..9fda52e 100644
--- a/app/routes/api-bands.tsx
+++ b/app/routes/api-bands.tsx
@@ -1,15 +1,30 @@
-import type { ActionFunctionArgs } from "react-router";
-import { createBand, getIpAddress, listBands, toSlug, type MemberInput } from "~/lib/db.server";
+import type { ActionFunctionArgs, LoaderFunctionArgs } from "react-router";
+import {
+  createBand,
+  getBandById,
+  getBandLinks,
+  getBandMembers,
+  getIpAddress,
+  listBands,
+  toSlug,
+  updateBand,
+  type MemberInput,
+} from "~/lib/db.server";
 
-export function loader() {
+export function loader({ request }: LoaderFunctionArgs) {
+  const url = new URL(request.url);
+  const id = url.searchParams.get("id");
+  if (id) {
+    const band = getBandById(id);
+    if (!band) return Response.json({ error: "Not found" }, { status: 404 });
+    const links = getBandLinks(band.id);
+    const members = getBandMembers(band.id);
+    return Response.json({ ...band, links, members });
+  }
   return Response.json(listBands());
 }
 
 export async function action({ request }: ActionFunctionArgs) {
-  if (request.method !== "POST") {
-    return Response.json({ error: "Method not allowed" }, { status: 405 });
-  }
-
   let body: Record<string, unknown>;
   try {
     body = await request.json();
@@ -17,6 +32,52 @@ export async function action({ request }: ActionFunctionArgs) {
     return Response.json({ error: "Invalid JSON body" }, { status: 400 });
   }
 
+  if (request.method === "PATCH") {
+    const id = body.id as string | undefined;
+    if (!id) return Response.json({ error: "id is required" }, { status: 400 });
+    const band = getBandById(id);
+    if (!band) return Response.json({ error: "Not found" }, { status: 404 });
+
+    const currentLinks = getBandLinks(band.id);
+    const currentMembers = getBandMembers(band.id);
+
+    const patchLinks = (body.links as { label: string; url: string }[] | undefined) ?? [];
+    const patchMembers = (body.members as MemberInput[] | undefined) ?? [];
+    const appendLinks = body.append_links !== false;
+    const appendMembers = body.append_members !== false;
+
+    const existingUrls = new Set(currentLinks.map((l) => l.url));
+    const newLinks = appendLinks
+      ? [...currentLinks.map((l) => ({ label: l.label, url: l.url })), ...patchLinks.filter((l) => !existingUrls.has(l.url))]
+      : patchLinks;
+
+    const existingArtistIds = new Set(currentMembers.map((m) => m.artist_id));
+    const newMembers: MemberInput[] = appendMembers
+      ? [
+          ...currentMembers.map((m) => ({ artist_id: m.artist_id, role: m.role, since: m.since ?? "", until: m.until ?? "", note: m.note ?? "" })),
+          ...patchMembers.filter((m) => !existingArtistIds.has(m.artist_id)),
+        ]
+      : patchMembers;
+
+    updateBand(band.id, {
+      slug: (body.slug as string | undefined) ?? band.slug,
+      name: (body.name as string | undefined) ?? band.name,
+      area: (body.area as string | undefined) ?? band.area,
+      description: "description" in body ? (body.description as string | null) : band.description,
+      status: (body.status as string | undefined) ?? band.status,
+      links: newLinks,
+      members: newMembers,
+      message: (body.message as string | undefined) || "API update",
+      ip_address: getIpAddress(request),
+    });
+
+    return Response.json(getBandById(band.id));
+  }
+
+  if (request.method !== "POST") {
+    return Response.json({ error: "Method not allowed" }, { status: 405 });
+  }
+
   const name = (body.name as string | undefined)?.trim();
   if (!name) return Response.json({ error: "name is required" }, { status: 400 });
 
@@ -45,4 +106,3 @@ export async function action({ request }: ActionFunctionArgs) {
     throw e;
   }
 }
-
-- 
cgit v1.2.3

