Skip to content

Commit 7e9d2d5

Browse files
committed
Merge branch 'develop' of https://github.com/team-incube/Gwangju-talent-festival-Client into feat/booking-api
2 parents 2b03d58 + 5d73efd commit 7e9d2d5

56 files changed

Lines changed: 1109 additions & 88 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

README.md

Lines changed: 50 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,51 @@
1-
This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/app/api-reference/cli/create-next-app).
21

3-
## Getting Started
4-
5-
First, run the development server:
6-
7-
```bash
8-
npm run dev
9-
# or
10-
yarn dev
11-
# or
12-
pnpm dev
13-
# or
14-
bun dev
15-
```
16-
17-
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
18-
19-
You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.
20-
21-
This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load [Geist](https://vercel.com/font), a new font family for Vercel.
22-
23-
## Learn More
24-
25-
To learn more about Next.js, take a look at the following resources:
26-
27-
- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
28-
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
29-
30-
You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback and contributions are welcome!
31-
32-
## Deploy on Vercel
33-
34-
The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
35-
36-
Check out our [Next.js deployment documentation](https://nextjs.org/docs/app/building-your-application/deploying) for more details.
2+
<img width="5792" height="4676" alt="Frame 19364" src="https://github.com/user-attachments/assets/f836d3c7-8809-433f-b210-48952725838d" />
3+
4+
5+
# 광주탈렌트페스티벌 공식 웹 서비스
6+
7+
[**광탈페.kr 바로가기 >**](https://www.xn--hc0b809dz3b.kr/home)
8+
9+
[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
10+
![Repo size](https://img.shields.io/github/repo-size/team-incube/Gwangju-talent-festival-Client)
11+
![Last commit](https://img.shields.io/github/last-commit/team-incube/Gwangju-talent-festival-Client?color=red)
12+
13+
This is the official web service for the Gwangju Student Talent Festival (광주학생탈렌트페스티벌).
14+
15+
## Tech Stack
16+
17+
![Top language](https://img.shields.io/github/languages/top/team-incube/Gwangju-talent-festival-Client)
18+
19+
![TypeScript](https://img.shields.io/badge/TypeScript-3178C6?logo=typescript&logoColor=white)
20+
![Next.js](https://img.shields.io/badge/Next.js-000000?logo=nextdotjs&logoColor=white)
21+
![React](https://img.shields.io/badge/React-61DAFB?logo=react&logoColor=black)
22+
![TanStack Query](https://img.shields.io/badge/TanStack%20Query-FF4154?logo=reactquery&logoColor=white)
23+
![Axios](https://img.shields.io/badge/Axios-5A29E4?logo=axios&logoColor=white)
24+
![nextjs-google-analytics](https://img.shields.io/badge/Google%20Analytics-E37400?logo=googleanalytics&logoColor=white)
25+
![sonner](https://img.shields.io/badge/sonner-000000?logo=sonos&logoColor=white)
26+
![Zod](https://img.shields.io/badge/Zod-3E67B1?logo=zod&logoColor=white)
27+
![Tailwind CSS](https://img.shields.io/badge/Tailwind_CSS-06B6D4?logo=tailwindcss&logoColor=white)
28+
29+
## Teams
30+
<table>
31+
<tr>
32+
<td align="center">
33+
<a href="https://github.com/happytaeyoon">
34+
<img src="https://avatars.githubusercontent.com/u/129380797?v=4" width="100" height="100" /><br/>
35+
김태윤
36+
</a>
37+
</td>
38+
<td align="center">
39+
<a href="https://github.com/976520">
40+
<img src="https://avatars.githubusercontent.com/u/123460320?v=4" width="100" height="100" /><br/>
41+
송재욱
42+
</a>
43+
</td>
44+
<td align="center">
45+
<a href="https://github.com/bae080311">
46+
<img src="https://avatars.githubusercontent.com/u/156505831?v=4" width="100" height="100" /><br/>
47+
배경진
48+
</a>
49+
</td>
50+
</tr>
51+
</table>

src/app/admin/evaluation/page.tsx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import EvaluationView from "@/views/evaluation/ui/EvaluationView";
2+
3+
export default function EvaluationPage() {
4+
return <EvaluationView />;
5+
}

src/app/admin/list/page.tsx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import ListView from "@/views/list/ui/ListView";
2+
3+
export default function AdminListPage() {
4+
return <ListView />;
5+
}

src/app/api/server/[...path]/route.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { NextRequest, NextResponse } from "next/server";
22

3-
const BASE_URL = process.env.NEXT_PUBLIC_BASE_URL;
3+
const BASE_URL = process.env.NEXT_PUBLIC_API_URL;
44

55
type HttpMethod = "GET" | "POST" | "PUT" | "DELETE" | "PATCH";
66

src/app/api/signup/route.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,5 @@ import { NextRequest } from "next/server";
22
import { apiHandler } from "@/shared/utils/api";
33

44
export async function POST(request: NextRequest) {
5-
return apiHandler(request, "/auth/join", "POST", 201);
5+
return apiHandler(request, "/auth/join");
66
}

src/app/api/verify/route.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import { NextRequest } from "next/server";
2+
import { apiHandler } from "@/shared/utils/api";
3+
4+
export async function POST(request: NextRequest) {
5+
return apiHandler(request, "/auth/verify");
6+
}

src/app/vote/page.tsx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import VoteView from "@/views/vote/ui/VoteView";
2+
3+
export default function VotePage() {
4+
return <VoteView />;
5+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
export const EVALUATION_CATEGORY = {
2+
COMPLETION_EXPRESSION: "완성도 및 표현력",
3+
CREATIVITY_COMPOSITION: "창의력과 구성",
4+
STAGE_MANNER_PERFORMANCE: "무대매너 및 퍼포먼스",
5+
} as const;
6+
7+
export type EvaluationCategory = keyof typeof EVALUATION_CATEGORY;
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
"use client";
2+
3+
import DownArrow from "@/shared/asset/svg/DownArrow";
4+
import { useEffect, useRef } from "react";
5+
6+
export default function CustomDropdown({
7+
value,
8+
max,
9+
isOpen,
10+
onToggle,
11+
onSelect,
12+
onDoubleClick,
13+
}: {
14+
value: number | string;
15+
max: number;
16+
isOpen: boolean;
17+
onToggle: () => void;
18+
onSelect: (value: number) => void;
19+
onDoubleClick: () => void;
20+
}) {
21+
const dropdownRef = useRef<HTMLDivElement>(null);
22+
23+
useEffect(() => {
24+
const handleClickOutside = (event: MouseEvent) => {
25+
if (dropdownRef.current && !dropdownRef.current.contains(event.target as Node)) {
26+
onToggle();
27+
}
28+
};
29+
30+
if (isOpen) {
31+
document.addEventListener("mousedown", handleClickOutside);
32+
}
33+
34+
return () => {
35+
document.removeEventListener("mousedown", handleClickOutside);
36+
};
37+
}, [isOpen, onToggle]);
38+
39+
return (
40+
<div className="relative" ref={dropdownRef}>
41+
<div className="flex gap-12 cursor-pointer" onClick={onToggle} onDoubleClick={onDoubleClick}>
42+
{value}
43+
<DownArrow />
44+
</div>
45+
46+
{isOpen && (
47+
<div className="absolute text-center top-full left-0 mt-1 bg-white border border-gray-200 rounded-md shadow-lg z-10 max-h-48 overflow-y-auto min-w-[80px]">
48+
{Array.from({ length: max }, (_, num) => (
49+
<div
50+
key={num + 1}
51+
className="px-12 text-body2r text-gray-500 py-8 hover:bg-gray-100 cursor-pointer"
52+
onClick={() => onSelect(num + 1)}
53+
>
54+
{num + 1}
55+
</div>
56+
))}
57+
</div>
58+
)}
59+
</div>
60+
);
61+
}
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
"use client";
2+
3+
import { CheckIcon } from "@/shared/asset/svg/CheckIcon";
4+
import { Button } from "@/shared/ui";
5+
import { useState } from "react";
6+
import CustomDropdown from "../Dropdown";
7+
8+
type Score = {
9+
value: number | string;
10+
write: boolean;
11+
max: number;
12+
show: boolean;
13+
};
14+
15+
const scores: Score[] = [
16+
{ value: 0, write: false, max: 40, show: false },
17+
{ value: 0, write: false, max: 30, show: false },
18+
{ value: 0, write: false, max: 30, show: false },
19+
];
20+
21+
export default function EvaluationCard({ order }: { order: number }) {
22+
const [values, setValues] = useState<Score[]>(scores);
23+
24+
return (
25+
<ul className="w-full text-body3b flex py-14 border items-center rounded-md border-gray-100 border-solid justify-between px-24 pl-[80px]">
26+
<li className="text-main-600">{order}</li>
27+
{values.map((v, i) => {
28+
return v.write ? (
29+
<input
30+
className="w-[46.53px]"
31+
key={i}
32+
max={v.max}
33+
min={0}
34+
type="number"
35+
value={v.value}
36+
onChange={e => {
37+
const val = e.target.value === "" ? "" : Number(e.target.value);
38+
39+
if (val === "" || (val <= v.max && val >= 0)) {
40+
setValues(prev =>
41+
prev.map((item, idx) => (idx === i ? { ...item, value: val } : item)),
42+
);
43+
}
44+
}}
45+
onBlur={() => {
46+
setValues(prev =>
47+
prev.map((item, idx) =>
48+
idx === i
49+
? {
50+
...item,
51+
value: item.value === 0 || Number.isNaN(item.value) ? 0 : item.value,
52+
write: false,
53+
show: false,
54+
}
55+
: item,
56+
),
57+
);
58+
}}
59+
autoFocus
60+
/>
61+
) : (
62+
<CustomDropdown
63+
key={i}
64+
value={v.value}
65+
max={v.max}
66+
isOpen={v.show}
67+
onToggle={() => {
68+
setValues(prev =>
69+
prev.map((item, idx) => (idx === i ? { ...item, show: !item.show } : item)),
70+
);
71+
}}
72+
onSelect={selectedValue => {
73+
setValues(prev =>
74+
prev.map((item, idx) =>
75+
idx === i ? { ...item, value: selectedValue, write: false, show: false } : item,
76+
),
77+
);
78+
}}
79+
onDoubleClick={() => {
80+
setValues(prev =>
81+
prev.map((item, idx) => (idx === i ? { ...item, write: true, show: false } : item)),
82+
);
83+
}}
84+
/>
85+
);
86+
})}
87+
<Button className="py-12 px-16 gap-12 w-[126px] justify-center flex items-center">
88+
<CheckIcon color="white" />9
89+
</Button>
90+
</ul>
91+
);
92+
}

0 commit comments

Comments
 (0)