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 연동 #124

Merged
merged 14 commits into from
Dec 5, 2021
Merged
Show file tree
Hide file tree
Changes from 13 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
6 changes: 4 additions & 2 deletions src/hooks/usePost.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import { GENERAL_ERROR, NETWORK_ERROR } from 'constants/errors';

import { useCommonSnackbar } from 'components/CommonSnackbar/useCommonSnackbar';
import { ProductId } from 'pages/CreateProduct/types';
import { useState } from 'react';
import { useMutation, UseMutationResult } from 'react-query';
import { ObjectResponse } from 'utils/requestType';
import { postRequest } from 'utils/requests';

interface Post {
Expand All @@ -13,12 +15,12 @@ interface Post {
onError?: () => void;
}

export const usePost = ({
export const usePost = <T extends ProductId>({
pathname,
errorMessage = GENERAL_ERROR,
onSuccess,
onError,
}: Post): UseMutationResult<void, unknown> => {
}: Post): UseMutationResult<ObjectResponse<T> | void, unknown> => {
const [postErrorMessage, setPostErrorMessage] = useState<string>();

useCommonSnackbar({
Expand Down
5 changes: 2 additions & 3 deletions src/pages/CreateDesign/Detail/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -77,9 +77,8 @@ const Detail = (): React.ReactElement => {
bottomWidth,
armholeDepth,
} = size;
const [localCoverImage, setLocalCoverImage] = useRecoilState(
localCoverImageAtom,
);
const [localCoverImage, setLocalCoverImage] =
useRecoilState(localCoverImageAtom);

const { SWEATER } = DESIGN;
const { TEXT, IMAGE, VIDEO } = PATTERN;
Expand Down
5 changes: 3 additions & 2 deletions src/pages/CreateDesign/Pattern/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -133,8 +133,9 @@ const Pattern = (): React.ReactElement => {
toolbarPlugin,
];

const currentPatternLength = editorState.getCurrentContent().getPlainText('')
.length;
const currentPatternLength = editorState
.getCurrentContent()
.getPlainText('').length;

const handleBeforeInput = (
_chars: string,
Expand Down
14 changes: 1 addition & 13 deletions src/pages/CreateDesign/components/FontSize/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,5 @@ export type FontSizeProps = {
};

export const fontSizeOptions = [
8,
10,
12,
14,
16,
18,
24,
30,
36,
48,
60,
72,
96,
8, 10, 12, 14, 16, 18, 24, 30, 36, 48, 60, 72, 96,
];
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,8 @@ type StepController = {

export const useStepController = (): StepController => {
const [currentStep, setCurrentStep] = useRecoilState(currentStepAtom);
const {
name,
stitches,
rows,
size,
needle,
yarn,
description,
techniques,
} = useRecoilValue(currentDesignInputAtom);
const { name, stitches, rows, size, needle, yarn, description, techniques } =
useRecoilValue(currentDesignInputAtom);
const {
totalLength,
sleeveLength,
Expand Down
8 changes: 2 additions & 6 deletions src/pages/CreateDesign/components/Footer/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,8 @@ import { useStepController } from './hooks/useStepController';
const Footer = (): React.ReactElement => {
const currentStep = useRecoilValue(currentStepAtom);

const {
onPreviousClick,
onNextClick,
renderNextLabel,
isNextDisabled,
} = useStepController();
const { onPreviousClick, onNextClick, renderNextLabel, isNextDisabled } =
useStepController();

return (
<FooterContainer>
Expand Down
35 changes: 35 additions & 0 deletions src/pages/CreateProduct/Confirm/Confirm.css.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { Typography } from '@material-ui/core';
import { Link } from 'react-router-dom';
import styled from 'styled-components';
import { theme } from 'themes';

export const ProductCard = styled(Link)`
color: ${theme.palette.common.black};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Q: color: ${palette.text.secondary}; 이런거 안써주시고 새로 정의하신 이유가 궁금해욤

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A: 정의한게 아니라 palette 정의된거 보니까 기본으로 common이라는 객체가 있고 그 안에 white, black 있습니당!
palette.ts에 common 정의되어있는거 제가 한 것 같은데 ,, 왜 추가했는지 ,, 기억도 나지 않고 제거해도 동일하게 작동하네요 (33789a3 )
${palette.text.secondary}는 회색인 것 같슴다

image
node_modules/@material-ui/core/styles/createPalette.d.ts

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

${palette.text.primary}도 있어용

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

eb76c79 수정했어용

text-decoration: none;
width: ${theme.spacing(55)};
border: 5px solid ${theme.palette.grey[200]};
border-radius: ${theme.spacing(6)};
`;

export const RepresentativeImage = styled.img`
width: ${theme.spacing(55)};
height: ${theme.spacing(46)};
border-radius: ${theme.spacing(6)};
`;

export const Tag = styled.div`
display: inline-block;
background: ${theme.palette.grey[300]};
padding: ${theme.spacing(1)};
margin: ${theme.spacing(0.4)};
border-radius: ${theme.spacing(2)};
font-size: ${theme.spacing(1.5)};
`;

export const Price = styled(Typography)`
margin-left: ${theme.spacing(1)};
`;

export const InfoMessage = styled.li`
margin-top: ${theme.spacing(1)};
`;
78 changes: 78 additions & 0 deletions src/pages/CreateProduct/Confirm/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import { Box, Grid, Typography } from '@material-ui/core';
import React from 'react';
import { useRecoilValue } from 'recoil';
import { splitText } from 'utils/splitText';

import { currentProductIdAtom, currentProductInputAtom } from '../recoils';

import {
ProductCard,
RepresentativeImage,
InfoMessage,
Price,
Tag,
} from './Confirm.css';

const Confirm = (): React.ReactElement => {
const { name, fullPrice, discountPrice, representativeImageUrl, tags } =
useRecoilValue(currentProductInputAtom);
const currentProductId = useRecoilValue(currentProductIdAtom);

const getRate = (): string => {
const rate = Math.round((discountPrice / fullPrice) * 100);

return isNaN(rate) ? '' : rate.toString();
};

const getPrice = (): string => {
const price = fullPrice - discountPrice;

return isNaN(price) && Math.sign(price) ? '' : price.toLocaleString();
};

return (
<>
<Grid container>
<ProductCard to={`/product/${currentProductId}`}>
{representativeImageUrl && (
<RepresentativeImage
src="//via.placeholder.com/500x300"
alt="상품 대표 이미지"
/>
)}
<Box px={4} py={2}>
<Typography variant="h4">{name}</Typography>
<Box display="flex" justifyContent="space-between" mt={4}>
<div>
{splitText(tags, '#').map((tag: string) => (
<Tag>#{tag}</Tag>
))}
</div>
<Box display="flex">
<Typography color="primary">
<b>{getRate()}%</b>
</Typography>
<Price variant="h4">{getPrice()}원</Price>
</Box>
</Box>
</Box>
</ProductCard>
</Grid>
<ul>
<InfoMessage>
상품은 위와 같이 다른 니터들에게 노출될 예정이에요!
</InfoMessage>
<InfoMessage>클릭하면 상세도 확인해볼 수 있어요!</InfoMessage>
<InfoMessage>
노출되는 기간은 "
<Typography display="inline" color="primary">
jiyaaany marked this conversation as resolved.
Show resolved Hide resolved
상품이 등록된 이후부터 계속해서
</Typography>
" 노출됩니다.
</InfoMessage>
</ul>
</>
);
};

export default Confirm;
62 changes: 62 additions & 0 deletions src/pages/CreateProduct/components/Footer/hooks/useSaveProduct.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import { FAILED_TO_SAVE_PRODUCT } from 'constants/errors';

import { usePost } from 'hooks/usePost';
import {
currentProductIdAtom,
currentProductInputAtom,
currentStepAtom,
} from 'pages/CreateProduct/recoils';
import { PAGE } from 'pages/CreateProduct/types';
import { useRecoilValue, useSetRecoilState } from 'recoil';
import { splitText } from 'utils/splitText';

type SaveProduct = {
saveProduct: () => void;
};

export const useSaveProduct = (): SaveProduct => {
const setCurrentStep = useSetRecoilState(currentStepAtom);
const setCurrentProductId = useSetRecoilState(currentProductIdAtom);

const {
name,
fullPrice,
discountPrice,
representativeImageUrl,
specifiedSalesStartDate,
specifiedSalesEndDate,
tags,
designIds,
} = useRecoilValue(currentProductInputAtom);

const onSuccess = () => {
if (data) {
setCurrentProductId(data.payload.id);
}
setCurrentStep(PAGE.INTRODUCTION);
};

const { data, mutate } = usePost({
pathname: '/product/package',
errorMessage: FAILED_TO_SAVE_PRODUCT,
onSuccess,
});

const saveProduct = (): void => {
const postProductData = {
id: null,
name,
full_price: fullPrice,
discount_price: discountPrice,
representative_image_url: representativeImageUrl,
specified_sales_start_date: specifiedSalesStartDate,
specified_sales_end_date: specifiedSalesEndDate,
tags: splitText(tags, '#'),
design_ids: designIds,
};

mutate(postProductData);
};

return { saveProduct };
};
26 changes: 26 additions & 0 deletions src/pages/CreateProduct/components/Footer/hooks/useStartSale.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { MY_INFORMATION_ROUTER_ROOT } from 'constants/path';

import { usePost } from 'hooks/usePost';
import { currentProductIdAtom } from 'pages/CreateProduct/recoils';
import { useHistory } from 'react-router-dom';
import { useRecoilValue } from 'recoil';

type StartSale = {
startSale: () => void;
};

export const useStartSale = (): StartSale => {
const currentProductId = useRecoilValue(currentProductIdAtom);
const history = useHistory();

const { mutate } = usePost({
pathname: '/product',
});

const startSale = () => {
mutate({ id: currentProductId });
history.push(MY_INFORMATION_ROUTER_ROOT);
};

return { startSale };
};
65 changes: 10 additions & 55 deletions src/pages/CreateProduct/components/Footer/index.tsx
Original file line number Diff line number Diff line change
@@ -1,67 +1,21 @@
import { FAILED_TO_SAVE_PRODUCT } from 'constants/errors';

import { Button as MaterialButton } from '@material-ui/core';
import { useCommonSnackbar } from 'components/CommonSnackbar/useCommonSnackbar';
import { Button } from 'dumbs';
import { usePost } from 'hooks/usePost';
import {
currentProductInputAtom,
currentStepAtom,
} from 'pages/CreateProduct/recoils';
import { currentStepAtom } from 'pages/CreateProduct/recoils';
import { PAGE } from 'pages/CreateProduct/types';
import React, { useState } from 'react';
import { useRecoilState, useRecoilValue } from 'recoil';
import React from 'react';
import { useRecoilState } from 'recoil';
import { FooterContainer } from 'styles/constants';

import { useSaveProduct } from './hooks/useSaveProduct';
import { useStartSale } from './hooks/useStartSale';

const Footer = (): React.ReactElement => {
const { DESIGN, PACKAGE, INTRODUCTION, CONFIRM } = PAGE;
const [currentStep, setCurrentStep] = useRecoilState(currentStepAtom);
const {
name,
fullPrice,
discountPrice,
representativeImageUrl,
specifiedSalesStartDate,
specifiedSalesEndDate,
tags,
designIds,
} = useRecoilValue(currentProductInputAtom);

const [showError, setShowError] = useState(false);

const { mutate } = usePost({
pathname: '/product/package',
errorMessage: FAILED_TO_SAVE_PRODUCT,
onSuccess: () => setCurrentStep(INTRODUCTION),
onError: () => setShowError(true),
});

useCommonSnackbar({
message: FAILED_TO_SAVE_PRODUCT,
severity: 'error',
dependencies: [showError],
});

const saveProduct = (): void => {
const postProductData = {
id: null,
name,
full_price: fullPrice,
discount_price: discountPrice,
representative_image_url: representativeImageUrl,
specified_sales_start_date: specifiedSalesStartDate,
specified_sales_end_date: specifiedSalesEndDate,
tags: tags
.split('#')
.map((tag) => tag.trim())
.filter((value) => value),
design_ids: designIds,
};

mutate(postProductData);
};
const { saveProduct } = useSaveProduct();
const { startSale } = useStartSale();

const handleOnClickPrevious = (): void => {
const handleOnClickPrevious = async (): Promise<void> => {
switch (currentStep) {
case PACKAGE:
setCurrentStep(DESIGN);
Expand Down Expand Up @@ -104,6 +58,7 @@ const Footer = (): React.ReactElement => {
setCurrentStep(CONFIRM);
break;
case CONFIRM:
startSale();
break;
default:
break;
Expand Down
Loading