Skip to content

Commit 218577d

Browse files
client のリファクタリング (#192)
* feat(WorksImages): create a new component to display works images in a list format for better code reuse refactor(Arranger, Category, Exhibition, Material, Season): replace individual image rendering functions with WorksImages component to reduce code duplication and improve maintainability close #185 * refactor(Index.tsx): rename date variables for consistency and clarity feat(Index.tsx): add loading state for exhibitions to improve user experience * style(WorkImages.tsx, ArrangerWork.tsx, CategoryWork.tsx, ExhibitionWork.tsx, MaterialWork.tsx, SeasonWork.tsx): replace fragment shorthand with section tags for better semantic structure and accessibility
1 parent 15f569f commit 218577d

File tree

13 files changed

+60
-155
lines changed

13 files changed

+60
-155
lines changed

client/src/components/WorkImages.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ export default function WorkImages({ work }: { work: Work }) {
66
return <p>この作品には写真がありません。</p>;
77
}
88
return (
9-
<>
9+
<section>
1010
<h2>作品写真</h2>
1111
<div>
1212
<ul role="list" className="work-image-list">
@@ -21,6 +21,6 @@ export default function WorkImages({ work }: { work: Work }) {
2121
))}
2222
</ul>
2323
</div>
24-
</>
24+
</section>
2525
);
2626
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import { type components } from "../types/api";
2+
import { Link } from "react-router";
3+
4+
type Work = components["schemas"]["Work"];
5+
6+
export default function WorksImages({ works }: { works: Work[] }) {
7+
return (
8+
<section>
9+
<ul role="list" className="works-image-list">
10+
{works.map((work, index) => (
11+
<li key={index}>
12+
<Link to={`work/${work.id}`}>
13+
<img
14+
className="works-image-list__image"
15+
src={`${import.meta.env.VITE_API_BASE_URL}/images/${work.image_ids[0]}`}
16+
alt={work.title ? work.title : "無題の作品"}
17+
/>
18+
</Link>
19+
</li>
20+
))}
21+
</ul>
22+
</section>
23+
);
24+
}

client/src/pages/Arranger.tsx

Lines changed: 4 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,17 @@
11
import { type components } from "../types/api";
22
import "./works.css"; // ToDo: CSS のインポートの変更
3-
import { Link, useParams } from "react-router";
3+
import { useParams } from "react-router";
44
import { useArranger, useArrangerWorkListItems } from "../hooks/arranger";
5+
import WorksImages from "../components/WorksImages";
56

67
type Arranger = components["schemas"]["Arranger"];
78
type Work = components["schemas"]["Work"];
89

9-
function ArrangerImages({ arrangerWorks }: { arrangerWorks: Work[] }) {
10-
return (
11-
<>
12-
<div>
13-
<ul role="list" className="works-image-list">
14-
{arrangerWorks.map((work, index) => (
15-
<li key={index}>
16-
<Link to={`work/${work.id}`}>
17-
<img
18-
className="works-image-list__image"
19-
src={`${import.meta.env.VITE_API_BASE_URL}/images/${work.image_ids[0]}`}
20-
alt={work.title ? work.title : "無題の作品"}
21-
/>
22-
</Link>
23-
</li>
24-
))}
25-
</ul>
26-
</div>
27-
</>
28-
);
29-
}
30-
3110
export default function Arranger() {
3211
const params = useParams();
3312
const arrangerId = Number(params.arrangerId);
3413
const arranger = useArranger(arrangerId);
35-
const arrangerWorks = Object.values(useArrangerWorkListItems(arrangerId)).map(
14+
const arrangerWorks: Work[] = Object.values(useArrangerWorkListItems(arrangerId)).map(
3615
(item) => item.work
3716
);
3817

@@ -45,11 +24,9 @@ export default function Arranger() {
4524
}
4625

4726
return (
48-
<>
4927
<main>
5028
<h1>{arranger.name}の作品一覧</h1>
51-
<ArrangerImages arrangerWorks={arrangerWorks} />
29+
<WorksImages works={arrangerWorks} />
5230
</main>
53-
</>
5431
);
5532
}

client/src/pages/ArrangerWork.tsx

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,13 +61,11 @@ export default function ArrangerWork() {
6161
}
6262

6363
return (
64-
<>
6564
<main>
6665
<WorkHeading arranger={arranger} />
6766
<WorkImages work={workListItem.work} />
6867
<AdjacentNavigation arrangerId={arrangerId} navigation={navigation} />
6968
<WorkMetadata work={workListItem.work} />
7069
</main>
71-
</>
7270
);
7371
}

client/src/pages/Category.tsx

Lines changed: 3 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,12 @@
11
import { type components } from "../types/api";
22
import "./works.css"; // ToDo: CSS のインポートの変更
3-
import { Link, useParams } from "react-router";
3+
import { useParams } from "react-router";
44
import { useCategory, useCategoryWorkListItems } from "../hooks/category";
5+
import WorksImages from "../components/WorksImages";
56

67
type Work = components["schemas"]["Work"];
78
type Category = components["schemas"]["Category"];
89

9-
function CategoryImages({ categoryWorks }: { categoryWorks: Work[] }) {
10-
return (
11-
<>
12-
<div>
13-
<ul role="list" className="works-image-list">
14-
{categoryWorks.map((work, index) => (
15-
<li key={index}>
16-
<Link to={`work/${work.id}`}>
17-
<img
18-
className="works-image-list__image"
19-
src={`${import.meta.env.VITE_API_BASE_URL}/images/${work.image_ids[0]}`}
20-
alt={work.title ? work.title : "無題の作品"}
21-
/>
22-
</Link>
23-
</li>
24-
))}
25-
</ul>
26-
</div>
27-
</>
28-
);
29-
}
30-
3110
export default function Category() {
3211
const params = useParams();
3312
const categoryId = Number(params.categoryId);
@@ -45,11 +24,9 @@ export default function Category() {
4524
}
4625

4726
return (
48-
<>
4927
<main>
5028
<h1>{category.name}の作品一覧</h1>
51-
<CategoryImages categoryWorks={categoryWorks} />
29+
<WorksImages works={categoryWorks} />
5230
</main>
53-
</>
5431
);
5532
}

client/src/pages/CategoryWork.tsx

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,13 @@ type WorkListNavigation = components["schemas"]["WorkListNavigation"];
1111

1212
function WorkHeading({ category }: { category: Category }) {
1313
const title: string = category.name;
14-
const works_url: string = `/category/${category.id}`;
14+
const worksUrl: string = `/category/${category.id}`;
1515

1616
return (
1717
<>
1818
<h1>{title}の作品</h1>
1919
<nav>
20-
<Link to={works_url}>作品一覧へ戻る</Link>
20+
<Link to={worksUrl}>作品一覧へ戻る</Link>
2121
</nav>
2222
</>
2323
);
@@ -62,13 +62,11 @@ export default function CategoryWork() {
6262
}
6363

6464
return (
65-
<>
6665
<main>
6766
<WorkHeading category={category} />
6867
<WorkImages work={work} />
6968
<AdjacentNavigation categoryId={categoryId} navigation={navigation} />
7069
<WorkMetadata work={work} />
7170
</main>
72-
</>
7371
);
7472
}

client/src/pages/Exhibition.tsx

Lines changed: 3 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,12 @@
11
import { type components } from "../types/api";
22
import "./works.css"; // ToDo: CSS のインポートの変更
3-
import { Link, useParams } from "react-router";
3+
import { useParams } from "react-router";
44
import { useExhibition, useExhibitionWorkListItems } from "../hooks/exhibition";
5+
import WorksImages from "../components/WorksImages";
56

67
type Exhibition = components["schemas"]["Exhibition"];
78
type Work = components["schemas"]["Work"];
89

9-
function ExhibitionImages({ exhibitionWorks }: { exhibitionWorks: Work[] }) {
10-
return (
11-
<>
12-
<div>
13-
<ul role="list" className="works-image-list">
14-
{exhibitionWorks.map((work, index) => (
15-
<li key={index}>
16-
<Link to={`work/${work.id}`}>
17-
<img
18-
className="works-image-list__image"
19-
src={`${import.meta.env.VITE_API_BASE_URL}/images/${work.image_ids[0]}`}
20-
alt={work.title ? work.title : "無題の作品"}
21-
/>
22-
</Link>
23-
{/* ToDo: 遅延読み込み、work.image_ids[0] が存在しない場合の処理 */}
24-
</li>
25-
))}
26-
</ul>
27-
</div>
28-
</>
29-
);
30-
}
31-
3210
export default function Exhibition() {
3311
const params = useParams();
3412
const exhibitionId = Number(params.exhibitionId);
@@ -46,11 +24,9 @@ export default function Exhibition() {
4624
}
4725

4826
return (
49-
<>
5027
<main>
5128
<h1>{`${exhibition.name}の作品一覧`}</h1>
52-
<ExhibitionImages exhibitionWorks={exhibitionWorks} />
29+
<WorksImages works={exhibitionWorks} />
5330
</main>
54-
</>
5531
);
5632
}

client/src/pages/ExhibitionWork.tsx

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,13 +61,11 @@ export default function ExhibitionWork() {
6161
}
6262

6363
return (
64-
<>
6564
<main>
6665
<WorkHeading exhibition={exhibition} />
6766
<WorkImages work={work} />
6867
<AdjacentNavigation exhibitionId={exhibitionId} navigation={navigation} />
6968
<WorkMetadata work={work} />
7069
</main>
71-
</>
7270
);
7371
}

client/src/pages/Index.tsx

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,17 @@ type Exhibition = components["schemas"]["Exhibition"];
77

88
// ToDo: 日付フォーマットの方法について検討
99
function ExhibitionInfo({ exhibition }: { exhibition: Exhibition }) {
10-
const started_date = new Date(exhibition.started_date);
11-
const ended_date = new Date(exhibition.ended_date);
10+
const startedDate = new Date(exhibition.started_date);
11+
const endedDate = new Date(exhibition.ended_date);
1212

1313
return (
1414
<article>
1515
<h3>
1616
<Link to={`/exhibition/${exhibition.id}`}>{exhibition.name}</Link>
1717
</h3>
1818
<p>
19-
開催期間: {started_date.toLocaleDateString("ja-JP")}-
20-
{ended_date.toLocaleDateString("ja-JP")}
19+
開催期間: {startedDate.toLocaleDateString("ja-JP")}-
20+
{endedDate.toLocaleDateString("ja-JP")}
2121
</p>
2222
</article>
2323
);
@@ -45,13 +45,19 @@ function ExhibitionList({ exhibitions }: { exhibitions: Record<number, Exhibitio
4545
export default function Index() {
4646
const exhibitions = useExhibitions();
4747

48-
return (
49-
<>
48+
if (!exhibitions) {
49+
return (
5050
<main>
51-
<h1>華道用写真共有Webアプリ</h1>
52-
<p>このアプリは、華道の写真を共有するための Web アプリケーションです。</p>
53-
<ExhibitionList exhibitions={exhibitions} />
51+
<h1>読み込み中</h1>
5452
</main>
55-
</>
53+
);
54+
}
55+
56+
return (
57+
<main>
58+
<h1>華道用写真共有Webアプリ</h1>
59+
<p>このアプリは、華道の写真を共有するための Web アプリケーションです。</p>
60+
<ExhibitionList exhibitions={exhibitions} />
61+
</main>
5662
);
5763
}

client/src/pages/Material.tsx

Lines changed: 3 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,12 @@
11
import { type components } from "../types/api";
22
import "./works.css"; // ToDo: CSS のインポートの変更
3-
import { Link, useParams } from "react-router";
3+
import { useParams } from "react-router";
44
import { useMaterial, useMaterialWorkListItems } from "../hooks/material";
5+
import WorksImages from "../components/WorksImages";
56

67
type Work = components["schemas"]["Work"];
78
type Material = components["schemas"]["Material"];
89

9-
function MaterialImages({ materialWorks }: { materialWorks: Work[] }) {
10-
return (
11-
<>
12-
<div>
13-
<ul role="list" className="works-image-list">
14-
{materialWorks.map((work, index) => (
15-
<li key={index}>
16-
<Link to={`work/${work.id}`}>
17-
<img
18-
className="works-image-list__image"
19-
src={`${import.meta.env.VITE_API_BASE_URL}/images/${work.image_ids[0]}`}
20-
alt={work.title ? work.title : "無題の作品"}
21-
/>
22-
</Link>
23-
</li>
24-
))}
25-
</ul>
26-
</div>
27-
</>
28-
);
29-
}
30-
3110
export default function Material() {
3211
const params = useParams();
3312
const materialId = Number(params.materialId);
@@ -45,11 +24,9 @@ export default function Material() {
4524
}
4625

4726
return (
48-
<>
4927
<main>
5028
<h1>{material.name}の作品一覧</h1>
51-
<MaterialImages materialWorks={materialWorks} />
29+
<WorksImages works={materialWorks} />
5230
</main>
53-
</>
5431
);
5532
}

0 commit comments

Comments
 (0)