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

강원대 FE_김정윤 2주차 과제 Step1 #50

Open
wants to merge 16 commits into
base: wjdsbs
Choose a base branch
from
Open
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
21 changes: 21 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,24 @@
## Week 2. 1단계 - 페이지 만들기

[🔗 link](https://edu.nextstep.camp/s/hazAC9xa/ls/QzV1ncxk)

### 기능 목록

- [x] Header, Footer와 같은 공통 컴포넌트 만들기 (모든 페이지에서 Header와 Footer는 보여질 수 있게 적용)

- 각 Url Path별로 페이지 만들기 (결과물과 스타일은 결과 링크 참고)
- [x] 메인 페이지 (/)
- [x] Theme 카테고리 섹션 추가
- [x] heme 카테고리 Item 클릭 시 Theme 페이지(/theme/:themeKey)로 이동
- [x] 실시간 급상승 선물랭킹 추가
- [x] 필터 기능을 hooks를 사용하여 구현 (ex. 전체, 여성이, 남성이, 청소년이 / 받고 싶어한, 많이 선물한, 위시로 받은)
- [x] 상품 목록을 처음에는 6개만 보여지게 하기
- [x] 더보기를 누르는 경우 상품 목록을 더 보여주기 (접기 버튼을 누르면 다시 6개만 보여지도록)
- [x] Theme 페이지(/theme/:themeKey)
- [x] Header 섹션 추가
- [x] 재사용성을 고려하여 Header 섹션을 만들기 (themeKey에 따라 label, title, description, backgroundColor가 달라짐)
- [x] 상품 목록 섹션 추가
- [x] 로그인 페이지(/login)
- [x] ID와 PW를 입력하면 로그인이 되도록 구현(ID와 PW는 아무 값을 입력해도 통과)
- [x] 나의 페이지(/my-account)
- [x] 로그아웃을 할 수있는 버튼을 추가
41 changes: 40 additions & 1 deletion package-lock.json

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

7 changes: 4 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,10 @@
"@emotion/react": "^11.11.3",
"@emotion/styled": "^11.11.0",
"react": "^18.2.0",
"react-dom": "^18.2.0"
"react-dom": "^18.2.0",
"react-router-dom": "^6.24.1"
},
"devDependencies": {
"react-scripts": "5.0.1",
"typescript": "^4.9.5",
"@craco/craco": "^7.1.0",
"@emotion/eslint-plugin": "^11.11.0",
"@storybook/addon-essentials": "^7.6.17",
Expand Down Expand Up @@ -65,8 +64,10 @@
"eslint-plugin-storybook": "^0.8.0",
"prettier": "^3.2.5",
"prop-types": "^15.8.1",
"react-scripts": "5.0.1",
"storybook": "^7.6.17",
"tsconfig-paths-webpack-plugin": "^4.1.0",
"typescript": "^4.9.5",
"webpack": "^5.90.3"
},
"overrides": {
Expand Down
15 changes: 2 additions & 13 deletions src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,7 @@
import styled from '@emotion/styled';
import Routes from './Routes/index';

const App = () => {
const name = 'Josh Perez';

return (
<div>
<Title>Hello, {name}</Title>
</div>
);
return <Routes />;
};

export default App;

const Title = styled.h1`
font-size: 1.5em;
color: gray;
`;
6 changes: 6 additions & 0 deletions src/Routes/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export const ROUTE_PATHS = {
MAIN: '/',
THEME: '/theme/:themeKey',
LOGIN: '/login',
MY_ACCOUNT: '/my-account',
};
45 changes: 45 additions & 0 deletions src/Routes/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { BrowserRouter as Router, Route, Routes, useLocation } from 'react-router-dom';

import Footer from '@/components/Footer';
import Header from '@/components/Header';
import LoginPage from '@/pages/Login';
import MainPage from '@/pages/Main';
import MyAccountPage from '@/pages/MyAccount';
import ThemePage from '@/pages/Theme';

import { ROUTE_PATHS } from './constants';

const RoutesComponent = () => {
return (
<Routes>
<Route path={ROUTE_PATHS.MAIN} element={<MainPage />} />
<Route path={ROUTE_PATHS.THEME} element={<ThemePage />} />
<Route path={ROUTE_PATHS.LOGIN} element={<LoginPage />} />
<Route path={ROUTE_PATHS.MY_ACCOUNT} element={<MyAccountPage />} />
</Routes>
);
};
const Layout = ({ children }: { children: React.ReactNode }) => {
const location = useLocation();
const isLoginPage = location.pathname === ROUTE_PATHS.LOGIN;

return (
<div>
{!isLoginPage && <Header />}
{children}
{!isLoginPage && <Footer />}
</div>
);
};

const AppRoutes = () => {
return (
<Router>
<Layout>
<RoutesComponent />
</Layout>
</Router>
);
};

export default AppRoutes;
30 changes: 30 additions & 0 deletions src/components/Footer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import styled from '@emotion/styled';

const FooterContainer = styled.footer`
padding: 28px 16px 88px;
width: 100%;
max-width: 100vw;
background-color: rgb(250, 250, 252);
display: flex;
justify-content: center;

position: relative;
`;

const FooterInner = styled.div`
display: flex;
justify-content: space-between;
width: 80%;
`;

const Footer = () => {
return (
<FooterContainer>
<FooterInner>
<p>카카오톡 선물하기</p>
</FooterInner>
</FooterContainer>
);
};

export default Footer;
80 changes: 80 additions & 0 deletions src/components/Header.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import styled from '@emotion/styled';
import { useEffect, useState } from 'react';
import { Link } from 'react-router-dom';

import { Container } from '@/components/common/layouts/Container';

const HeaderInner = styled.div`
width: 100%;
max-width: 1024px;
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
`;

const Logo = styled.div`
display: flex;
align-items: center;

img {
height: 54px;
}
`;

const LoginContainer = styled.div`
display: flex;
align-items: center;
`;

const Header = () => {
const [isLoggedIn, setIsLoggedIn] = useState(false);

useEffect(() => {
const authToken = sessionStorage.getItem('authToken');
setIsLoggedIn(!!authToken); // authToken이 존재하면 true, 아니면 false로 설정

// authToken 변경 시 sessionStorage 갱신
window.addEventListener('storage', handleStorageChange);

return () => {
window.removeEventListener('storage', handleStorageChange);
};
}, []);

const handleStorageChange = () => {
const authToken = sessionStorage.getItem('authToken');
setIsLoggedIn(!!authToken);
window.location.reload();
};

return (
<Container>
<HeaderInner>
<Link to="/">
<Logo>
<img
src="https://gift-s.kakaocdn.net/dn/gift/images/m640/pc_gift_logo.png"
alt="선물하기"
/>
</Logo>
</Link>
{isLoggedIn ? (
<Link to="/my-account">
<LoginContainer>
<p>내 계정</p>
</LoginContainer>
</Link>
) : (
<Link to="/login">
<LoginContainer>
<p>로그인</p>
</LoginContainer>
</Link>
)}
</HeaderInner>
</Container>
);
};

export default Header;
43 changes: 43 additions & 0 deletions src/components/MainPage/SelectFriend.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import styled from '@emotion/styled';

import { Image } from '@/components/common/Image/index';
import { Container } from '@/components/common/layouts/Container';

const SelectFriendContainer = styled(Container)`
width: 100%;
display: flex;
justify-content: center;
align-items: center;
height: 150px;
background-color: rgb(250, 250, 252);
`;

const SelectFriendInner = styled.section`
display: flex;
align-items: center;
width: 80%;
padding: 0px 16px;

p {
padding-left: 16px;
font-size: 28px;
}
`;

export const SelectFriend = () => (
<>
<SelectFriendContainer>
<SelectFriendInner>
<Image
src="https://gift-s.kakaocdn.net/dn/gift/images/m640/bg_profile_default.png"
alt="친구 선택 유도 아이콘"
width="70px"
radius={16}
ratio="square"
></Image>
<p>선물 받을 친구를 선택해주세요.</p>
</SelectFriendInner>
</SelectFriendContainer>
</>
);
export default SelectFriend;
Loading