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

Feat: api 연동 및 리팩토링 #46

Merged
merged 11 commits into from
Dec 9, 2024
3 changes: 2 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,6 @@
"javascriptreact",
"typescript",
"typescriptreact"
]
],
"compile-hero.disable-compile-files-on-did-save-code": true
}
2 changes: 1 addition & 1 deletion src/api/axiosInstance.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import axios from 'axios';

const axiosInstance = axios.create({
baseURL: 'http://15.164.5.135:8080', // API URL
baseURL: import.meta.env.VITE_API_URL, // API URL
timeout: 5000, // 요청 제한 시간 (ms)
headers: {
'Content-Type': 'application/json', // JSON 형식 사용
Expand Down
75 changes: 32 additions & 43 deletions src/components/common/Header.tsx
Original file line number Diff line number Diff line change
@@ -1,23 +1,15 @@
import React, { useEffect, useState } from 'react';
import React, { useState } from 'react';
import { Link } from 'react-router-dom';
import styled from 'styled-components';
// import cart from '../../assets/icons/icon.png';
import cart from '../../assets/icons/icon.png';
import logo from '../../assets/icons/goodbuyus-logo.svg';
import menu from '../../assets/icons/menu.svg';
import { useAuth } from '../../context/AuthContext';

const Header = () => {
const [isLoggedIn, setIsLoggedIn] = useState(false);
const [isAdmin, setIsAdmin] = useState(false);
const { isLoggedIn, isAdmin, logout } = useAuth();
const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false);

useEffect(() => {
const token = localStorage.getItem('token');
const userRole = localStorage.getItem('role');


setIsLoggedIn(!!token);
setIsAdmin(userRole === 'ROLE_ADMIN');
}, []);

const toggleMobileMenu = () => {
setIsMobileMenuOpen(!isMobileMenuOpen);
};
Expand Down Expand Up @@ -60,12 +52,14 @@ const Header = () => {
</StyledLink>
</NavItem>
<NavItem>
<StyledLink
to={isAdmin ? '/adminpage' : '/mypage/setting'}
onClick={toggleMobileMenu}
>
{isAdmin ? 'Admin Page' : 'My Page'}
</StyledLink>
{isLoggedIn && (
<StyledLink
to={isAdmin ? '/adminpage' : '/mypage/setting'}
onClick={toggleMobileMenu}
>
{isAdmin ? 'Admin Page' : 'My Page'}
</StyledLink>
)}
{isAdmin && (
<SubMenu>
<SubMenuItem>
Expand All @@ -89,22 +83,16 @@ const Header = () => {
</Login>
) : (
<>
<LogOut
onClick={() => {
localStorage.removeItem('role');
localStorage.removeItem('token');
setIsLoggedIn(false);
}}
>
<LogOut onClick={logout}>
<a>LogOut</a>
</LogOut>
{/* <LogOut>
<LogOut>
<CartIcon>
<StyledLink to="/cart" onClick={toggleMobileMenu}>
<img src={cart} alt="장바구니 아이콘" />
</StyledLink>
</CartIcon>
</LogOut> */}
</LogOut>
</>
)}{' '}
</NavList>
Expand Down Expand Up @@ -291,7 +279,7 @@ const Login = styled.li`
text-decoration: none;
display: block;
text-align: center;
margin-top: 4px;
margin-top: 5px;
font-weight: bold;
}

Expand Down Expand Up @@ -320,11 +308,11 @@ const LogOut = styled.li`
padding: 0px 10px;

a {
font-size: 15px;
color: white;
text-decoration: none;
display: block;
text-align: center;
margin-top: 1px;
font-weight: bold;
}

Expand Down Expand Up @@ -361,16 +349,17 @@ const StyledLink = styled(Link)`
}
`;

// const CartIcon = styled.div`
// img {
// width: 20px;
// height: 20px;
// }

// @media (min-width: 576px) and (max-width: 767px) {
// img {
// width: 25px;
// height: 25px;
// }
// }
// `;
const CartIcon = styled.div`
img {
margin-top: -4px;
width: 22px;
height: 22px;
}

@media (min-width: 576px) and (max-width: 767px) {
img {
width: 25px;
height: 25px;
}
}
`;
25 changes: 10 additions & 15 deletions src/components/pages/HomePage/CategoryProduct.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useEffect, useMemo, useState } from 'react';
import React, { useMemo, useState } from 'react';
import styled from 'styled-components';
import StarRating from '../../common/StarRating';
import DEFAULT_IMG from '../../../assets/icons/default-featured-image.png.jpg';
Expand Down Expand Up @@ -42,24 +42,19 @@ const CategoryProduct: React.FC<CategoryProductsProps> = ({
setSelectedCategory(category);
setIsExpanded(false);
};

const filtered = products.filter((product: Product) =>
product.category.toLowerCase().includes(selectedCategory.toLowerCase())
const filtered = useMemo(
() =>
products?.filter((product) =>
product.category.toLowerCase().includes(selectedCategory.toLowerCase())
) || [],
[selectedCategory, products]
);

const getRandomProducts = (products: Product[]): Product[] => {
const shuffled = [...products].sort(() => 0.5 - Math.random()); // Shuffle the array
const displayedProducts = useMemo(() => {
const shuffled = [...filtered].sort(() => 0.5 - Math.random());
return shuffled.slice(0, 8);
};

const displayedProducts = useMemo(
() => getRandomProducts(filtered),
[filtered]
);
}, [filtered]);

useEffect(() => {
//fetch상품
}, [selectedCategory]);
return (
<Recommend>
<CategoryWrapper>
Expand Down
15 changes: 11 additions & 4 deletions src/components/pages/HomePage/HomePage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,17 @@ import RecommendProduct from './RecommendProduct';
import PopularProduct from './PopularProduct';
import CategoryProduct from './CategoryProduct';
import ScrollToTopButton from '../../common/ScrollToTopButton';
import { categories } from '../../../mocks/products';

import { QueryHandler, useProductsQuery } from '../../../hooks/useGetProduct';
import { Link } from 'react-router-dom';
import { categories } from './model/categories';

const HomePage: React.FC = () => {
const { data: products, isLoading, isError } = useProductsQuery();
const popularProduct = products?.sort(
const availableProduct = products?.filter(
(p) => p.available === true && new Date(p.deadline) > new Date()
);
const popularProduct = availableProduct?.sort(
(a, b) => b.currentStock - a.currentStock
)[0];

Expand All @@ -30,12 +34,15 @@ const HomePage: React.FC = () => {
</ContainerBox>
<ContainerBox>
<Container>
<RecommendProduct products={products} />
<RecommendProduct products={availableProduct} />
</Container>
</ContainerBox>
<ContainerBox>
<Container>
<CategoryProduct categories={categories} products={products} />
<CategoryProduct
categories={categories}
products={availableProduct}
/>
</Container>
<ScrollToTopButton />
</ContainerBox>
Expand Down
1 change: 1 addition & 0 deletions src/components/pages/HomePage/model/categories.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const categories = ['FOOD', 'LIFESTYLE', 'FASHION'];
3 changes: 2 additions & 1 deletion src/components/pages/HomePage/model/productSchema.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
interface Review {
review: string;
content: string;
rating: number;
using: boolean;
}

export interface Product {
Expand Down
61 changes: 32 additions & 29 deletions src/components/pages/Payment/PaymentFailPage.tsx
Original file line number Diff line number Diff line change
@@ -1,48 +1,51 @@
import React from 'react';
import { Link, useParams } from 'react-router-dom';
import styled from 'styled-components';
// import { QueryHandler, useProductQuery } from '../../../hooks/useGetProduct';
import { products } from '../../../mocks/products';
import { QueryHandler, useProductQuery } from '../../../hooks/useGetProduct';

const PaymentFailPage = () => {
const { id } = useParams();
if (!id) {
return <p>상품 번호가 유실되었습니다.</p>;
}
const productId = Number(id);
// const { data: product, isLoading, isError } = useProductQuery(productId);
const product = products.filter((p) => p.id === productId)[0];
console.log(product);
const queryString = window.location.search;
const urlParams = new URLSearchParams(queryString);
const amount = urlParams.get('amount');
const { data: product, isLoading, isError } = useProductQuery(productId);

if (!product) {
return <p>해당 상품을 찾을 수 없습니다.</p>;
}

return (
<>
{/* <QueryHandler isLoading={isLoading} isError={isError}> */}
<Container>
<FailureSection>
<Title>결제 실패</Title>
<Subtitle>죄송합니다. 결제에 실패하였습니다.</Subtitle>

<OrderSummary>
<SummaryRow>
<Label>상품명</Label>
<Value>{product?.name}</Value>
</SummaryRow>
<SummaryRow>
<Label>결제 금액</Label>
<Value>{product?.discountprice} 원</Value>
</SummaryRow>
</OrderSummary>
</FailureSection>

<ButtonGroup>
<RetryButton to={`/products/${productId}`}>다시 시도하기</RetryButton>
<BackButton to="/">메인으로 돌아가기</BackButton>
</ButtonGroup>
</Container>
{/* </QueryHandler> */}
<QueryHandler isLoading={isLoading} isError={isError}>
<Container>
<FailureSection>
<Title>결제 실패</Title>
<Subtitle>죄송합니다. 결제에 실패하였습니다.</Subtitle>

<OrderSummary>
<SummaryRow>
<Label>상품명</Label>
<Value>{product?.name}</Value>
</SummaryRow>
<SummaryRow>
<Label>결제 금액</Label>
<Value>{amount} 원</Value>
</SummaryRow>
</OrderSummary>
</FailureSection>

<ButtonGroup>
<RetryButton to={`/products/${productId}`}>
다시 시도하기
</RetryButton>
<BackButton to="/">메인으로 돌아가기</BackButton>
</ButtonGroup>
</Container>
</QueryHandler>
</>
);
};
Expand Down
20 changes: 8 additions & 12 deletions src/components/pages/Payment/PaymentForm.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
import React, { useMemo, useState } from 'react';
import { Link, useLocation, useParams } from 'react-router-dom';
import { Link, useParams } from 'react-router-dom';
import styled from 'styled-components';
import { handlePayment } from './api/paymentApi';
import { QueryHandler, useProductQuery } from '../../../hooks/useGetProduct';
import { useQuantity } from '../../../context/QuantityContext';

const PaymentForm = () => {
// URL 쿼리 스트링을 통한 데이터 수신
const location = useLocation();
const productData = location.state;

const { quantity } = useQuantity();
const { id } = useParams();
const productId = useMemo(() => {
if (!id || isNaN(Number(id))) {
Expand Down Expand Up @@ -58,8 +56,8 @@ const PaymentForm = () => {
const payload = {
productName: product.name,
url: product.url,
price: product.discountprice * productData.amount,
quantity: productData.amount,
price: product.discountprice * quantity,
quantity: quantity,
payMethod: payment,
deliveryRequestDTO: {
name: userName,
Expand All @@ -79,12 +77,12 @@ const PaymentForm = () => {
}
try {
const paymentResult = await handlePayment(productId, payload);

window.location.href = paymentResult;
} catch (e) {
alert(`결제에 실패하였습니다 ${e}`);
}
};

return (
<>
<QueryHandler isLoading={isLoading} isError={isError}>
Expand All @@ -97,13 +95,11 @@ const PaymentForm = () => {
<Price>{product.discountprice}원</Price>
</FlexRow>
<FlexRow>
<Quantity>{productData.amount}</Quantity>
<Quantity>수량 : {quantity}</Quantity>
</FlexRow>
<TotalRow>
<span>합계:</span>
<TotalPrice>
{product.discountprice * productData.amount}원
</TotalPrice>
<TotalPrice>{product.discountprice * quantity}원</TotalPrice>
</TotalRow>
</ContentBox>
</Section>
Expand Down
11 changes: 10 additions & 1 deletion src/components/pages/Payment/PaymentSuccessPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@ const PaymentSuccessPage = () => {
return <p>상품 번호가 유실되었습니다.</p>;
}
const productId = Number(id);
const queryString = window.location.search;
const urlParams = new URLSearchParams(queryString);
const orderId = urlParams.get('orderId');
const amount = urlParams.get('amount');

const { data: product, isLoading, isError } = useProductQuery(productId);

if (!product) {
Expand All @@ -29,7 +34,11 @@ const PaymentSuccessPage = () => {
</SummaryRow>
<SummaryRow>
<Label>결제 금액</Label>
<Value>{product?.discountprice.toLocaleString()}</Value>
<Value>{amount}원</Value>
</SummaryRow>
<SummaryRow>
<Label>주문 번호</Label>
<Value>{orderId}</Value>
</SummaryRow>
</OrderSummary>
</SuccessSection>
Expand Down
Loading