Skip to content

Commit 1547e69

Browse files
authored
feat: 리뷰 작성 페이지 UI 구현 (#246)
* feat: 후기 작성 페이지 UI 구현 * feat: 별점 기능 추가 * feat: 작품 특징 선택 기능 추가 * feat: 뒤로가기, 취소하기, 작성하기, 후기 삭제 클릭 시 이전 화면으로 돌아가기
1 parent 94c6244 commit 1547e69

File tree

4 files changed

+228
-1
lines changed

4 files changed

+228
-1
lines changed

src/App.jsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import FindBar from "./pages/auth/FindBar";
1717
import PostGallery from "./pages/work/postList/PostGallery";
1818

1919
import Detail from "./pages/work/Detail.tsx";
20+
import ReviewWrite from "./pages/work/review/reviewWrite";
2021

2122
import PostView from "./pages/work/PostView";
2223
import PostWork from "./pages/work/PostWork";
@@ -84,6 +85,7 @@ function App() {
8485

8586
<Route path="list/detail/:id" element={<Detail />} />
8687
<Route path="list/view/:id" element={<PostView />} />
88+
<Route path="list/review/write/:id" element={<ReviewWrite />} />
8789
<Route
8890
path="purchase/:id"
8991
element={<ProtectedRoute element={<Purchase />} />}

src/components/button/GoBack.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,11 @@ const GoBack = ({ url }: GoBackProps) => {
2121
<div
2222
className="a-items-center c-pointer go-back no-drag"
2323
onClick={() => {
24-
navigate(url);
24+
if (url === "-1") {
25+
navigate(-1); // 숫자형으로 이전 페이지로 이동
26+
} else {
27+
navigate(url); // 지정된 경로로 이동
28+
}
2529
}}
2630
>
2731
<img src={goBackArrowImg} alt="go back"></img>
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
@use "../../../styles/_responsive.scss" as r;
2+
3+
.all {
4+
@include r.media-desktop {
5+
width: 1280px;
6+
}
7+
@include r.media-laptop {
8+
width: 1280px;
9+
}
10+
@include r.media-tablet {
11+
width: 780px;
12+
}
13+
@include r.media-mobile {
14+
width: 88.3%;
15+
}
16+
}
17+
18+
.content {
19+
@include r.media-desktop {
20+
width: 630px;
21+
}
22+
@include r.media-laptop {
23+
width: 630px;
24+
}
25+
}
26+
27+
.content-img {
28+
@include r.media-desktop {
29+
width: 197px;
30+
}
31+
@include r.media-laptop {
32+
width: 197px;
33+
}
34+
}
Lines changed: 187 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,187 @@
1+
import { useState, useRef, useEffect, useContext } from "react";
2+
import { useParams, useLocation, useNavigate } from "react-router-dom";
3+
import HeaderWithBack from "@/components/header/HeaderWithBack";
4+
import GoBack from "@/components/button/GoBack";
5+
import defaultImg from "@/assets/image/post/list/defaultProfile.png";
6+
import SmallOnOffBtn from "@/components/button/RoundBtn_135_40";
7+
import "./reviewWrite.scss";
8+
const reviewWrite = () => {
9+
const { id } = useParams<string>();
10+
const [text, setText] = useState("");
11+
const [selectedStar, setSelectedStar] = useState(0);
12+
const [reason, setEeason] = useState<Record<string, boolean>>({
13+
"캐릭터가 매력적이에요": false,
14+
"관계성이 탄탄해요": false,
15+
"스토리가 좋아요": false,
16+
});
17+
const navigate = useNavigate();
18+
19+
const handleChange = (e: any) => {
20+
setText(e.target.value);
21+
};
22+
23+
const hasSelectedReason = Object.values(reason).some((value) => value);
24+
return (
25+
<div className="mx-auto all pb-[92px]">
26+
<div className="mt-[37px] flex flex-col gap-[14px]">
27+
<GoBack url="-1" />
28+
29+
<div className="flex flex-col gap-[75px] border-b-1 border-[#B489FF] ">
30+
<h1 className="h4-bold">후기를 작성해 주세요!</h1>
31+
<span></span>
32+
</div>
33+
</div>
34+
35+
<div className="mx-auto content mt-[35px]">
36+
<div className=" flex flex-col gap-[35px]">
37+
<div className="flex flex-row gap-[34px]">
38+
<div className={`flex flex-col content-img gap-[7px] `}>
39+
<img
40+
src={defaultImg}
41+
className="border border-[var(--grey3)] rounded-[20px]"
42+
></img>
43+
<div className="flex flex-col gap-[3px]">
44+
<span className="w-full truncate p-large-bold">
45+
제목제목제목제목제목제목제목제목
46+
</span>
47+
<span className="w-full truncate p-medium-bold">
48+
작가작가작가작가작가작가자가자가작
49+
</span>
50+
</div>
51+
</div>
52+
53+
<div className="flex flex-col w-full gap-[47px]">
54+
<div>
55+
{/* 작품의 평점 */}
56+
<span className="p-large-bold mb-[11px]">작품의 평점</span>
57+
<div className="flex flex-row gap-[15px]">
58+
<div className="flex flex-row gap-[2px]">
59+
{Array.from({ length: 5 }, (_, i) => (
60+
<div
61+
key={i}
62+
onClick={() => {
63+
if (selectedStar === i + 1) {
64+
setSelectedStar(i);
65+
} else {
66+
setSelectedStar(i + 1);
67+
}
68+
}}
69+
className="cursor-pointer"
70+
>
71+
{i >= selectedStar ? (
72+
<svg
73+
xmlns="http://www.w3.org/2000/svg"
74+
width="25"
75+
height="25"
76+
viewBox="0 0 25 25"
77+
fill="none"
78+
>
79+
<path
80+
d="M22.1694 8.6211L15.9707 7.72022L13.1997 2.10255C13.124 1.94874 12.9995 1.82423 12.8457 1.74854C12.4599 1.55811 11.9912 1.71681 11.7983 2.10255L9.02731 7.72022L2.82858 8.6211C2.65768 8.64552 2.50143 8.72608 2.3818 8.84815C2.23717 8.9968 2.15748 9.19679 2.16022 9.40416C2.16297 9.61154 2.24794 9.80935 2.39645 9.95411L6.88131 14.3267L5.82174 20.501C5.79689 20.6446 5.81279 20.7923 5.86762 20.9274C5.92245 21.0624 6.01403 21.1794 6.13196 21.2651C6.2499 21.3507 6.38948 21.4016 6.53487 21.412C6.68027 21.4224 6.82565 21.3918 6.95455 21.3237L12.499 18.4087L18.0434 21.3237C18.1948 21.4043 18.3706 21.4312 18.539 21.4019C18.9638 21.3286 19.2495 20.9258 19.1762 20.501L18.1167 14.3267L22.6015 9.95411C22.7236 9.83448 22.8042 9.67823 22.8286 9.50733C22.8945 9.08009 22.5966 8.68458 22.1694 8.6211ZM16.2295 13.7114L17.1108 18.8457L12.499 16.4238L7.88717 18.8482L8.76852 13.7139L5.03805 10.0762L10.1943 9.32667L12.499 4.65626L14.8037 9.32667L19.9599 10.0762L16.2295 13.7114Z"
81+
fill="#BABABA"
82+
/>
83+
</svg>
84+
) : (
85+
<svg
86+
xmlns="http://www.w3.org/2000/svg"
87+
width="25"
88+
height="25"
89+
viewBox="0 0 25 25"
90+
fill="none"
91+
>
92+
<path
93+
d="M22.1694 8.6211L15.9707 7.72022L13.1997 2.10255C13.124 1.94874 12.9995 1.82423 12.8457 1.74854C12.4599 1.55811 11.9912 1.71681 11.7983 2.10255L9.02731 7.72022L2.82858 8.6211C2.65768 8.64552 2.50143 8.72608 2.3818 8.84815C2.23717 8.9968 2.15748 9.19679 2.16022 9.40416C2.16297 9.61154 2.24794 9.80935 2.39645 9.95411L6.88131 14.3267L5.82174 20.501C5.79689 20.6446 5.81279 20.7923 5.86762 20.9274C5.92245 21.0624 6.01403 21.1794 6.13196 21.2651C6.2499 21.3507 6.38948 21.4016 6.53487 21.412C6.68027 21.4224 6.82565 21.3918 6.95455 21.3237L12.499 18.4087L18.0434 21.3237C18.1948 21.4043 18.3706 21.4312 18.539 21.4019C18.9638 21.3286 19.2495 20.9258 19.1762 20.501L18.1167 14.3267L22.6015 9.95411C22.7236 9.83448 22.8042 9.67823 22.8286 9.50733C22.8945 9.08009 22.5966 8.68458 22.1694 8.6211Z"
94+
fill="#6A39C0"
95+
/>
96+
</svg>
97+
)}
98+
</div>
99+
))}
100+
</div>
101+
<span className="flex flex-row gap-[9px]">
102+
<p className="p-large-bold">{selectedStar}</p>
103+
<p className="p-medium-regular">/ 5</p>
104+
</span>
105+
</div>
106+
</div>
107+
108+
{/* 이 작품은 특히*/}
109+
<div>
110+
<span className=" p-large-bold mb-[10px]">
111+
이 작품은 특히...
112+
</span>
113+
<span className="flex flex-row gap-[20px] whitespace-nowrap">
114+
{Object.entries(reason).map(([label, selected]) => (
115+
<button
116+
key={label}
117+
onClick={() =>
118+
setEeason((prev) => ({
119+
...prev,
120+
[label]: !prev[label],
121+
}))
122+
}
123+
className={`cursor-pointer hover:text-[var(--purple5)] p-medium-medium ${
124+
selected ? "text-[var(--purple5)] " : ""
125+
}`}
126+
>
127+
{label}
128+
</button>
129+
))}
130+
</span>
131+
</div>
132+
</div>
133+
</div>
134+
135+
<div className="flex flex-col">
136+
<span className="p-large-bold mb-[10px]"> 내용 작성</span>
137+
<div className="flex flex-col border-[0.5px] rounded-[5px] h-[250px] ">
138+
<textarea
139+
className=" p-medeim-regular h-[203px] p-[20px] border-none box-border resize-none rounded-[5px] focus:outline-none focus:ring-0 "
140+
onChange={handleChange}
141+
></textarea>
142+
<span className="h-[47px] bg-[var(--purple10)] w-full flex flex-row justify-between rounded-[5px] ">
143+
<p className="flex my-auto ml-[20px] w-fit p-medium-regular">
144+
EX) 내용이 재밌었요!
145+
</p>
146+
<span className="my-auto mr-[13px]">
147+
{text.length} / 50자 이상
148+
</span>
149+
</span>
150+
</div>
151+
</div>
152+
</div>
153+
154+
<ul className="text-[var(--grey5)] p-small-bold p-[0] m-[0] list-none mt-[30px]">
155+
<li>• 후기 작성 시 유의사항</li>
156+
<li className="list-none">
157+
- 비속어 및 부적절한 내용은 별도의 고지 없이 삭제됩니다.
158+
</li>
159+
</ul>
160+
161+
<div className="flex flex-row gap-[15px] justify-end mt-[80px]">
162+
<SmallOnOffBtn color="white" onClick={() => navigate(-1)}>
163+
취소하기
164+
</SmallOnOffBtn>
165+
<SmallOnOffBtn
166+
color="purple"
167+
disabled={
168+
text.length < 50 || selectedStar < 1 || !hasSelectedReason
169+
}
170+
onClick={() => navigate(-1)}
171+
>
172+
작성하기
173+
</SmallOnOffBtn>
174+
</div>
175+
176+
<span
177+
className="flex justify-end p-small-under mt-[80px] cursor-pointer"
178+
onClick={() => navigate(-1)}
179+
>
180+
후기 삭제
181+
</span>
182+
</div>
183+
</div>
184+
);
185+
};
186+
187+
export default reviewWrite;

0 commit comments

Comments
 (0)