Skip to content

Commit 0502749

Browse files
committed
✨ Sort translations
1 parent 5379b40 commit 0502749

File tree

5 files changed

+150
-35
lines changed

5 files changed

+150
-35
lines changed

app/jargon/[slug]/page.tsx

Lines changed: 9 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,7 @@ import CommentThread from "@/components/comment/comment-thread";
55
import SuggestTranslationDialog from "@/components/dialogs/suggest-translation-dialog";
66
import ShareButton from "@/components/share-button";
77
import { Comment } from "@/types/comment";
8-
import JargonActions from "@/components/jargon/jargon-actions";
9-
import TranslationActions from "@/components/jargon/translation-actions";
8+
import JargonTranslationsSection from "@/components/jargon/jargon-translations-section";
109
import UpdateJargonCategoriesDialog from "@/components/jargon/update-jargon-categories-dialog";
1110

1211
export default async function JargonDetailPage({
@@ -59,42 +58,18 @@ export default async function JargonDetailPage({
5958
</div>
6059
<ShareButton label="공유" />
6160
</div>
62-
<div className="flex items-center gap-2">
63-
<h1 className="text-2xl font-bold">{jargon.name}</h1>
64-
<JargonActions
65-
jargonId={jargon.id}
66-
authorId={jargon.author_id}
67-
name={jargon.name}
68-
/>
69-
</div>
70-
{jargon.translations.length > 0 ? (
71-
<div className="text-foreground text-base">
72-
<ul className="list-disc pl-5">
73-
{jargon.translations.map((tran) => (
74-
<li
75-
key={tran.id}
76-
className="text-foreground flex items-center gap-2"
77-
>
78-
<span>{tran.name}</span>
79-
<TranslationActions
80-
id={tran.id}
81-
authorId={tran.author_id}
82-
name={tran.name}
83-
/>
84-
</li>
85-
))}
86-
</ul>
87-
</div>
88-
) : (
89-
<p className="text-muted-foreground text-lg">번역이 없습니다</p>
90-
)}
91-
92-
{/* Suggest translation */}
61+
{/* translations */}
62+
<JargonTranslationsSection
63+
jargonId={jargon.id}
64+
authorId={jargon.author_id}
65+
name={jargon.name}
66+
translations={jargon.translations}
67+
/>
9368
<SuggestTranslationDialog jargonId={jargon.id} />
9469
</div>
9570
</div>
9671

97-
{/* Comments section */}
72+
{/* comments */}
9873
<div className="bg-card rounded-lg p-3">
9974
<CommentThread
10075
jargonId={jargon.id}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
"use client";
2+
3+
import { useState } from "react";
4+
import TranslationList, {
5+
type TranslationListItem,
6+
type TranslationSortOption,
7+
} from "@/components/jargon/translation-list";
8+
import JargonActions from "@/components/jargon/jargon-actions";
9+
import TranslationSortButton from "@/components/jargon/translation-sort-button";
10+
11+
export default function JargonTranslationsSection({
12+
jargonId,
13+
authorId,
14+
name,
15+
translations,
16+
}: {
17+
jargonId: string;
18+
authorId: string;
19+
name: string;
20+
translations: TranslationListItem[];
21+
}) {
22+
const [sort, setSort] = useState<TranslationSortOption>("recent");
23+
24+
return (
25+
<div className="flex flex-col gap-2">
26+
<div className="flex items-baseline justify-between gap-2">
27+
<div className="flex items-baseline gap-2">
28+
<h1 className="text-2xl font-bold">{name}</h1>
29+
<JargonActions jargonId={jargonId} authorId={authorId} name={name} />
30+
</div>
31+
{translations.length > 0 && (
32+
<TranslationSortButton value={sort} onChange={setSort} />
33+
)}
34+
</div>
35+
<TranslationList translations={translations} sort={sort} />
36+
</div>
37+
);
38+
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
"use client";
2+
3+
import { useMemo } from "react";
4+
import TranslationActions from "@/components/jargon/translation-actions";
5+
6+
export type TranslationSortOption = "recent" | "abc" | "zyx";
7+
8+
export interface TranslationListItem {
9+
id: string;
10+
name: string;
11+
author_id: string;
12+
updated_at?: string;
13+
}
14+
15+
export default function TranslationList({
16+
translations,
17+
sort,
18+
}: {
19+
translations: TranslationListItem[];
20+
sort: TranslationSortOption;
21+
}) {
22+
const sorted = useMemo(() => {
23+
const copy = [...translations];
24+
if (sort === "recent") {
25+
copy.sort((a, b) => {
26+
const aTime = a.updated_at ?? "";
27+
const bTime = b.updated_at ?? "";
28+
return bTime.localeCompare(aTime);
29+
});
30+
} else if (sort === "abc") {
31+
copy.sort((a, b) => a.name.localeCompare(b.name, "ko"));
32+
} else if (sort === "zyx") {
33+
copy.sort((a, b) => b.name.localeCompare(a.name, "ko"));
34+
}
35+
return copy;
36+
}, [translations, sort]);
37+
38+
return (
39+
<ul className="list-disc pl-5">
40+
{sorted.map((tran) => (
41+
<li key={tran.id} className="text-foreground flex items-center gap-2">
42+
<span>{tran.name}</span>
43+
<TranslationActions
44+
id={tran.id}
45+
authorId={tran.author_id}
46+
name={tran.name}
47+
/>
48+
</li>
49+
))}
50+
</ul>
51+
);
52+
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
"use client";
2+
3+
import { SlidersHorizontal } from "lucide-react";
4+
import { Button } from "@/components/ui/button";
5+
import {
6+
DropdownMenu,
7+
DropdownMenuContent,
8+
DropdownMenuLabel,
9+
DropdownMenuRadioGroup,
10+
DropdownMenuRadioItem,
11+
DropdownMenuSeparator,
12+
DropdownMenuTrigger,
13+
} from "@/components/ui/dropdown-menu";
14+
import type { TranslationSortOption } from "@/components/jargon/translation-list";
15+
16+
export default function TranslationSortButton({
17+
value,
18+
onChange,
19+
}: {
20+
value: TranslationSortOption;
21+
onChange: (value: TranslationSortOption) => void;
22+
}) {
23+
return (
24+
<DropdownMenu>
25+
<DropdownMenuTrigger asChild>
26+
<Button
27+
type="button"
28+
aria-label="번역 정렬"
29+
className="size-8.5 transition-all ease-in-out hover:rounded-3xl"
30+
>
31+
<SlidersHorizontal />
32+
</Button>
33+
</DropdownMenuTrigger>
34+
<DropdownMenuContent className="w-40" align="end">
35+
<DropdownMenuLabel>정렬 기준</DropdownMenuLabel>
36+
<DropdownMenuSeparator />
37+
<DropdownMenuRadioGroup
38+
value={value}
39+
onValueChange={(val) => onChange(val as TranslationSortOption)}
40+
>
41+
<DropdownMenuRadioItem value="recent">
42+
최근 활동순
43+
</DropdownMenuRadioItem>
44+
<DropdownMenuRadioItem value="abc">가나다순</DropdownMenuRadioItem>
45+
<DropdownMenuRadioItem value="zyx">하파카순</DropdownMenuRadioItem>
46+
</DropdownMenuRadioGroup>
47+
</DropdownMenuContent>
48+
</DropdownMenu>
49+
);
50+
}

lib/supabase/repository.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ export const QUERIES = {
3535
return supabase
3636
.from("jargon")
3737
.select(
38-
"id, name, slug, created_at, author_id, translations:translation(id, name, author_id), categories:jargon_category(category:category(id, name, acronym))",
38+
"id, name, slug, created_at, author_id, translations:translation(id, name, author_id, updated_at), categories:jargon_category(category:category(id, name, acronym))",
3939
)
4040
.eq("slug", slug)
4141
.limit(1)

0 commit comments

Comments
 (0)