Skip to content

Commit

Permalink
Merge pull request #31 from Duri-Salon/feat(duri)/home-ui(DURI-204)
Browse files Browse the repository at this point in the history
[feat] home UI 페이지 구현
  • Loading branch information
cksquf98 authored Dec 2, 2024
2 parents b972c45 + 3e213fd commit 1f14a5e
Show file tree
Hide file tree
Showing 55 changed files with 1,119 additions and 40 deletions.
4 changes: 3 additions & 1 deletion apps/duri/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
"@duri-fe/utils": "workspace:packages/utils",
"@emotion/react": "^11.13.5",
"@emotion/styled": "^11.13.5",
"@tanstack/react-query": "^5.62.0",
"@tosspayments/tosspayments-sdk": "^2.3.2",
"@types/node": "^22.10.1",
"@typescript-eslint/eslint-plugin": "^8.15.0",
Expand All @@ -28,7 +29,8 @@
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-hook-form": "^7.53.2",
"react-router-dom": "^7.0.1"
"react-router-dom": "^7.0.1",
"swiper": "^11.1.15"
},
"devDependencies": {
"@types/react": "^18",
Expand Down
4 changes: 2 additions & 2 deletions apps/duri/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ import Home from '@pages/Home';
import LoginPage from '@pages/Login';
import StartPage from '@pages/Onboarding/StartPage';
import PaymentPage from '@pages/PaymentPage';
import { FailPage } from '@pages/PaymentPage/Fail';
import { SuccessPage } from '@pages/PaymentPage/Success';
import FailPage from '@pages/PaymentPage/Fail';
import SuccessPage from '@pages/PaymentPage/Success';

function App() {
return (
Expand Down
File renamed without changes.
12 changes: 12 additions & 0 deletions apps/duri/src/assets/types/shop.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
export interface RegularShopProps {
shopIdx: string;
shopName:string;
shopImg: string;
shopScore?: number;
shopReview?: number;
}

export interface RecommendeShopProps extends RegularShopProps{
shopAddress: string;
shopTag: string[];
}
101 changes: 100 additions & 1 deletion apps/duri/src/components/home/home.tsx
Original file line number Diff line number Diff line change
@@ -1 +1,100 @@
//
import { SetStateAction, useState } from 'react';

import { Button, Flex, HeightFitFlex, Text, theme } from '@duri-fe/ui';
import styled from '@emotion/styled';
import {
Swiper as OriginalSwiper,
SwiperSlide as OriginalSwiperSlide,
} from 'swiper/react';

const CarouselHome = () => {
const [swiperIndex, setSwiperIndex] = useState<number>(0); // 슬라이드 인덱스 상태

return (
<HeightFitFlex direction="column" align="flex-start">
<Text
typo="Heading3"
colorCode={theme.palette.Normal900}
margin="33px 0 23px 25px"
>
미용한지 <br />
12일이 지났어요 <br />
매일매일 빗질 잘 해주세요!
</Text>
{/* Swiper를 감싸는 Wrapper */}
<CustomSwiperWrapper>
<CustomSwiper
slidesPerView={1.5}
spaceBetween={8}
centeredSlides={true}
onSlideChange={(e: { realIndex: SetStateAction<number> }) => {
setSwiperIndex(e.realIndex);
console.log(e.realIndex);
}} // 슬라이드 변경 완료 시 인덱스 업데이트
>
{[0, 1, 2].map((i) => (
<CustomSwiperSlide key={i} isActive={swiperIndex === i}>
<Card backgroundColor={theme.palette.White} borderRadius={12}>
카드 {i}
</Card>
</CustomSwiperSlide>
))}
</CustomSwiper>
</CustomSwiperWrapper>
<Flex margin="9px 0 0 0" gap={4}>
{/* Bullets */}
{[0, 1, 2].map((i) => (
<Bullet
key={i}
width={swiperIndex === i ? '18px' : '5px'}
height="4px"
bg={
swiperIndex === i
? theme.palette.Normal700
: theme.palette.Gray100
}
/>
))}
</Flex>
</HeightFitFlex>
);
};

export default CarouselHome;

// Swiper를 감싸는 Wrapper 스타일
const CustomSwiperWrapper = styled(Flex)`
overflow: hidden;
`;

// Swiper를 커스텀한 스타일 컴포넌트
const CustomSwiper = styled(OriginalSwiper)`
width: 100%;
padding: 0 16px;
.swiper-wrapper {
display: flex;
align-items: center;
justify-content: start;
width: fit-content;
height: fit-content;
}
`;

// SwiperSlide를 커스텀한 스타일 컴포넌트
const CustomSwiperSlide = styled(OriginalSwiperSlide)<{ isActive: boolean }>`
transition: transform 0.3s ease;
height: ${({ isActive }) =>
isActive ? '171px !important' : '141px !important'};
width: ${({ isActive }) =>
isActive ? '317px !important' : '316px !important'};
`;

const Card = styled(Flex)`
box-shadow: 0px 2px 8px rgba(0, 0, 0, 0.1);
flex-shrink: 0;
`;

const Bullet = styled(Button)`
padding: 0;
transition: all 0.3s ease;
`;
20 changes: 20 additions & 0 deletions apps/duri/src/components/home/recommendedShop.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { RecommendeShopProps } from '@duri/assets/types/shop';
import { Flex, Text, theme } from '@duri-fe/ui';

import { ShopVertical } from './shop';

const RecommendedShop = ({ shopList }: { shopList: RecommendeShopProps[] }) => {
return (
<Flex direction="column" align="flex-start">
<Text typo="Body3" colorCode={theme.palette.Gray400} margin='31px 0 6px 0'>
피부 질환이 있는 강아지들이 주로 다니는 샵이에요!
</Text>
<Text typo="Heading4">여기 샵은 어때요?</Text>
<Flex justify='flex-start' gap={15} margin='23px 0 0 0'>
<ShopVertical shopList={shopList} />
</Flex>
</Flex>
);
};

export default RecommendedShop;
2 changes: 2 additions & 0 deletions apps/duri/src/components/home/shop/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './shopHorizontal';
export * from './shopVertical';
69 changes: 69 additions & 0 deletions apps/duri/src/components/home/shop/shopHorizontal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import { useNavigate } from 'react-router-dom';

import { RegularShopProps } from '@duri/assets/types/shop';
import {
Button,
Flex,
HeightFitFlex,
Image,
NextArrow,
Star,
Text,
theme,
} from '@duri-fe/ui';
import styled from '@emotion/styled';

export const ShopHorizontal = ({ shopList }: { shopList: RegularShopProps[] }) => {
const navigate = useNavigate();
const handleClickShop = (shopIdx: string) => navigate(`/shop/${shopIdx}`);
return (
<Flex direction="column" gap={15} margin="28px 0 0 0">
{shopList &&
shopList.map((shop: RegularShopProps) => (
<HeightFitFlex key={shop.shopIdx} justify="flex-start" gap={15}>
<Image
width={100}
height={100}
borderRadius={8}
src={shop.shopImg}
onClick={() => handleClickShop(shop.shopIdx)}
/>
<Flex
direction="column"
justify="space-between"
align="flex-start"
gap={20}
>
<Wrapper direction="column" align="flex-start">
{/* onClick함수 추가해야 함!!! */}
<Flex justify="flex-start" gap={2}>
<Text typo="Body2">{shop.shopName}</Text>
<NextArrow width={20} height={20} />
</Flex>
<HeightFitFlex justify="flex-start" gap={7}>
<Star width={14} height={14} />
<Text typo="Label3">
{shop.shopScore}&nbsp;({shop.shopReview})
</Text>
</HeightFitFlex>
</Wrapper>
{/* onClick함수 추가해야 함!!! */}
<Button
height="37px"
bg={theme.palette.Black}
fontColor={theme.palette.White}
borderRadius="8px"
typo="Label3"
>
입찰 넣기
</Button>
</Flex>
</HeightFitFlex>
))}
</Flex>
);
};

const Wrapper = styled(HeightFitFlex)`
cursor: pointer;
`
70 changes: 70 additions & 0 deletions apps/duri/src/components/home/shop/shopVertical.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import { useNavigate } from 'react-router-dom';

import { RecommendeShopProps } from '@duri/assets/types/shop';
import { Button, HeightFitFlex, Image, Text, theme } from '@duri-fe/ui';
import styled from '@emotion/styled';

export const ShopVertical = ({
shopList,
}: {
shopList: RecommendeShopProps[];
}) => {
const navigate = useNavigate();
const handleClickShop = (shopIdx: string) => navigate(`/shop/${shopIdx}`);

return (
<HeightFitFlex justify="flex-start" gap={6}>
{shopList &&
shopList.map((shop: RecommendeShopProps) => (
<Wrapper
key={shop.shopIdx}
direction="column"
align="flex-start"
gap={6}
width={152}
height={184}
padding="3px 3px 13px 3px"
onClick={() => handleClickShop(shop.shopIdx)}
>
<Image
width={146}
height={81}
borderRadius={8}
src={shop.shopImg}
/>
<HeightFitFlex direction='column' align='flex-start'>
<Text typo="Label1" margin='13px 0 11px 6px'>{shop.shopName}</Text>
<Text typo="Body3" colorCode={theme.palette.Gray500} margin='0 0 12px 6px'>
{shop.shopAddress}
</Text>
<HeightFitFlex justify="flex-start" gap={3} margin='0 0 0 6px'>
{shop.shopTag.map((shopTag: string) => (
<Tag
key={shopTag}
typo="Body3"
bg={theme.palette.Gray50}
fontColor={theme.palette.Gray500}
width="fit-content"
height="19px"
borderRadius="2px"
>
<Text typo="Label3">{shopTag}</Text>
</Tag>
))}
</HeightFitFlex>
</HeightFitFlex>
</Wrapper>
))}
</HeightFitFlex>
);
};

const Tag = styled(Button)`
padding: 10px;
`;
const Wrapper = styled(HeightFitFlex)`
border-radius: 12px;
background: var(--bw-white, #fff);
box-shadow: 0px 0px 4px 0px rgba(0, 0, 0, 0.1);
cursor: pointer;
`;
26 changes: 26 additions & 0 deletions apps/duri/src/components/home/speedQuotation.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { RegularShopProps } from '@duri/assets/types/shop';
import { Flex, Text, theme } from '@duri-fe/ui';

import { ShopHorizontal } from './shop';

const SpeedQuotation = ({
name,
shopList,
}: {
name: string;
shopList: RegularShopProps[];
}) => {
return (
<Flex direction="column" align="flex-start" margin="28px 0 0 0">
<Text typo="Body3" colorCode={theme.palette.Gray400} margin='0 0 6px 0'>
{name}가 3회 이상 방문한 샵들이에요.
</Text>
<Text typo="Heading4">단골 샵 빠른 입찰</Text>
<Flex gap={15}>
<ShopHorizontal shopList={shopList} />
</Flex>
</Flex>
);
};

export default SpeedQuotation;
4 changes: 1 addition & 3 deletions apps/duri/src/components/payment/info.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
import { QuotationProps } from '@duri/assets/types/QuotationType';


import { QuotationProps } from '@duri/assets/types/quotation';

interface QuotationInfo {
quotationInfo: QuotationProps;
Expand Down
14 changes: 6 additions & 8 deletions apps/duri/src/components/payment/widget.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { useEffect, useState } from 'react';

import { QuotationProps } from '@duri/assets/types/QuotationType';
import { QuotationProps } from '@duri/assets/types/quotation';
import {
loadTossPayments,
TossPaymentsWidgets,
Expand All @@ -10,16 +10,16 @@ const clientKey = import.meta.env.VITE_CLIENT_KEY;
const customerKey = crypto.randomUUID(); //user Idx값으로 대체하기!

interface QuotationInfo {
quotationInfo: QuotationProps;
quotationInfo: QuotationProps;
}
interface Amount {
currency: string;
value: number;
}

const PaymentWidget = ({quotationInfo} : QuotationInfo) => {
const PaymentWidget = ({ quotationInfo }: QuotationInfo) => {
// const [amount, setAmount] = useState<Amount>({
const [amount, ] = useState<Amount>({
const [amount] = useState<Amount>({
currency: 'KRW',
value: quotationInfo.groomingTotalPrice,
});
Expand Down Expand Up @@ -116,15 +116,13 @@ const PaymentWidget = ({quotationInfo} : QuotationInfo) => {
try {
// ------ '결제하기' 버튼 누르면 결제창 띄우기 ------
// 결제를 요청하기 전에 orderId, amount를 서버에 저장하세요.
// 결제 항목(groomingList, 미용실 정보, 고객 정보) POST 요청 to 서버!!!!!!


// 결제 항목(groomingList, 미용실 정보, 고객 정보) POST 요청 to 서버!!!!!!

// 결제 과정에서 악의적으로 결제 금액이 바뀌는 것을 확인하는 용도입니다.
if (widgets)
await widgets.requestPayment({
orderId: 'gmilrw7NlNvxDwuzV2D4m',
orderName: `${quotationInfo.groomingList[0].menu}${quotationInfo.groomingList.length-1}건`,
orderName: `${quotationInfo.groomingList[0].menu}${quotationInfo.groomingList.length - 1}건`,
successUrl: window.location.origin + '/payment/success',
failUrl: window.location.origin + '/payment/fail',
customerName: '김토스',
Expand Down
Loading

0 comments on commit 1f14a5e

Please sign in to comment.