Skip to content

Commit a107616

Browse files
Merge pull request #227 from 626-ju/React-김성주-sprint8
[김성주] sprint8
2 parents e2ebdd7 + d91ece5 commit a107616

29 files changed

+438
-216
lines changed

package-lock.json

Lines changed: 68 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,16 +12,20 @@
1212
"format": "prettier --write \"src/**/*.{js,jsx,css,json}\""
1313
},
1414
"dependencies": {
15+
"@hookform/resolvers": "^5.1.1",
16+
"clsx": "^2.1.1",
1517
"react": "^19.1.0",
1618
"react-dom": "^19.1.0",
1719
"react-hook-form": "^7.59.0",
1820
"react-router-dom": "^7.6.0",
1921
"sass": "^1.88.0",
2022
"styled-components": "^6.1.18",
23+
"zod": "^4.0.5",
2124
"zustand": "^5.0.5"
2225
},
2326
"devDependencies": {
2427
"@eslint/js": "^9.25.0",
28+
"@types/node": "^24.0.10",
2529
"@types/react": "^19.1.2",
2630
"@types/react-dom": "^19.1.2",
2731
"@vitejs/plugin-react": "^4.4.1",
@@ -35,6 +39,7 @@
3539
"eslint-plugin-react-refresh": "^0.4.19",
3640
"globals": "^16.0.0",
3741
"prettier": "^3.5.3",
42+
"typescript": "^5.8.3",
3843
"vite": "^6.3.5"
3944
}
4045
}

src/App.jsx renamed to src/App.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
import { BrowserRouter, Routes, Route } from 'react-router-dom';
22
import Header from './components/Header/Header';
3-
import AddItem from './pages/AddItem/AddItem';
3+
import AddItem from './pages/AddItem/AddItem.jsx';
44
import Login from './pages/Auth/Login';
55
import SignUp from './pages/Auth/SignUp';
66
import Home from './pages/Home/Home';
7-
import Items from './pages/Items/Items';
8-
import ProductDetail from './pages/ProductDetail/ProductDetail';
7+
import Items from './pages/Items/Items.jsx';
8+
import ProductDetail from './pages/ProductDetail/ProductDetail.jsx';
99
import './styles/reset.css';
1010
import './styles/global.css';
1111
import './App.css';

src/components/Header/Header.jsx renamed to src/components/Header/Header.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import HeaderAuth from './HeaderAuth';
77
import Navigations from './Navigations';
88

99
function Header() {
10-
const [isLoggedIn] = useState(sessionStorage.getItem('loggedIn'));
10+
const [isLoggedIn] = useState(!!sessionStorage.getItem('loggedIn'));
1111

1212
return (
1313
<>

src/components/Header/HeaderAuth.jsx renamed to src/components/Header/HeaderAuth.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,11 @@ import userImg from '@assets/icon/ic_user.png';
22
import styles from '@styles/Header.module.css';
33
import { Link } from 'react-router-dom';
44

5-
function HeaderAuth({ isLoggedIn }) {
5+
interface Props {
6+
isLoggedIn: boolean;
7+
}
8+
9+
function HeaderAuth({ isLoggedIn }: Props) {
610
return (
711
<>
812
{isLoggedIn ? (

src/components/Header/Navigations.jsx renamed to src/components/Header/Navigations.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import styles from '@styles/Header.module.css';
22
import { Link, NavLink, useLocation } from 'react-router-dom';
3+
import clsx from 'clsx';
34

45
function Navigations() {
56
const location = useLocation();
@@ -9,10 +10,10 @@ function Navigations() {
910

1011
return (
1112
<div className={styles.navCategory}>
12-
<Link>자유게시판</Link>
13+
<Link to={'/'}>자유게시판</Link>
1314
<NavLink
1415
to="/items"
15-
className={() => (isMarketLocation ? `${styles.isActive}` : null)}
16+
className={clsx({ [styles.isActive]: isMarketLocation })}
1617
>
1718
중고마켓
1819
</NavLink>

src/components/KebabMenu.jsx

Lines changed: 9 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
import { useEffect, useRef, useState } from 'react';
1+
import { useRef, useState } from 'react';
22
import kebabIcon from '@assets/icon/ic_kebab.png';
3+
import useOutsideClick from '../hooks/useOutsideClick';
34
import styles from '../styles/KebabMenu.module.css';
45

56
function makeHtmlAttr(selector) {
@@ -24,28 +25,22 @@ function KebabMenu({ dropdownList, onSelect = () => {} }) {
2425
setIsOpen(false);
2526
}
2627

27-
useEffect(() => {
28-
function closeDropDown(e) {
29-
if (!kebabRef.current.contains(e.target)) {
30-
setIsOpen(false);
31-
}
32-
}
33-
34-
window.addEventListener('click', closeDropDown);
28+
function onCloseDropdown() {
29+
setIsOpen(false);
30+
}
3531

36-
return () => window.removeEventListener('click', closeDropDown);
37-
}, []);
32+
useOutsideClick(kebabRef, onCloseDropdown);
3833

3934
return (
40-
<div className={styles.kebab}>
41-
<button ref={kebabRef} onClick={handleToggleDropDown}>
35+
<div className={styles.kebab} ref={kebabRef}>
36+
<button onClick={handleToggleDropDown}>
4237
<img src={kebabIcon} alt="케밥 아이콘" />
4338
</button>
4439
{isOpen && (
4540
<ul role="listbox">
4641
{dropdownList?.map((selector) => (
4742
<li
48-
key={`${selector}`}
43+
key={selector}
4944
{...makeHtmlAttr(selector)}
5045
onClick={() => handleClick(selector)}
5146
>
File renamed without changes.

src/global.d.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
declare module '*.png';
2+
3+
declare module '*.module.css' {
4+
const classes: { [key: string]: string };
5+
export default classes;
6+
}
7+
8+
declare module '*.css' {
9+
const classes: { [key: string]: string };
10+
export default classes;
11+
}
12+
13+
declare module '*.jsx' {
14+
import * as React from 'react';
15+
const component: React.FC<any>;
16+
export default component;
17+
}

src/hooks/useOutsideClick.js

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import { useEffect } from 'react';
2+
3+
function useOutsideClick(ref, onCloseDropdown) {
4+
useEffect(() => {
5+
function closeDropdownHandler(e) {
6+
if (ref.current && !ref.current.contains(e.target)) {
7+
onCloseDropdown();
8+
}
9+
}
10+
11+
window.addEventListener('click', closeDropdownHandler);
12+
13+
return () => window.removeEventListener('click', closeDropdownHandler);
14+
}, [ref, onCloseDropdown]);
15+
}
16+
17+
export default useOutsideClick;

0 commit comments

Comments
 (0)