summaryrefslogtreecommitdiff
path: root/app/routes/artist-by-uuid.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'app/routes/artist-by-uuid.tsx')
-rw-r--r--app/routes/artist-by-uuid.tsx98
1 files changed, 59 insertions, 39 deletions
diff --git a/app/routes/artist-by-uuid.tsx b/app/routes/artist-by-uuid.tsx
index a65525b..7ddf318 100644
--- a/app/routes/artist-by-uuid.tsx
+++ b/app/routes/artist-by-uuid.tsx
@@ -1,6 +1,14 @@
import { data, Link, useLoaderData } from "react-router";
import type { LoaderFunctionArgs } from "react-router";
-import { getArtistById, getArtistLinks, getArtistMembers, getArtistRevisions, type ArtistMemberRow } from "~/lib/db.server";
+import {
+ getArtistById,
+ getArtistLinks,
+ getArtistMembers,
+ getArtistRevisions,
+ groupArtistMembers,
+ type BandGroup,
+} from "~/lib/db.server";
+import { formatDuration } from "~/lib/utils";
export async function loader({ params }: LoaderFunctionArgs) {
const artist = getArtistById(params.uuid!);
@@ -8,21 +16,49 @@ export async function loader({ params }: LoaderFunctionArgs) {
const links = getArtistLinks(artist.id);
const memberships = getArtistMembers(artist.id);
const revisions = getArtistRevisions(artist.id);
- return { artist, links, memberships, latest: revisions[0] ?? null };
+ const grouped = groupArtistMembers(memberships);
+ return { artist, links, grouped, latest: revisions[0] ?? null };
}
-function periodLabel(m: ArtistMemberRow): string | null {
- if (!m.since && !m.until) return null;
- const from = m.since || "?";
- const to = m.until || "現在";
- return `${from} 〜 ${to}`;
+function periodRange(since: string, until: string): string | null {
+ if (!since && !until) return null;
+ return `${since || "?"} 〜 ${until || "現在"}`;
}
-export default function ArtistDetail() {
- const { artist, links, memberships, latest } = useLoaderData<typeof loader>();
+function BandItem({ group }: { group: BandGroup }) {
+ const roles = [...new Set(group.periods.flatMap((p) =>
+ p.role ? p.role.split(", ").filter(Boolean) : []
+ ))];
+ const hasPeriodInfo = group.periods.some((p) => p.since || p.until || p.note);
+ return (
+ <li>
+ <div className="member-main">
+ <Link to={`/bands/of/${group.band_id}`}>{group.band_name}</Link>
+ {roles.map((r, i) => <span key={i} className="badge">{r}</span>)}
+ {group.duration_months !== null && (
+ <span className="muted">{formatDuration(group.duration_months)}</span>
+ )}
+ </div>
+ {hasPeriodInfo && (
+ <ul className="period-list">
+ {group.periods.map((p) => {
+ const range = periodRange(p.since, p.until);
+ if (!range && !p.note) return null;
+ return (
+ <li key={p.id} className="period-item">
+ {range && <span className="period-range">{range}</span>}
+ {p.note && <span className="period-note">{p.note}</span>}
+ </li>
+ );
+ })}
+ </ul>
+ )}
+ </li>
+ );
+}
- // group by band_id
- const bandIds = [...new Set(memberships.map((m) => m.band_id))];
+export default function ArtistDetail() {
+ const { artist, links, grouped, latest } = useLoaderData<typeof loader>();
return (
<main>
@@ -34,36 +70,20 @@ export default function ArtistDetail() {
</div>
</div>
- {bandIds.length > 0 && (
+ {grouped.current.length > 0 && (
<section>
- <h2>バンド</h2>
+ <h2>在籍中のバンド</h2>
<ul className="member-list">
- {bandIds.map((bandId) => {
- const group = memberships.filter((m) => m.band_id === bandId);
- const first = group[0];
- return (
- <li key={bandId}>
- <div className="member-main">
- <Link to={`/bands/of/${bandId}`}>{first.band_name}</Link>
- {first.role && <span className="muted">{first.role}</span>}
- </div>
- {group.some((m) => m.since || m.until || m.note) && (
- <ul className="period-list">
- {group.map((m) => {
- const label = periodLabel(m);
- if (!label && !m.note) return null;
- return (
- <li key={m.id} className="period-item">
- {label && <span className="period-range">{label}</span>}
- {m.note && <span className="period-note">{m.note}</span>}
- </li>
- );
- })}
- </ul>
- )}
- </li>
- );
- })}
+ {grouped.current.map((g) => <BandItem key={g.band_id} group={g} />)}
+ </ul>
+ </section>
+ )}
+
+ {grouped.former.length > 0 && (
+ <section>
+ <h2>元在籍バンド</h2>
+ <ul className="member-list former">
+ {grouped.former.map((g) => <BandItem key={g.band_id} group={g} />)}
</ul>
</section>
)}