Skip to content
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
8 changes: 4 additions & 4 deletions src/App.jsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import React from "react";
import { BrowserRouter as Router, Route, Routes } from "react-router-dom";
import ItemsPage from "./pages/ItemsPage.jsx";
import AddItem from "./pages/AddItem.jsx";
import Nav from "./components/Nav.jsx";
import ItemDetail from "./pages/ItemDetail.jsx";
import ItemsPage from "./pages/ItemsPage.tsx";
import AddItem from "./pages/AddItem.tsx";
import Nav from "./components/Nav.tsx";
import ItemDetail from "./pages/ItemDetail.tsx";
import "./style.css";

function App() {
Expand Down
67 changes: 0 additions & 67 deletions src/components/AddImgForm.jsx

This file was deleted.

File renamed without changes.
80 changes: 80 additions & 0 deletions src/components/AddImgForm.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import React, { useState, useRef, ChangeEvent } from "react";
import PlusIcon from "../asset/icon/ic_plus.png";
import CloseIcon from "../asset/icon/ic_X.png";
import styles from "./AddImgForm.module.css";

interface AddImgFormProps {
label: string;
}

function AddImgForm({ label }: AddImgFormProps) {
const [imagePreviewUrl, setImagePreviewUrl] = useState<string>("");
const fileInputRef = useRef<HTMLInputElement>(null);
Comment on lines +11 to +12
Copy link
Collaborator

Choose a reason for hiding this comment

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

잘 만드신것같아요 AddImgForm 컴포넌트

조금만 더 나아가서... 아마 이미지는 서버에다가 업로드를 하고, 응답값으로 업로드한 이미지의 url을 받을꺼에요

https://panda-market-api.vercel.app/docs/#/Image/ImageUpload

그럼 여기서 이 컴포넌트를 사용했을때 서버에 업로드하고 url을 위로 올리는 작업이 필요하게 될거에요~

그래서

const imageUrl = URL.createObjectURL(file);
      setImagePreviewUrl(imageUrl);

위 코드처럼 이미지를 미리보기로 만든건 좋은데, 좀더 발전하면 서버에 이미지를 업로드하고 url을 받아와서 해당 url로 이미지를 보여주는게 좀더 좋을것같아요ㅎㅎㅎ!


function handleImageChange(e: ChangeEvent<HTMLInputElement>) {
const file = e.target.files?.[0];
if (file) {
const imageUrl = URL.createObjectURL(file);
setImagePreviewUrl(imageUrl);
}
}

function handleClick() {
fileInputRef.current?.click();
}

function handleRemoveImage() {
setImagePreviewUrl("");
if (fileInputRef.current) {
fileInputRef.current.value = "";
}
}

return (
<div>
<label>{label}</label>
<div className={styles["img-upload-container"]}>
<div
onClick={handleClick}
className={styles["img-upload-btn"]}
style={{ cursor: "pointer" }}
>
<img
src={PlusIcon}
alt="업로드 아이콘"
className={styles["plus-icon"]}
/>
<p className={styles["img-upload-text"]}>이미지 등록</p>
</div>

{imagePreviewUrl && (
<div className={styles["img-preview-container"]}>
<img
src={imagePreviewUrl}
alt="미리보기"
className={styles["img-preview"]}
/>
<img
src={CloseIcon}
alt="삭제 버튼"
onClick={handleRemoveImage}
className={styles["img-remove-button"]}
style={{ cursor: "pointer" }}
/>
</div>
)}
</div>

<input
ref={fileInputRef}
id="img-upload"
type="file"
accept="image/*"
onChange={handleImageChange}
style={{ display: "none" }}
/>
</div>
);
}

export default AddImgForm;
File renamed without changes.
28 changes: 22 additions & 6 deletions src/components/AddItemForm.jsx → src/components/AddItemForm.tsx
Original file line number Diff line number Diff line change
@@ -1,27 +1,42 @@
import React from "react";
import "./AddItemForm.css";
import styles from "./AddItemForm.module.css";

interface AddItemFormProps {
label: string;
type?: string;
placeholder: string;
id: string;
value: string;
onChange: (
event: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>
) => void;
isTextArea?: boolean;
onKeyDown?: (
event: React.KeyboardEvent<HTMLInputElement | HTMLTextAreaElement>
) => void;
}
Comment on lines +4 to +17
Copy link
Collaborator

Choose a reason for hiding this comment

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

오 공통 컴포넌트를 설계해보신것같네요ㅎㅎ

저라면 기존에 사용하고 있는 속성들을 그대로 가져와서 정의했을것같아요...!

interface AddItemFormProps
  extends React.TextareaHTMLAttributes<HTMLTextAreaElement | HTMLInputElement> {
  label: string;
}

이런식으로 하면, 깜빡하고 누락한 속성도 처리할 수 있거든요ㅎㅎ

이건 조금 어려우니 멘토링떄 같이 보면 좋을것같아요~


function AddItemForm({
label,
type,
type = "text",
placeholder,
id,
value,
onChange,
isTextArea,
isTextArea = false,
onKeyDown,
}) {
}: AddItemFormProps) {
return (
<div className="form-field">
<div className={styles["form-field"]}>
<label htmlFor={id}>{label}</label>
{isTextArea ? (
<textarea
id={id}
type={type}
placeholder={placeholder}
value={value}
onChange={onChange}
onKeyDown={onKeyDown}
className={styles["textarea"]}
/>
) : (
<input
Expand All @@ -31,6 +46,7 @@ function AddItemForm({
value={value}
onChange={onChange}
onKeyDown={onKeyDown}
className={styles["input"]}
/>
)}
</div>
Expand Down
File renamed without changes.
30 changes: 19 additions & 11 deletions src/components/AddTagForm.jsx → src/components/AddTagForm.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,20 @@
import React, { useState } from "react";
import AddItemForm from "./AddItemForm";
import React, { useState, KeyboardEvent } from "react";
import AddItemForm from "./AddItemForm.tsx";
import CloseIcon from "../asset/icon/ic_X.png";
import "./AddTagForm.css";
import styles from "./AddTagForm.module.css";

function AddTagForm({ tags, onAddTag, onRemoveTag }) {
const [input, setInput] = useState("");
interface AddTagFormProps {
tags: string[];
onAddTag: (tag: string) => void;
onRemoveTag: (tag: string) => void;
}
Comment on lines +6 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.

필요한거만 잘 만들어주신것같네요ㅎㅎ!

조금더 개선한다면 중복된 tag는 걸러주는 로직을 넣으면 좀더 좋겠네요ㅎㅎ!

왜냐하면 tag를 key로 사용하는데, 중복된 값이 들어오면 문제가 될꺼거든요ㅠ


function AddTagForm({ tags, onAddTag, onRemoveTag }: AddTagFormProps) {
const [input, setInput] = useState<string>("");

const onPressEnter = (event) => {
function onPressEnter(
event: KeyboardEvent<HTMLInputElement | HTMLTextAreaElement>
): void {
if (event.nativeEvent.isComposing) return;

const inputString = input.trim();
Expand All @@ -15,7 +23,7 @@ function AddTagForm({ tags, onAddTag, onRemoveTag }) {
onAddTag(inputString);
setInput("");
}
};
}

return (
<div>
Expand All @@ -28,16 +36,16 @@ function AddTagForm({ tags, onAddTag, onRemoveTag }) {
placeholder="태그를 입력해주세요"
/>

<div className="tag-buttons-section">
<div className={styles["tag-buttons-section"]}>
{tags.map((tag) => (
<div key={`tag-${tag}`} className="tag">
<span className="tag-text">#{tag}</span>
<div key={`tag-${tag}`} className={styles["tag"]}>
<span className={styles["tag-text"]}>#{tag}</span>
<img
src={CloseIcon}
alt="태그 삭제 버튼"
onClick={() => onRemoveTag(tag)}
aria-label={`${tag} 태그 삭제`}
className="tag-delete-button"
className={styles["tag-delete-button"]}
/>
</div>
))}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,39 +1,43 @@
import React, { useState } from "react";
import "./detailInquiry.css";
import React, { useState, ChangeEvent } from "react";
import styles from "./detailInquiry.module.css";

function Inquiry() {
const [inputValue, setInputValue] = useState("");
interface InquiryProps {}

const handleChange = (event) => {
function Inquiry(props: InquiryProps) {
const [inputValue, setInputValue] = useState<string>("");

function handleChange(event: ChangeEvent<HTMLTextAreaElement>): void {
setInputValue(event.target.value);
};
}

const handleSubmit = () => {
function handleSubmit(): void {
if (inputValue.trim()) {
alert(`문의 내용: ${inputValue}`);
setInputValue("");
}
};
}

const isButtonEnabled = inputValue.trim().length > 0;
Copy link
Collaborator

Choose a reason for hiding this comment

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

이런 값은 물론 이렇게 해도 되지만 좀더 성능을 끌어올리고 싶다면 useMemo를 활용하는것도 좋아요ㅎㅎ!

const isButtonEnabled = useMemo(() => {
    return inputValue.trim().length > 0;
  }, [inputValue]);


return (
<div className="form-container">
<label htmlFor="inquiry" className="form-label">
<div className={styles["form-container"]}>
<label htmlFor="inquiry" className={styles["form-label"]}>
문의하기
</label>
<textarea
className="form-textarea"
className={styles["form-textarea"]}
id="inquiry"
placeholder="개인정보를 공유 및 요청하거나, 명예 훼손, 무단 광고, 불법 정보 유포시 모니터링 후 삭제될 수 있으며, 이에 대한 민형사상 책임은 게시자에게 있습니다."
value={inputValue}
onChange={handleChange}
/>
<div className="button-container">
<div className={styles["button-container"]}>
<button
className={`form-button ${isButtonEnabled ? "enabled" : "disabled"}`}
className={`${styles["form-button"]} ${
isButtonEnabled ? styles["enabled"] : styles["disabled"]
}`}
onClick={handleSubmit}
disabled={!inputValue.trim()}
disabled={!isButtonEnabled}
>
등록
</button>
Expand Down
29 changes: 0 additions & 29 deletions src/components/ItemCard.jsx

This file was deleted.

Loading
Loading