Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[장아영] Sprint 10 #270

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions assets/icons/ic_delete.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 5 additions & 0 deletions assets/icons/ic_kebab.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/icons/ic_plus.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions assets/icons/slash.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 2 additions & 2 deletions components/Header/MenuTab/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ export default function MenuTab() {
return (
<>
<Link
href="/community"
href="/boards"
className={
pathname === "/community"
pathname === "/boards"
? styles["menu-tab-active"]
: styles["menu-tab"]
}
Expand Down
2 changes: 0 additions & 2 deletions components/Header/MenuTab/styles.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
.menu-tab {
text-decoration: none;
color: $cool-gray;
font-family: Pretendard;
font-size: 18px;
font-weight: 700;
text-align: center;
Expand All @@ -12,7 +11,6 @@
.menu-tab-active {
text-decoration: none;
color: $brand-blue;
font-family: Pretendard;
font-size: 18px;
font-weight: 700;
text-align: center;
Expand Down
3 changes: 1 addition & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@
"axios": "^1.7.2",
"lodash-es": "^4.17.21",
"next": "14.2.5",
"react": "^18",
"react-dom": "^18",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"sass": "^1.77.8"
},
"devDependencies": {
Expand Down
137 changes: 137 additions & 0 deletions pages/addboard/index.tsx
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

addBoard 로 컴포넌트 이름을 바꿔주세요 😁
이 컴포넌트안에 너무 많은 컴포넌트들이 있는 것같아요!

파일 업로드를 할 수 있는 부분을 따로 뺀다면, 향후 어디서든 가져다 사용할 수 있고, 가독성도 늘어날 것 같습니다!

사실 파일업로드 뿐 아니라 기본 input이나 textArea도 제어컴포넌트와 함께 새로운 공용컴포넌트로 만들 수 있죠!

Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
import styles from "./styles.module.scss";
import plusIcon from "@/assets/icons/ic_plus.png";
import { ST } from "next/dist/shared/lib/utils";
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이건 안쓰이고 있는것같아요!

import Image from "next/image";
import { useState, useRef, useEffect } from "react";
import deleteIcon from "@/assets/icons/ic_delete.svg";

export default function AddBoard() {
const [preview, setPreview] = useState();
const [value, setValue] = useState();
Comment on lines +9 to +10
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

useState에 초기값을 넣어주지않는다면 자동으로 undefined가 들어갑니다! 그러면 state의 type도 undefined가 되어요!

원시값이면 type을 선언해줄 필요까지는 없지만 초기값을 넣어줘어야한답니다! 아니면 | null도 하나의 방법이겠구요!

const fileInputRef = useRef(null);
const [formState, setFormState] = useState({
title: "",
contents: "",
});

const handleInput = (e) => {
setFormState({
...formState,
[e.target.name]: e.target.value,
});
};

const handleChange = (e) => {
const nextValue = e.target.files[0];
setValue(nextValue);
};
Comment on lines +17 to +27
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

각각의 event 타입도 선언을 해주면, 사용하는곳에서 조금 더 정확히 사용할 수 있습니다!


const handleImageClick = () => {
fileInputRef.current.click();
};

const handleCancelClick = () => {
setPreview(null);
setValue(null);
fileInputRef.current.value = "";
};

useEffect(() => {
if (!value) return;

const nextPreview = URL.createObjectURL(value);
setPreview(nextPreview);
return () => URL.revokeObjectURL(nextPreview);
}, [value]);

const isFormValid = formState.title && formState.contents;

return (
<div className={styles["page-container"]}>
<div className={styles["title-and-button"]}>
<p className={styles["form-title"]}>게시글 쓰기</p>
<button
className={`${styles["register-button"]} ${
isFormValid ? styles["register-button-active"] : ""
}`}
disabled={!isFormValid}
type="submit"
>
등록
</button>
</div>
<form>
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

아직 api가 없어서 그런것같지만 onSubmit에 대한 핸들러가 없네요!
그래도 버튼을 클릭하면 무언가 동작되는데 왜그런지는 혹시 아실까요?!

<div className={styles["form-box"]}>
<div className={styles["title"]}>
<label className={styles["label"]}>*제목</label>
<input
className={styles["title-input-box"]}
type="text"
name="title"
onChange={handleInput}
placeholder="제목을 입력해주세요"
required
/>
</div>
<div className={styles["contents"]}>
<label className={styles["label"]}>*내용</label>
<textarea
className={styles["contents-input-box"]}
placeholder="내용을 입력해주세요"
name="contents"
onChange={handleInput}
required
/>
</div>
<div className={styles["image"]}>
<label className={styles["label"]}>이미지</label>
<div className={styles["img-register-container"]}>
<div
className={styles["img-register-box"]}
onClick={handleImageClick}
>
<input
ref={fileInputRef}
className={styles["img-register"]}
type="file"
name="image"
onChange={handleChange}
/>
<div className={styles["img-register-button"]}>
<Image
className={styles["plus-icon"]}
src={plusIcon}
alt="파일추가버튼"
/>
<p className={styles["register-button-text"]}>이미지 등록</p>
</div>
</div>
{preview && (
<div className={styles["preview-image-box"]}>
<Image
className={styles["preview-image"]}
src={preview}
alt="이미지 미리보기"
width="282"
height="282"
/>
<button
className={styles["delete-preview-image"]}
onClick={handleCancelClick}
>
<Image
src={deleteIcon}
alt="미리보기 삭제"
width="8"
height="8"
/>
</button>
</div>
)}
</div>
</div>
</div>
</form>
</div>
);
}
164 changes: 164 additions & 0 deletions pages/addboard/styles.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
@import "@/styles/import.scss";

.page-container {
max-width: 1200px;
margin: 0 auto;
}

.title-and-button {
margin: 24px 0;
display: flex;
justify-content: space-between;
align-items: center;
}

.form-title {
font-size: 20px;
font-weight: 700;
line-height: 23.87px;
text-align: left;
color: $cool-gray-800;
}

.register-button {
width: 74px;
height: 42px;
border-radius: 8px;
padding: 12px 23px;
background-color: $cool-gray-400;
font-size: 16px;
font-weight: 600;
text-align: left;
color: #fff;
:disabled {
cursor: not-allowed;
}
&.register-button-active {
background-color: $brand-blue;
cursor: pointer;
}
}

.form-box {
display: flex;
flex-direction: column;
gap: 24px;
}

.label {
font-size: 18px;
font-weight: 700;
text-align: left;
color: $cool-gray-800;
margin-bottom: 12px;
}

.title-input-box {
cursor: text;
max-width: 1200px;
height: 56px;
border-radius: 12px;
padding: 16px 24px;
background-color: $cool-gray-100;
font-size: 16px;
font-weight: 400;
line-height: 24px;
color: $cool-gray-800;
}
.title-input-box::placeholder {
text-align: left;
color: $cool-gray-400;
}

.title,
.contents,
.image {
display: flex;
flex-direction: column;
}

.contents-input-box {
resize: none;
max-width: 1200px;
height: 282px;
border-radius: 12px;
padding: 16px 24px;
background-color: $cool-gray-100;
border: none;
font-size: 16px;
font-weight: 400;
line-height: 24px;
text-align: left;
color: $cool-gray-800;
}
.contents-input-box::placeholder {
color: $cool-gray-400;
}

.img-register-container {
display: flex;
flex-direction: row;
}

.img-register-box {
cursor: pointer;
position: relative;
width: 282px;
height: 282px;
border-radius: 12px;
background-color: $cool-gray-100;
}

.img-register {
display: none;
object-fit: cover;
width: 100%;
height: 100%;
}

.img-register-button {
position: absolute;
justify-content: center;
align-items: center;
top: 99px;
left: 104px;
display: flex;
flex-direction: column;
gap: 13px;
}

.plus-icon {
width: 48px;
}

.register-button-text {
font-size: 16px;
font-weight: 400;
text-align: left;
color: $cool-gray-400;
}

.preview-image-box {
position: relative;
}

.preview-image {
width: 282px;
height: 282px;
object-fit: cover;
margin-left: 24px;
border-radius: 12px;
}

.delete-preview-image {
position: absolute;
top: 8px;
right: 8px;
background-color: #3962ff;
border-radius: 50%;
width: 20px;
height: 20px;
display: flex;
align-items: center;
justify-content: center;
}
24 changes: 24 additions & 0 deletions pages/boards/[id]/components/Comment/index.tsx
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

실제 데이터를 받기전에 mock으로 만드신 것은 아주 좋은 방법입니다!
그런데 조금 더 실제 데이터를 받는것처럼 만들면 나중에 연결할 때 더 편해요!

예를들어 상수로 const MOCK_DATA = {value: '혹시 사용기간이 어떻게 되실까요?'; time: 1}이런식으로 해두고 사용ㅇ하는곳에서는 MOCK_DATA.value나 MOCK_DTA.time 이런식으로요. 혹은 props를 받게해서 부모에서 내려줄수도있구요!

Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import styles from "./styles.module.scss";
import profileImg from "@/assets/icons/profileImg.svg";
import Image from "next/image";
import kebabIcon from "@/assets/icons/ic_kebab.svg";

export default function Comment() {
return (
<div className={styles["comment-card"]}>
<div className={styles["card-top-line"]}>
<p className={styles["comment-text"]}>
혹시 사용기간이 어떻게 되실까요?
</p>
<Image src={kebabIcon} alt="케밥아이콘" />
</div>
<div className={styles["comment-information-container"]}>
<Image src={profileImg} alt="프로필이미지" />
<div className={styles["nickname-and-time"]}>
<p className={styles["nickname"]}>nickname</p>
<p className={styles["time"]}>1시간전</p>
</div>
</div>
</div>
);
}
Loading
Loading