Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions app/musics/[musicId]/edit/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import MusicForm from "@/components/music-form";
import { fetchMusic } from "@/lib/api";

export default async function EditMusicPage({
params,
}: {
params: Promise<{ musicId: string }>;
}) {
const { musicId } = await params;
const data = await fetchMusic(musicId);

return <MusicForm data={data} title="楽曲を編集" />;
}
9 changes: 7 additions & 2 deletions app/musics/[musicId]/error.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,23 @@ import Header from "@cloudscape-design/components/header";
import SpaceBetween from "@cloudscape-design/components/space-between";

import DashboardLayout from "@/components/dashboard-layout";
import MusicBreadcrumbs from "@/components/music-breadcrumbs";

export default function MusicDetailError({ reset }: { reset: () => void }) {
return (
<DashboardLayout activeHref="/musics">
<ContentLayout header={<Header variant="h1">楽曲管理</Header>}>
<ContentLayout
breadcrumbs={
<MusicBreadcrumbs current="楽曲詳細" currentHref="/musics" />
}
header={<Header variant="h1">楽曲管理</Header>}
>
<Container>
<Alert type="error" header="楽曲を取得できませんでした">
楽曲が存在しないか、一時的に取得できません。時間をおいて再試行してください。
</Alert>
<div className="mt-4">
<SpaceBetween direction="horizontal" size="s">
<Button href="/musics">楽曲一覧に戻る</Button>
<Button onClick={reset}>再試行</Button>
</SpaceBetween>
</div>
Expand Down
22 changes: 22 additions & 0 deletions app/musics/actions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
"use server";

import {
type CreateMusicInput,
createMusic,
type MusicWithSheets,
type UpdateMusicInput,
updateMusic,
} from "@/lib/api";

export async function createMusicAction(
input: CreateMusicInput,
): Promise<MusicWithSheets> {
return createMusic(input);
}

export async function updateMusicAction(
musicId: string,
input: UpdateMusicInput,
): Promise<MusicWithSheets> {
return updateMusic(musicId, input);
}
5 changes: 5 additions & 0 deletions app/musics/new/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import MusicForm from "@/components/music-form";

export default function NewMusicPage() {
return <MusicForm title="楽曲を追加" />;
}
19 changes: 19 additions & 0 deletions components/music-breadcrumbs.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
"use client";

import BreadcrumbGroup from "@cloudscape-design/components/breadcrumb-group";

export default function MusicBreadcrumbs({
current,
currentHref,
}: {
current?: string;
currentHref?: string;
}) {
const items = [
{ text: "ホーム", href: "/" },
{ text: "楽曲管理", href: "/musics" },
...(current ? [{ text: current, href: currentHref ?? "/musics" }] : []),
];

return <BreadcrumbGroup ariaLabel="楽曲管理の階層" items={items} />;
}
8 changes: 7 additions & 1 deletion components/music-detail-loading.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,17 @@ import Header from "@cloudscape-design/components/header";
import Spinner from "@cloudscape-design/components/spinner";

import DashboardLayout from "@/components/dashboard-layout";
import MusicBreadcrumbs from "@/components/music-breadcrumbs";

export default function MusicDetailLoading() {
return (
<DashboardLayout activeHref="/musics">
<ContentLayout header={<Header variant="h1">楽曲管理</Header>}>
<ContentLayout
breadcrumbs={
<MusicBreadcrumbs current="楽曲詳細" currentHref="/musics" />
}
header={<Header variant="h1">楽曲管理</Header>}
>
<Container>
<div
aria-label="楽曲詳細を読み込み中"
Expand Down
27 changes: 17 additions & 10 deletions components/music-detail.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import SpaceBetween from "@cloudscape-design/components/space-between";
import dynamic from "next/dynamic";

import DashboardLayout from "@/components/dashboard-layout";
import MusicBreadcrumbs from "@/components/music-breadcrumbs";
import type { MusicWithSheets } from "@/lib/api";

const MusicSheetsTable = dynamic(
Expand All @@ -32,11 +33,17 @@ export default function MusicDetail({ data }: { data: MusicWithSheets }) {
header={
<Header
variant="h1"
actions={<Button href="/musics">楽曲一覧に戻る</Button>}
actions={<Button href={`/musics/${music.id}/edit`}>編集</Button>}
>
{music.title}
</Header>
}
breadcrumbs={
<MusicBreadcrumbs
current={music.title}
currentHref={`/musics/${encodeURIComponent(music.id)}`}
/>
}
>
<SpaceBetween size="l">
<Container header={<Header variant="h2">楽曲情報</Header>}>
Expand All @@ -48,22 +55,22 @@ export default function MusicDetail({ data }: { data: MusicWithSheets }) {
<DetailItem label="ジャケット" value={music.jacket} />
<DetailItem
label="登録日時"
value={new Date(music.registrationDate).toISOString()}
value={new Date(music.registrationDate).toLocaleDateString(
"ja-JP",
)}
/>
<DetailItem
label="テスト楽曲"
value={music.isTest ? "はい" : "いいえ"}
/>
</dl>
</Container>
<Container header={<Header variant="h2">譜面</Header>}>
<MusicSheetsTable
sheets={data.sheets.map((sheet) => ({
...sheet,
difficultyLabel: difficultyLabels[sheet.difficulty],
}))}
/>
</Container>
<MusicSheetsTable
sheets={data.sheets.map((sheet) => ({
...sheet,
difficultyLabel: difficultyLabels[sheet.difficulty],
}))}
/>
</SpaceBetween>
</ContentLayout>
</DashboardLayout>
Expand Down
Loading