Skip to content

Commit

Permalink
feat: Apply the product API
Browse files Browse the repository at this point in the history
  • Loading branch information
dani784601 committed Oct 31, 2024
1 parent 94fdaee commit c853d33
Show file tree
Hide file tree
Showing 10 changed files with 140 additions and 37 deletions.
5 changes: 0 additions & 5 deletions src/App.tsx

This file was deleted.

28 changes: 28 additions & 0 deletions src/apis/fetch.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
export const BASE_URL = new URL('https://panda-market-api.vercel.app/');

type FetchReqPrams = {
method: 'GET' | 'POST' | 'PATCH' | 'DELETE';
path: string;
payload?: Record<string, unknown>;
}

export const fetchReq = async (params: FetchReqPrams) => {
const { method, path, payload } = params;
const options = {
method,
headers: {
'Content-Type': 'application/json',
'cors': 'no-cors',
},
body: payload ? JSON.stringify(payload) : null,
};
try {
const response = await fetch(path, options);
if (!response.ok) {
throw new Error(`HTTP error status ${response?.status}`);
}
return response.json();
} catch (error) {
console.error(error)
}
};
21 changes: 18 additions & 3 deletions src/apis/products.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,18 @@
// @ts-nocheck
const base_url = 'https://panda-market-api.vercel.app/';
const api_url = `${base_url}products`;
import { BASE_URL, fetchReq } from './fetch.js';

type OrderType = 'favorite' | 'recent'
type QueryObjType = {
page?: number;
pageSize?: number;
orderBy?: OrderType;
keyword?: string;
}


export const getProductList = (queryObj: QueryObjType) => {
const queryStr = new URLSearchParams(queryObj as Record<string, string>);
return fetchReq({
method: 'GET',
path: `${BASE_URL}products?${queryStr}`,
});
};
9 changes: 7 additions & 2 deletions src/components/Footer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -67,14 +67,19 @@ function Footer() {
gapY="5"
>
<Flex css={{ '@container style(--is-sm: false)': { order: 3 } }}>
<Text trim="both" style={{ color: 'var(--gray-7)' }}>
©codeit - 2024
<Text
trim="both"
weight="light"
style={{ color: 'var(--gray-7)' }}
>
©codeit - {new Date().getFullYear() ?? '2024'}
</Text>
</Flex>

<Flex gap="6" justify={{ initial: 'start', sm: 'center' }}>
{footerLinks.map(({ label, href }) => (
<Link
weight="light"
key={label}
href={href}
underline="none"
Expand Down
32 changes: 22 additions & 10 deletions src/components/ItemCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,20 @@ import {
AspectRatio,
Grid,
Badge,
Flex,
IconButton,
} from '@radix-ui/themes';
import { css } from '@emotion/react';
import type { ItemCardProps } from '../../types/product';

const numberTextStyle = css({
fontVariantNumeric: 'tabular-nums',
});

function ItemCard() {
function ItemCard(itemCardProps: Readonly<ItemCardProps>) {
const { favoriteCount, images, name, price } = itemCardProps;
return (
<Box maxWidth="282px">
<Grid>
<Card variant="ghost">
<Grid gap="4">
<AspectRatio ratio={1 / 1}>
Expand All @@ -28,25 +32,33 @@ function ItemCard() {
borderRadius: 'var(--radius-5)',
objectFit: 'cover',
}}
src={defaultImg}
alt=""
src={images[0] || defaultImg}
alt={name}
/>
</AspectRatio>
<Grid style={{ rowGap: '0.5rem' }}>
<Text as="p" size="2" truncate wrap="nowrap">
{'제목'}
{name}
</Text>
<Strong css={numberTextStyle}>{'500 원'}</Strong>
<Badge variant="outline" color="gray" style={{ boxShadow: 'none' }}>
<HeartIcon />
<Strong css={numberTextStyle}>
{`${price.toLocaleString()} 원`}
</Strong>
<Badge
color="gray"
variant="outline"
style={{ boxShadow: 'none', paddingLeft: 0 }}
>
<IconButton color="gray" variant="ghost">
<HeartIcon />
</IconButton>
<Text css={numberTextStyle} trim="both" weight="regular">
?
{favoriteCount}
</Text>
</Badge>
</Grid>
</Grid>
</Card>
</Box>
</Grid>
);
}

Expand Down
1 change: 1 addition & 0 deletions src/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@
}

.radix-themes {
--space-10: 100px;
--cursor-button: pointer;
--default-font-family: 'Pretendard', sans-serif;
--font-weight-light: 400;
Expand Down
10 changes: 10 additions & 0 deletions src/main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,20 @@ import { createBrowserRouter, RouterProvider } from 'react-router-dom';
import Root from './routes/root.tsx';
import ErrorPage from './error-page';
import './index.css';
import { getProductList } from './apis/products.ts';

const router = createBrowserRouter([
{
path: '/',
loader: async () => {
const bestItems = await getProductList({
page: 1,
pageSize: 4,
orderBy: 'favorite',
});
const sellingItems = await getProductList({ page: 1, pageSize: 10 });
return { bestItems, sellingItems };
},
element: <Root />,
errorElement: <ErrorPage />,
},
Expand Down
39 changes: 23 additions & 16 deletions src/routes/root.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,32 +10,40 @@ import {
import Header from '../components/Header';
import Footer from '../components/Footer';
import Pagination from '../components/Pagination';
import ItemCard from '../components/ItemCard';
import SearchInput from '../components/SearchInput';
import SortSelection from '../components/SortSelection';
import { useLoaderData } from 'react-router-dom';
import type { ItemCardProps } from '../../types/product';
import ItemCard from '../components/ItemCard';

type ItemListType = {
list: ItemCardProps[];
totalCount: number;
};

export default function Root() {
const { bestItems, sellingItems } = useLoaderData();
return (
<main>
<Header />
<Container>
<Section pt="6">
<Container px={{ initial: '4' }}>
<Section pt="6" pb="0">
<Heading size="5" mb="4">
베스트 상품
</Heading>
<Grid
columns={{ initial: '1', sm: '2', md: '4' }}
gap="3"
gap="5"
width="auto"
rows="repeat(1, 1fr)"
overflow={'hidden'}
rows="1"
>
{Array.from({ length: 4 }).map((_, i) => (
<ItemCard key={i} />
{bestItems.list.map((itemInfo: ItemCardProps) => (
<ItemCard key={itemInfo.id} {...itemInfo} />
))}
</Grid>
</Section>
<Section pt="7">

<Section pt="7" style={{ paddingBottom: 'var(--space-10)' }}>
<Flex mb="5" align="center" justify="between">
<Heading size="5" trim="both">
판매 중인 상품
Expand All @@ -50,16 +58,15 @@ export default function Root() {
</Flex>
<Grid
columns={{ initial: '2', sm: '3', md: '5' }}
gap="3"
width="auto"
rows="repeat(1, 1fr)"
overflow={'hidden'}
gapX="5"
gapY="7"
rows="2"
>
{Array.from({ length: 5 }).map((_, i) => (
<ItemCard key={i} />
{sellingItems.list.map((itemInfo: ItemCardProps) => (
<ItemCard key={itemInfo.id} {...itemInfo} />
))}
</Grid>
<Section>
<Section py="7">
<Pagination />
</Section>
</Section>
Expand Down
20 changes: 19 additions & 1 deletion tsconfig.app.tsbuildinfo
Original file line number Diff line number Diff line change
@@ -1 +1,19 @@
{"root":["./src/app.tsx","./src/error-page.tsx","./src/main.tsx","./src/vite-env.d.ts","./src/apis/products.ts","./src/components/defaultbtn.tsx","./src/components/dropdown.tsx","./src/components/footer.tsx","./src/components/header.tsx","./src/components/itemcard.tsx","./src/components/logo.tsx","./src/components/pagination.tsx","./src/components/serach.tsx","./src/routes/items.tsx","./src/routes/root.tsx"],"version":"5.6.3"}
{
"root": [
"./src/app.tsx",
"./src/error-page.tsx",
"./src/main.tsx",
"./src/vite-env.d.ts",
"./src/apis/products.ts",
"./src/components/footer.tsx",
"./src/components/header.tsx",
"./src/components/itemcard.tsx",
"./src/components/logo.tsx",
"./src/components/pagination.tsx",
"./src/components/searchinput.tsx",
"./src/components/sortselection.tsx",
"./src/routes/items.tsx",
"./src/routes/root.tsx"
],
"version": "5.6.3"
}
12 changes: 12 additions & 0 deletions types/product.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
export interface ItemCardProps {
createdAt: string;
description: string;
favoriteCount: number;
id: number;
images: string[];
name: string;
ownerId: number;
price: number;
tags: string[];
updatedAt: string;
}

0 comments on commit c853d33

Please sign in to comment.