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

[염정훈] Sprint8 #244

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
5,075 changes: 2,623 additions & 2,452 deletions package-lock.json

Large diffs are not rendered by default.

18 changes: 12 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,21 +1,23 @@
{
"name": "1-weekly-mission",
"name": "typescript-change",
"version": "0.1.0",
"private": true,
"dependencies": {
"@testing-library/jest-dom": "^5.17.0",
"@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^13.5.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-native-dotenv": "^3.4.11",
"react-router-dom": "^6.23.1",
"@types/jest": "^27.5.2",
"@types/react": "^18.3.3",
"@types/react-dom": "^18.3.0",
Comment on lines +9 to +11
Copy link
Collaborator

Choose a reason for hiding this comment

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

@types 관련 의존성들은 devDependancy에 설치를 해주세요.
devDependency에 설치된 의존성 파일들은 최종 빌드시에 포함되지 않아 번들 사이즈가 줄어듭니다.

"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-router-dom": "^6.25.1",
"react-scripts": "5.0.1",
"web-vitals": "^2.1.4"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"build": "tsc",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
Expand All @@ -36,5 +38,9 @@
"last 1 firefox version",
"last 1 safari version"
]
},
"devDependencies": {
"@types/node": "^22.1.0",
"typescript": "^5.5.4"
}
}
12 changes: 10 additions & 2 deletions src/api.js → src/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,18 @@ export async function getProducts({
return body;
}

interface GetComments {
productId: string | undefined;
commentLimit: number;
}

// 댓글 API
export async function getComments({ productId, limit = 3 }) {
export async function getComments({
productId,
commentLimit = 3,
}: GetComments) {
const apiUrl = process.env.REACT_APP_BASE_URL;
const query = `${productId}/comments?limit=${limit}`;
const query = `${productId}/comments?limit=${commentLimit}`;
const response = await fetch(`${apiUrl}.vercel.app/products/${query}`);
const body = await response.json();
return body;
Expand Down
44 changes: 25 additions & 19 deletions src/components/AddItem.js → src/components/AddItem.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,28 @@
import { useEffect, useRef, useState } from "react";
import { ChangeEvent, useEffect, useRef, useState } from "react";

interface FormData {
name: string;
info: string;
price: string;
tag: string;
}

Comment on lines +3 to +8
Copy link
Collaborator

Choose a reason for hiding this comment

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

👍

function AddItem() {
const [formData, setFormDate] = useState({
const [formData, setFormDate] = useState<FormData>({
name: "",
info: "",
price: "",
tag: "",
});
const [addItemBtn, setAddItemBtn] = useState("");
const [btnDisabled, setBtnDisabled] = useState(true);
const [inputFileUrl, setInputFileUrl] = useState(null);
const inputFileImg = useRef(null);
const [addItemBtn, setAddItemBtn] = useState<string>("");
const [btnDisabled, setBtnDisabled] = useState<boolean>(true);
const [inputFileUrl, setInputFileUrl] = useState<string | null>(null);
const inputFileImg = useRef<HTMLInputElement>(null);
const imgAccept = ".jpg, .jpeg, .png";

const inputChange = (e) => {
const inputChange = (
e: ChangeEvent<HTMLInputElement | HTMLTextAreaElement>
) => {
// input value 상태 변경
const { name, value } = e.target;
setFormDate({
Expand All @@ -23,12 +32,13 @@ function AddItem() {
};

const inputFileChange = () => {
const inputFile = inputFileImg.current.files[0];
console.log(inputFile);
if (inputFileImg.current && inputFileImg.current.files) {
const inputFile = inputFileImg.current.files[0];

if (inputFile) {
const fileUrl = URL.createObjectURL(inputFile);
setInputFileUrl(fileUrl);
if (inputFile) {
const fileUrl = URL.createObjectURL(inputFile);
setInputFileUrl(fileUrl);
}
}
};

Expand All @@ -38,16 +48,12 @@ function AddItem() {

const validAddItemVal = () => {
// 유효성 검사
if (
return (
formData.name.trim() !== "" &&
formData.info.trim() !== "" &&
formData.price.trim() !== "" &&
formData.tag.trim() !== ""
) {
return true;
}

return false;
);
};

useEffect(() => {
Expand Down Expand Up @@ -128,7 +134,7 @@ function AddItem() {
type="number"
name="price"
placeholder="판매 가격을 입력해주세요."
value={formData.price === NaN ? null : formData.price}
value={formData.price === "" ? "" : formData.price}
onChange={inputChange}
/>
</div>
Expand Down
54 changes: 35 additions & 19 deletions src/components/AllProduct.js → src/components/AllProduct.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Link } from "react-router-dom";
import { getProducts } from "../api.js";
import { useEffect, useState } from "react";
import { MouseEvent, SetStateAction, useEffect, useState } from "react";

const responsivePageSize = () => {
const winWidth = window.innerWidth;
Expand All @@ -19,18 +19,33 @@ const responsivePageSize = () => {
const RECENT = "recent";
const FAVORITE = "favorite";

interface Product {
id: number;
name: string;
info: string;
price: number;
tag: string;
images: string;
favoriteCount: number;
}
Comment on lines +22 to +30
Copy link
Collaborator

Choose a reason for hiding this comment

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

API 문서에 나와 있는 Product의 데이터 구조를 그대로 작성해주시는것이 좋을 것 같습니다.
아래의 구조를 따라서 Product의 데이터 타입을 완성해주세요.
특히 tag는 string 타입이 아니라 string의 배열타입이네요 ~

{
      "createdAt": "2024-08-05T08:25:27.138Z",
      "favoriteCount": 0,
      "ownerId": 1,
      "images": [
        "https://example.com/..."
      ],
      "tags": [
        "전자제품"
      ],
      "price": 0,
      "description": "string",
      "name": "상품 이름",
      "id": 1
    }


function AllProduct() {
const [products, setProducts] = useState([]);
const [page, setPage] = useState(1);
const [pageSize, setPageSize] = useState(10);
const [order, setOrder] = useState(RECENT);
const [dropArrow, setDropArrow] = useState("");
const [dropDisplay, setDropDisplay] = useState("none");
const [orderTxt, setOrderTxt] = useState("최신순");
const [pagesNum, setPagesNum] = useState([1, 2]);

const handleLoad = async (options) => {
const [products, setProducts] = useState<Product[]>([]);
const [page, setPage] = useState<number>(1);
const [pageSize, setPageSize] = useState<number>(10);
const [order, setOrder] = useState<string>(RECENT);
const [dropArrow, setDropArrow] = useState<string>("");
const [dropDisplay, setDropDisplay] = useState<string>("none");
const [orderTxt, setOrderTxt] = useState<string>("최신순");
const [pagesNum, setPagesNum] = useState<number[]>([1, 2]);
Comment on lines +33 to +40
Copy link
Collaborator

Choose a reason for hiding this comment

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

useState에 상태들의 꼼꼼한 타입 명시 좋습니다 !!


const handleLoad = async (options: {
page: number;
pageSize: number;
order: string;
}) => {
let { list } = await getProducts(options);
console.log(list);
setProducts(list);
};

Expand All @@ -39,23 +54,23 @@ function AllProduct() {
setDropDisplay(dropDisplay === "none" ? "block" : "none");
};

const handleNewsOrder = (e) => {
const menuTxt = e.target.textContent;
const handleNewsOrder = (e: MouseEvent<HTMLElement>) => {
const menuTxt = e.currentTarget.textContent || "";
setOrderTxt(menuTxt);
setDropArrow("");
setDropDisplay("none");
setOrder(RECENT);
};

const handleBestOrder = (e) => {
const menuTxt = e.target.textContent;
const handleBestOrder = (e: MouseEvent<HTMLElement>) => {
const menuTxt = e.currentTarget.textContent || "";
setOrderTxt(menuTxt);
setDropArrow("");
setDropDisplay("none");
setOrder(FAVORITE);
};

const pageNumClick = (page) => {
const pageNumClick = (page: SetStateAction<number>) => {
setPage(page);
};

Expand Down Expand Up @@ -112,16 +127,17 @@ function AllProduct() {
const productPrice = product.price
.toString()
.replace(/\B(?<!\.\d*)(?=(\d{3})+(?!\d))/g, ","); // 숫자 3자리 마다 콤마 추가(정규식 사용)
const imgChk = product.images.join("").includes("jpeg"); // 이미지 경로에 jpeg가 있는지 확인

return (
<li key={product.id}>
<Link to={`/Items/${product.id}`}>
<div className="product-img">
<img
src={
imgChk ? product.images : "/images/card01-small.png"
} // 이미지 경로에 jpeg가 없으면 기본 이미지 있으면 정상적인 이미지
product.images
? product.images
: "/images/card01-small.png"
}
alt={product.name}
/>
</div>
Expand Down
12 changes: 6 additions & 6 deletions src/components/App.js → src/components/App.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import Footer from "./Footer";
import Header from "./Header";
import Footer from "./layout/Footer";
import Header from "./layout/Header";
import Home from "./Home";
import Login from "./Login";
import Signup from "./Signup";
Expand All @@ -19,13 +19,13 @@ function App() {
<main>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/Login" element={<Login />} />
<Route path="/Signup" element={<Signup />} />
<Route path="/Items">
<Route path="/login" element={<Login />} />
<Route path="/signup" element={<Signup />} />
<Route path="/items">
<Route index element={<Items />} />
<Route path=":productId" element={<ProductDetail />} />
</Route>
<Route path="/AddItem" element={<AddItem />} />
<Route path="/addItem" element={<AddItem />} />
<Route path="*" element={<NotFoundPage />} />
</Routes>
</main>
Expand Down
19 changes: 17 additions & 2 deletions src/components/BestProduct.js → src/components/BestProduct.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,29 @@ const responsivePageSize = () => {
}
};

interface Product {
id: number;
name: string;
info: string;
price: number;
tag: string;
images: string;
favoriteCount: number;
}
Comment on lines +19 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.

AllProduct에서 Product 타입을 정의를 했으니까 그 타입을 재사용해야합니다. AllProduct에서 정의한 타입을 가져와서 재사용해주세요.


function BestProduct() {
const [products, setProducts] = useState([]);
const [products, setProducts] = useState<Product[]>([]);
const [page, setPage] = useState(1);
const [pageSize, setPageSize] = useState(4);
const [order, setOrder] = useState("favorite");

const handleLoad = async (options) => {
const handleLoad = async (options: {
page: number;
pageSize: number;
order: string;
}) => {
const { list } = await getProducts(options);
console.log(list);
setProducts(list);
};

Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
4 changes: 2 additions & 2 deletions src/components/Login.js → src/components/Login.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ function Login() {
<div className="input-wrap">
<form>
<div className="input-box">
<label for="user-email">이메일</label>
<label htmlFor="user-email">이메일</label>
<div className="input-position">
<input
id="user-email"
Expand All @@ -26,7 +26,7 @@ function Login() {
</div>
</div>
<div className="input-box">
<label for="user-password">비밀번호</label>
<label htmlFor="user-password">비밀번호</label>
<div className="input-position">
<input
id="user-password"
Expand Down
File renamed without changes.
File renamed without changes.
Loading
Loading