This repository has been archived by the owner on Dec 16, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
85573b1
commit ccd0fee
Showing
12 changed files
with
325 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
89 changes: 89 additions & 0 deletions
89
frontend/src/app/console/roster/_components/DeleteRosterForm.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
'use client' | ||
|
||
import { | ||
Drawer, | ||
DrawerContent, | ||
DrawerDescription, | ||
DrawerHeader, | ||
DrawerTitle, | ||
DrawerTrigger | ||
} from '@/components/ui/drawer' | ||
import { | ||
Form, | ||
FormControl, | ||
FormField, | ||
FormItem, | ||
FormLabel | ||
} from '@/components/ui/form' | ||
import { Input } from '@/components/ui/input' | ||
import { RosterFormSchema } from '@/lib/forms' | ||
import type { RosterListItem } from '@/lib/types/roster' | ||
import { zodResolver } from '@hookform/resolvers/zod' | ||
import { useState } from 'react' | ||
import { useForm } from 'react-hook-form' | ||
import type { z } from 'zod' | ||
|
||
export function DeleteRosterForm({ roster }: { roster: RosterListItem }) { | ||
const DeleteRosterFormSchema = RosterFormSchema.pick({ | ||
id: true, | ||
name: true, | ||
studentId: true | ||
}) | ||
|
||
const [open, setOpen] = useState(false) | ||
|
||
const form = useForm<z.infer<typeof DeleteRosterFormSchema>>({ | ||
resolver: zodResolver(DeleteRosterFormSchema), | ||
defaultValues: { | ||
id: roster.id | ||
} | ||
}) | ||
|
||
return ( | ||
<Drawer open={open} onOpenChange={setOpen}> | ||
<DrawerTrigger asChild> | ||
<button>삭제</button> | ||
</DrawerTrigger> | ||
<DrawerContent> | ||
<div className="mx-auto w-full max-w-sm"> | ||
<Form {...form}> | ||
<form> | ||
<DrawerHeader> | ||
<DrawerTitle>로스터 삭제</DrawerTitle> | ||
<DrawerDescription> | ||
삭제할 로스터의 이름과 학번을 정확하게 입력해주세요 | ||
</DrawerDescription> | ||
</DrawerHeader> | ||
<div className="space-y-3 p-4"> | ||
<FormField | ||
control={form.control} | ||
name="name" | ||
render={({ field }) => ( | ||
<FormItem> | ||
<FormLabel>이름</FormLabel> | ||
<FormControl> | ||
<Input {...field} placeholder={roster.backNumber} /> | ||
</FormControl> | ||
</FormItem> | ||
)} | ||
/> | ||
<FormField | ||
control={form.control} | ||
name="studentId" | ||
render={({ field }) => ( | ||
<FormItem> | ||
<FormLabel>학번</FormLabel> | ||
<FormControl> | ||
<Input {...field} placeholder={roster.studentId} /> | ||
</FormControl> | ||
</FormItem> | ||
)} | ||
/> | ||
</div> | ||
</form> | ||
</Form> | ||
</div> | ||
</DrawerContent> | ||
</Drawer> | ||
) | ||
} |
117 changes: 117 additions & 0 deletions
117
frontend/src/app/console/roster/_components/RosterListTable.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
'use client' | ||
|
||
import Badge, { BadgeColor } from '@/components/Badge' | ||
import { DataTable } from '@/components/DataTable' | ||
import { Button } from '@/components/ui/button' | ||
import { | ||
DropdownMenu, | ||
DropdownMenuContent, | ||
DropdownMenuItem, | ||
DropdownMenuLabel, | ||
DropdownMenuSeparator, | ||
DropdownMenuTrigger | ||
} from '@/components/ui/dropdown-menu' | ||
import { RosterType } from '@/lib/enums' | ||
import type { RosterListItem } from '@/lib/types/roster' | ||
import { UserIcon } from '@heroicons/react/24/outline' | ||
import type { ColumnDef } from '@tanstack/react-table' | ||
import { MoreHorizontal } from 'lucide-react' | ||
import Image from 'next/image' | ||
import { DeleteRosterForm } from './DeleteRosterForm' | ||
|
||
export default function RosterListTable({ | ||
rosters | ||
}: { | ||
rosters: RosterListItem[] | ||
}) { | ||
const createTypeBadge = (type: RosterType) => { | ||
switch (type) { | ||
case RosterType.Athlete: | ||
return <Badge color={BadgeColor.indigo} content="선수" /> | ||
case RosterType.Staff: | ||
return <Badge color={BadgeColor.yellow} content="스태프" /> | ||
case RosterType.Coach: | ||
return <Badge color={BadgeColor.green} content="코치" /> | ||
case RosterType.HeadCoach: | ||
default: | ||
return <Badge color={BadgeColor.red} content="감독" /> | ||
} | ||
} | ||
|
||
const columns: ColumnDef<RosterListItem>[] = [ | ||
{ | ||
id: 'profile', | ||
header: '이름', | ||
cell: ({ row }) => { | ||
const roster = row.original | ||
|
||
return ( | ||
<div className="flex flex-nowrap items-center gap-x-1.5"> | ||
<div className="h-6 w-6 rounded-full"> | ||
{roster.profileImageUrl ? ( | ||
<Image | ||
src={roster.profileImageUrl} | ||
width={32} | ||
height={32} | ||
alt="" | ||
className="object-cover" | ||
/> | ||
) : ( | ||
<UserIcon /> | ||
)} | ||
</div> | ||
<p>{roster.name}</p> | ||
</div> | ||
) | ||
} | ||
}, | ||
{ | ||
accessorKey: 'type', | ||
header: '구분', | ||
cell: ({ row }) => { | ||
return createTypeBadge(row.getValue('type')) | ||
} | ||
}, | ||
{ | ||
accessorKey: 'studentId', | ||
header: '학번' | ||
}, | ||
{ | ||
accessorKey: 'admissionYear', | ||
header: '입학년도' | ||
}, | ||
{ | ||
accessorKey: 'registerYear', | ||
header: '입부년도' | ||
}, | ||
{ | ||
id: 'actions', | ||
cell: ({ row }) => { | ||
const roster = row.original | ||
|
||
return ( | ||
<DropdownMenu> | ||
<DropdownMenuTrigger asChild> | ||
<Button variant="ghost" className="h-8 w-8 p-0"> | ||
<span className="sr-only">Open menu</span> | ||
<MoreHorizontal className="h-4 w-4" /> | ||
</Button> | ||
</DropdownMenuTrigger> | ||
<DropdownMenuContent align="end"> | ||
<DropdownMenuLabel>메뉴</DropdownMenuLabel> | ||
<DropdownMenuSeparator /> | ||
<DropdownMenuItem onClick={() => alert(roster.id)}> | ||
수정 | ||
</DropdownMenuItem> | ||
<DropdownMenuItem> | ||
<DeleteRosterForm roster={roster} /> | ||
</DropdownMenuItem> | ||
</DropdownMenuContent> | ||
</DropdownMenu> | ||
) | ||
} | ||
} | ||
] | ||
|
||
return <DataTable columns={columns} data={rosters} /> | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,10 +1,33 @@ | ||
export default async function RosterPage() { | ||
import Pagination from '@/components/Pagination' | ||
import { getRosters } from '@/lib/actions' | ||
import { calculateTotalPages } from '@/lib/utils' | ||
import { PAGINATION_LIMIT_DEFAULT } from '@/lib/vars' | ||
import RosterListTable from './_components/RosterListTable' | ||
|
||
export default async function RosterPage({ | ||
searchParams | ||
}: { | ||
searchParams?: { | ||
page?: string | ||
} | ||
}) { | ||
const currentPage = Number(searchParams?.page) || 1 | ||
const rosterList = await getRosters(currentPage) | ||
|
||
return ( | ||
<main className="mx-auto flex w-full flex-grow flex-col items-center justify-center"> | ||
<div className="mt-4 w-full px-4 text-left sm:px-6"> | ||
<h1 className="text-base font-bold sm:text-xl">부원명단</h1> | ||
</div> | ||
<div className="flex w-full flex-grow flex-col gap-5 py-4 sm:px-6"></div> | ||
<div className="flex w-full flex-grow flex-col gap-5 py-4 sm:px-6"> | ||
<RosterListTable rosters={rosterList.rosters} /> | ||
<Pagination | ||
totalPages={calculateTotalPages( | ||
rosterList.total, | ||
PAGINATION_LIMIT_DEFAULT | ||
)} | ||
/> | ||
</div> | ||
</main> | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
import type { RosterStatus, RosterType } from '../enums' | ||
|
||
type RosterBasic = { | ||
id: number | ||
name: string | ||
type: RosterType | ||
status: RosterStatus | ||
target: boolean | ||
} | ||
|
||
export interface Roster extends RosterBasic { | ||
studentId: string | ||
admissionYear: number | ||
profileImageUrl?: string | ||
registerYear: number | ||
offPosition?: string | ||
defPosition?: string | ||
splPosition?: string | ||
backNumber?: string | ||
} | ||
|
||
export interface RosterProfile extends RosterBasic { | ||
profileImageUrl?: string | ||
registerYear: number | ||
offPosition?: string | ||
defPosition?: string | ||
splPosition?: string | ||
backNumber?: string | ||
} | ||
|
||
export interface RosterListItem extends RosterProfile { | ||
studentId: string | ||
admissionYear: number | ||
} | ||
|
||
export interface RosterList { | ||
total: number | ||
rosters: RosterListItem[] | ||
} |
Oops, something went wrong.