Skip to content

Commit 23b957c

Browse files
authored
Merge pull request #118 from team-incube/fix/evaluation
fix: 심사 페이지 변경 사항 반영
2 parents e602f93 + 75c2fcd commit 23b957c

11 files changed

Lines changed: 144 additions & 321 deletions

File tree

src/entities/evaluation/api/saveScore.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
import instance from "@/shared/lib/axios";
2+
import { AxiosError } from "axios";
3+
import { toast } from "sonner";
24

35
export const saveScore = async (
46
team_id: number,
@@ -12,8 +14,18 @@ export const saveScore = async (
1214
completion_expression,
1315
creativity_composition,
1416
});
17+
if (res.status === 200) {
18+
toast.success("심사가 저장되었습니다");
19+
}
1520
return res;
1621
} catch (error) {
17-
throw error;
22+
const axiosError = error as AxiosError;
23+
const errorMessage =
24+
axiosError?.response?.data &&
25+
typeof axiosError.response.data === "object" &&
26+
"message" in axiosError.response.data
27+
? (axiosError.response.data as { message: string }).message
28+
: "심사 실패했습니다.";
29+
throw new Error(errorMessage);
1830
}
1931
};
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
export const MAX = {
2+
perform: 30,
3+
compleition: 40,
4+
creativity: 30,
5+
} as const;

src/entities/evaluation/ui/Dropdown/index.tsx

Lines changed: 0 additions & 61 deletions
This file was deleted.
Lines changed: 73 additions & 141 deletions
Original file line numberDiff line numberDiff line change
@@ -1,167 +1,99 @@
11
"use client";
22

3-
import { CheckIcon } from "@/shared/asset/svg/CheckIcon";
4-
import { Button } from "@/shared/ui";
5-
import { useCallback, useEffect, useState } from "react";
6-
import CustomDropdown from "../Dropdown";
73
import { Score } from "@/views/evaluation/model/score";
8-
import { saveScore } from "../../api/saveScore";
9-
import { toast } from "sonner";
10-
import { colors } from "@/shared/utils/color";
114
import { cn } from "@/shared/utils/cn";
12-
13-
type Label = "completion_expression" | "creativity_composition" | "stage_manner_performance";
14-
15-
type ValueType = {
16-
write: boolean;
17-
max: number;
18-
show: boolean;
19-
label: Label;
20-
};
21-
22-
const scores: ValueType[] = [
23-
{ write: false, max: 40, show: false, label: "completion_expression" },
24-
{ write: false, max: 30, show: false, label: "creativity_composition" },
25-
{ write: false, max: 30, show: false, label: "stage_manner_performance" },
26-
];
5+
import { Button } from "@/shared/ui";
6+
import DownArrow from "@/shared/asset/svg/DownArrow";
7+
import UpArrow from "@/shared/asset/svg/UpArrow";
8+
import { useCallback, useState } from "react";
9+
import { saveScore } from "../../api/saveScore";
10+
import { MAX } from "../../const/max";
2711

2812
export default function EvaluationCard({
29-
judge_id,
3013
stage_manner_performance,
3114
completion_expression,
3215
creativity_composition,
33-
total_score,
3416
team_id,
3517
team_name,
36-
is_judged,
3718
is_performed,
3819
}: Score) {
39-
const [values, setValues] = useState<ValueType[]>(scores);
40-
const [scoreValues, setScoreValues] = useState<Record<Label, number>>({
41-
completion_expression: 0,
42-
creativity_composition: 0,
43-
stage_manner_performance: 0,
44-
});
45-
const [variant, setVariant] = useState<"submitted" | "active" | "disabled">("active");
20+
const [perform, setPerform] = useState(stage_manner_performance);
21+
const [compleition, setCompleition] = useState(completion_expression);
22+
const [creativity, setCreativity] = useState(creativity_composition);
4623

47-
useEffect(() => {
48-
setScoreValues({
49-
completion_expression: Number(completion_expression) || 0,
50-
creativity_composition: Number(creativity_composition) || 0,
51-
stage_manner_performance: Number(stage_manner_performance) || 0,
52-
});
53-
if (is_judged) {
54-
setVariant("submitted");
55-
return;
56-
} else if (!is_performed) {
57-
setVariant("disabled");
24+
const handleUp = useCallback((evaluationType: "perform" | "compleition" | "creativity") => {
25+
switch (evaluationType) {
26+
case "perform":
27+
setPerform(prev => Math.min(prev + 1, MAX.perform));
28+
break;
29+
case "compleition":
30+
setCompleition(prev => Math.min(prev + 1, MAX.compleition));
31+
break;
32+
case "creativity":
33+
setCreativity(prev => Math.min(prev + 1, MAX.creativity));
34+
break;
5835
}
59-
}, [
60-
judge_id,
61-
stage_manner_performance,
62-
completion_expression,
63-
creativity_composition,
64-
total_score,
65-
team_id,
66-
is_judged,
67-
is_performed,
68-
]);
36+
}, []);
6937

70-
const handleSave = useCallback(async () => {
71-
const { completion_expression, creativity_composition, stage_manner_performance } = scoreValues;
72-
const res = await saveScore(
73-
team_id,
74-
Number(stage_manner_performance) || 0,
75-
Number(completion_expression) || 0,
76-
Number(creativity_composition) || 0,
77-
);
78-
if (res.status === 200) {
79-
toast.success("심사 내용이 저장되었습니다");
80-
setVariant("submitted");
81-
} else {
82-
toast.error("심사 내용 저장에 실패하였습니다");
83-
setVariant("active");
38+
const handleDown = useCallback((evaluationType: "perform" | "compleition" | "creativity") => {
39+
switch (evaluationType) {
40+
case "perform":
41+
setPerform(prev => Math.max(prev - 1, 0));
42+
break;
43+
case "compleition":
44+
setCompleition(prev => Math.max(prev - 1, 0));
45+
break;
46+
case "creativity":
47+
setCreativity(prev => Math.max(prev - 1, 0));
48+
break;
8449
}
85-
}, [team_id, scoreValues]);
86-
87-
const changeActive = useCallback(() => {
88-
setVariant("active");
8950
}, []);
9051

52+
const handleSave = useCallback(() => {
53+
saveScore(team_id, perform, compleition, creativity);
54+
}, [team_id, perform, compleition, creativity]);
55+
9156
return (
92-
<ul
57+
<div
9358
className={cn(
94-
"w-full text-body3b flex py-14 border items-center rounded-md border-gray-100 border-solid justify-between px-24 pl-[80px]",
59+
"text-body1b grid grid-cols-6 py-14 border text-gray-300 mx-24 rounded-md border-gray-100 border-solid items-center text-center",
9560
!is_performed && "bg-#E9E9E9",
9661
)}
9762
>
98-
<li className="text-main-600">{team_id + ". " + team_name}</li>
99-
{values.map((v, i) => {
100-
return v.write ? (
101-
<input
102-
className="w-[46.53px]"
103-
key={v.label}
104-
max={v.max}
105-
min={0}
106-
type="number"
107-
value={scoreValues[v.label]}
108-
onChange={e => {
109-
const val = e.target.value === "" ? 0 : Number(e.target.value);
110-
111-
if (!Number.isNaN(val) && val <= v.max && val >= 0) {
112-
setScoreValues(prev => ({ ...prev, [v.label]: val }));
113-
}
114-
}}
115-
onBlur={() => {
116-
setValues(prev =>
117-
prev.map((item, idx) =>
118-
idx === i
119-
? {
120-
...item,
121-
write: false,
122-
show: false,
123-
}
124-
: item,
125-
),
126-
);
127-
}}
128-
autoFocus
129-
/>
130-
) : (
131-
<CustomDropdown
132-
key={v.label}
133-
value={scoreValues[v.label]}
134-
max={v.max}
135-
isOpen={v.show}
136-
onToggle={() => {
137-
setValues(prev =>
138-
prev.map((item, idx) => (idx === i ? { ...item, show: !item.show } : item)),
139-
);
140-
}}
141-
onSelect={selectedValue => {
142-
setScoreValues(prev => ({ ...prev, [v.label]: Number(selectedValue) }));
143-
setValues(prev =>
144-
prev.map((item, idx) =>
145-
idx === i ? { ...item, write: false, show: false } : item,
146-
),
147-
);
148-
}}
149-
onDoubleClick={() => {
150-
setValues(prev =>
151-
prev.map((item, idx) => (idx === i ? { ...item, write: true, show: false } : item)),
152-
);
153-
}}
154-
/>
155-
);
156-
})}
157-
<Button
158-
onClick={variant === "submitted" ? changeActive : handleSave}
159-
variant={variant === "submitted" ? "third" : "default"}
160-
className={cn("py-12 px-16 gap-12 w-[126px] justify-center flex items-center")}
161-
>
162-
<CheckIcon color={variant === "submitted" ? colors.main[600] : "white"} />
163-
{Object.values(scoreValues).reduce((sum, n) => sum + Number(n || 0), 0)}
164-
</Button>
165-
</ul>
63+
<div className="text-main-600 text-center">{team_id + ". " + team_name}</div>
64+
<div className="flex items-center justify-center gap-8">
65+
<span className="ml-12">{compleition}</span>
66+
<div onClick={() => handleDown("compleition")}>
67+
<DownArrow height={36} width={37} />
68+
</div>
69+
<div onClick={() => handleUp("compleition")}>
70+
<UpArrow />
71+
</div>
72+
</div>
73+
<div className="flex items-center justify-center gap-8">
74+
<span className="ml-12">{creativity}</span>
75+
<div onClick={() => handleDown("creativity")}>
76+
<DownArrow height={36} width={37} />
77+
</div>
78+
<div onClick={() => handleUp("creativity")}>
79+
<UpArrow />
80+
</div>
81+
</div>
82+
<div className="flex items-center justify-center gap-8">
83+
<span className="ml-12">{perform}</span>
84+
<div onClick={() => handleDown("perform")}>
85+
<DownArrow height={36} width={37} />
86+
</div>
87+
<div onClick={() => handleUp("perform")}>
88+
<UpArrow />
89+
</div>
90+
</div>
91+
<div className="text-main-600 text-center">{perform + compleition + creativity}</div>
92+
<div className="w-full flex justify-center px-24 gap-24">
93+
<Button onClick={handleSave} className="text-body2b w-1/2">
94+
저장
95+
</Button>
96+
</div>
97+
</div>
16698
);
16799
}
Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,29 @@
11
export default function Standard() {
22
return (
3-
<ul
4-
className="bg-gray-50 px-[40px
5-
6-
] w-full mt-24 mb-[41px] text-body3b items-center flex justify-around text-center py-24"
7-
>
8-
<li>팀명</li>
9-
<li>
3+
<div className="bg-gray-50 px-[40px] w-full mt-24 mb-20 text-body2b grid grid-cols-6 text-center py-24 items-center">
4+
<div>
5+
연번
6+
<br />
7+
(심사번호)
8+
</div>
9+
<div>
1010
완성도 및 표현력
1111
<br /> (40)
12-
</li>
13-
<li>
12+
</div>
13+
<div>
1414
창의력과 구성
1515
<br />
1616
(30)
17-
</li>
18-
<li>
17+
</div>
18+
<div>
1919
무대매너 및 퍼포먼스 등<br />
2020
(30)
21-
</li>
22-
<li>
21+
</div>
22+
<div>
2323
<br />
2424
(100)
25-
</li>
26-
</ul>
25+
</div>
26+
<div>저장</div>
27+
</div>
2728
);
2829
}

src/shared/asset/svg/UpArrow.tsx

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import { SvgProps } from "@/shared/model/SvgProps";
2+
3+
export default function UpArrow({ height = 36, width = 37, color = "#7A7A7A" }: SvgProps) {
4+
return (
5+
<svg
6+
xmlns="http://www.w3.org/2000/svg"
7+
width={width}
8+
height={height}
9+
viewBox="0 0 37 36"
10+
fill="none"
11+
>
12+
<path
13+
d="M12.68 22.0649L18.5 16.2449L24.32 22.0649C24.4589 22.2038 24.6237 22.3139 24.8052 22.3891C24.9866 22.4642 25.1811 22.5029 25.3775 22.5029C25.5739 22.5029 25.7684 22.4642 25.9498 22.3891C26.1313 22.3139 26.2961 22.2038 26.435 22.0649C26.5739 21.926 26.684 21.7611 26.7592 21.5797C26.8343 21.3983 26.873 21.2038 26.873 21.0074C26.873 20.811 26.8343 20.6165 26.7592 20.4351C26.684 20.2536 26.5739 20.0888 26.435 19.9499L19.55 13.0649C19.4112 12.9258 19.2464 12.8155 19.0649 12.7402C18.8835 12.665 18.6889 12.6262 18.4925 12.6262C18.296 12.6262 18.1015 12.665 17.9201 12.7402C17.7386 12.8155 17.5738 12.9258 17.435 13.0649L10.55 19.9499C10.4109 20.0887 10.3006 20.2535 10.2253 20.435C10.1501 20.6164 10.1113 20.8109 10.1113 21.0074C10.1113 21.2038 10.1501 21.3984 10.2253 21.5798C10.3006 21.7613 10.4109 21.9261 10.55 22.0649C11.135 22.6349 12.095 22.6499 12.68 22.0649Z"
14+
fill={color}
15+
/>
16+
</svg>
17+
);
18+
}

0 commit comments

Comments
 (0)