From 7568413b4fd63aa58d8b1ef2dc244b8c67616a23 Mon Sep 17 00:00:00 2001 From: yoonminsang Date: Sat, 28 Aug 2021 14:52:12 +0900 Subject: [PATCH 01/84] =?UTF-8?q?feat:=20=EC=8A=A4=ED=81=AC=EB=A1=A4=20?= =?UTF-8?q?=EC=9D=B4=EB=8F=99=EC=9D=84=20=EB=B6=80=EB=93=9C=EB=9F=BD?= =?UTF-8?q?=EA=B2=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/components/item-detail/detail.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/src/components/item-detail/detail.tsx b/client/src/components/item-detail/detail.tsx index f8abb8f..9497935 100644 --- a/client/src/components/item-detail/detail.tsx +++ b/client/src/components/item-detail/detail.tsx @@ -57,11 +57,11 @@ const DetailImageWrapper = styled.div` const Detail: FC = ({ contents, reviewCount, reviews, reviewLoading, pageCount, pageId, setPageId }) => { const detailRef = useRef(null); const detailExecuteScroll = () => { - if (detailRef.current) detailRef.current.scrollIntoView(); + if (detailRef.current) detailRef.current.scrollIntoView({ behavior: 'smooth' }); }; const reviewRef = useRef(null); const reviewExecuteScroll = () => { - if (reviewRef.current) reviewRef.current.scrollIntoView(); + if (reviewRef.current) reviewRef.current.scrollIntoView({ behavior: 'smooth' }); }; return ( From 4735ac932b1f0924a85e5edb4fbe880612957dd7 Mon Sep 17 00:00:00 2001 From: yoonminsang Date: Sat, 28 Aug 2021 15:16:17 +0900 Subject: [PATCH 02/84] =?UTF-8?q?bug:=20=EB=82=A0=EC=A7=9C=20validation=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 이전날짜가 더 큰경우를 막아줌 --- client/src/components/common/period-selector.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/client/src/components/common/period-selector.tsx b/client/src/components/common/period-selector.tsx index af49a25..6bdad95 100644 --- a/client/src/components/common/period-selector.tsx +++ b/client/src/components/common/period-selector.tsx @@ -107,6 +107,7 @@ const PeriodSelector: FC = ({ ['1개월', onClickThisMonth], ['3개월', onClickThreeMonth], ]; + const prevMax = currentDate && new Date(currentDate) < new Date(today) ? currentDate : today; return (
@@ -121,7 +122,7 @@ const PeriodSelector: FC = ({ { setPrevDate(e.target.value); @@ -131,6 +132,7 @@ const PeriodSelector: FC = ({ ~ { From b14a9761ec852ade8f046d689b768dcd4e808dc8 Mon Sep 17 00:00:00 2001 From: yoonminsang Date: Sat, 28 Aug 2021 15:16:43 +0900 Subject: [PATCH 03/84] =?UTF-8?q?refactor:=20=EA=B3=B5=ED=86=B5=EC=BB=B4?= =?UTF-8?q?=ED=8F=AC=EB=84=8C=ED=8A=B8=20=EC=82=AC=EC=9A=A9=ED=95=98?= =?UTF-8?q?=EB=A9=B4=EC=84=9C=20=EC=82=AC=EC=9A=A9=ED=95=98=EC=A7=80=20?= =?UTF-8?q?=EC=95=8A=EB=8A=94=20=EC=BB=B4=ED=8F=AC=EB=84=8C=ED=8A=B8=20?= =?UTF-8?q?=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/components/my/my-order-list.tsx | 52 ------------ client/src/components/my/my-order.tsx | 79 ------------------- .../containers/my-order-list-container.tsx | 2 - 3 files changed, 133 deletions(-) delete mode 100644 client/src/components/my/my-order-list.tsx delete mode 100644 client/src/components/my/my-order.tsx diff --git a/client/src/components/my/my-order-list.tsx b/client/src/components/my/my-order-list.tsx deleted file mode 100644 index 68ecb99..0000000 --- a/client/src/components/my/my-order-list.tsx +++ /dev/null @@ -1,52 +0,0 @@ -import React, { FC } from 'react'; -import styled from 'lib/woowahan-components'; - -import { IOrder } from 'types/order'; - -import { CircleLoader } from 'components'; -import MyOrder from './my-order'; - -interface MyOrderListProps { - loading: boolean; - orders: IOrder[]; - totalCount: number; -} - -const Wrapper = styled.div` - margin: 0 -12px; - margin-bottom: 100px; -`; - -const Empty = styled.div` - display: flex; - justify-content: center; - margin-top: 80px; - font-family: ${props => props.theme?.fontEuljiro10}; - color: ${props => props.theme?.colorLine}; - font-size: 80px; -`; - -const MyOrderList: FC = ({ loading, orders, totalCount }) => { - const inner = totalCount ? ( - orders.map(({ createdAt, id, title, thumbnail, price, quantity, status }) => ( - - )) - ) : ( - -
-
- ); - - return {loading ? : inner}; -}; - -export default MyOrderList; diff --git a/client/src/components/my/my-order.tsx b/client/src/components/my/my-order.tsx deleted file mode 100644 index 8682bd8..0000000 --- a/client/src/components/my/my-order.tsx +++ /dev/null @@ -1,79 +0,0 @@ -import React, { FC } from 'react'; -import styled from 'lib/woowahan-components'; - -import { IOrder } from 'types/order'; - -import { formatPrice } from 'utils'; - -const Wrapper = styled.div` - border-bottom: 1px solid ${props => props.theme?.colorLineLight}; - display: flex; - align-items: center; - justify-content: space-between; - padding: 18px 15px; - > div { - font-size: 12px; - color: ${props => props.theme?.softBlack}; - font-weight: ${props => props.theme?.weightMid}; - padding: 0 2px; - } - > div:nth-child(1) { - flex: 1.4; - } - > div:nth-child(2) { - flex: 3; - display: flex; - align-items: center; - } - > div:nth-child(3) { - flex: 1.7; - } - > div:nth-child(4) { - flex: 1; - } - img { - display: none; - } - ${props => props.theme?.tablet} { - > div { - font-size: 14px; - } - img { - width: 72px; - height: 62px; - padding-right: 7px; - display: block; - } - } - ${props => props.theme?.laptop} { - > div { - font-size: 16px; - } - img { - width: 82px; - height: 72px; - padding-right: 10px; - display: block; - } - } -`; - -const MyOrder: FC = ({ createdAt, title, thumbnail, price, quantity, status }) => { - return ( - -
{createdAt}
-
-
- 썸네일 -
-
{title}
-
-
- {formatPrice(price)}원 / {quantity}개 -
-
{status}
-
- ); -}; - -export default MyOrder; diff --git a/client/src/containers/my-order-list-container.tsx b/client/src/containers/my-order-list-container.tsx index 310dedd..b89c481 100644 --- a/client/src/containers/my-order-list-container.tsx +++ b/client/src/containers/my-order-list-container.tsx @@ -82,8 +82,6 @@ const MyOrderListContainer: FC = () => { select={select} /> - {/* - */} ); From 1106943c0ad9e66efbec3f14db0e5c88c8da3bc3 Mon Sep 17 00:00:00 2001 From: yoonminsang Date: Sat, 28 Aug 2021 15:31:03 +0900 Subject: [PATCH 04/84] =?UTF-8?q?refactor:=20=ED=85=8C=EB=B8=94=EB=A6=BF,?= =?UTF-8?q?=20=EB=8D=B0=EC=8A=A4=ED=81=AC=ED=83=91=20=EB=A7=A8=EC=9C=84=20?= =?UTF-8?q?navbar=20=EB=B0=B0=EA=B2=BD=EC=83=89=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - props white를 어디서 주는거 같은데 잘 안보여서 그냥 내비둠.. --- client/src/components/common/navbar.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/components/common/navbar.tsx b/client/src/components/common/navbar.tsx index 5da19a1..8d7baa8 100644 --- a/client/src/components/common/navbar.tsx +++ b/client/src/components/common/navbar.tsx @@ -19,7 +19,7 @@ interface NavbarProps { } const Wrapper = styled.nav` - background-color: ${props => (props.white ? props.theme?.colorWhite : props.theme?.colorBg)}; + background-color: ${props => props.theme?.colorBg}; border-bottom: 1px solid ${props => props.theme?.colorLineLight}; padding: 12px 10%; display: flex; From 461231b7be6feccd61af6e00c5c5edaf15c9173f Mon Sep 17 00:00:00 2001 From: yoonminsang Date: Sat, 28 Aug 2021 15:35:03 +0900 Subject: [PATCH 05/84] =?UTF-8?q?wip:=20sanitize-html=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 리액트에서는 기본적으로 html태그를 불러오지 않기 때문(불러오려면 따로 코드를 작성해줘야함) --- client/package.json | 1 - client/yarn.lock | 32 ++------------------------------ 2 files changed, 2 insertions(+), 31 deletions(-) diff --git a/client/package.json b/client/package.json index 320818e..62b191e 100644 --- a/client/package.json +++ b/client/package.json @@ -33,7 +33,6 @@ "redux-logger": "^3.0.6", "redux-saga": "^1.1.3", "redux-saga-test-plan": "^4.0.3", - "sanitize-html": "^2.4.0", "styled-reset": "^4.3.4", "stylis": "^4.0.10" }, diff --git a/client/yarn.lock b/client/yarn.lock index 18c673c..46a5ba6 100644 --- a/client/yarn.lock +++ b/client/yarn.lock @@ -4531,7 +4531,7 @@ html-webpack-plugin@^5.3.2: pretty-error "^3.0.4" tapable "^2.0.0" -htmlparser2@^6.0.0, htmlparser2@^6.1.0: +htmlparser2@^6.1.0: version "6.1.0" resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-6.1.0.tgz#c4d762b6c3371a05dbe65e94ae43a9f845fb8fb7" integrity sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A== @@ -5018,11 +5018,6 @@ is-plain-object@^2.0.3, is-plain-object@^2.0.4: dependencies: isobject "^3.0.1" -is-plain-object@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-5.0.0.tgz#4427f50ab3429e9025ea7d52e9043a9ef4159344" - integrity sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q== - is-posix-bracket@^0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz#3334dc79774368e92f016e6fbc0a88f5cd6e6bc4" @@ -5734,11 +5729,6 @@ kleur@^3.0.3: resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e" integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w== -klona@^2.0.3: - version "2.0.4" - resolved "https://registry.yarnpkg.com/klona/-/klona-2.0.4.tgz#7bb1e3affb0cb8624547ef7e8f6708ea2e39dfc0" - integrity sha512-ZRbnvdg/NxqzC7L9Uyqzf4psi1OM4Cuc+sJAkQPjO6XkQIJTNbfK2Rsmbw8fx1p2mkZdp2FZYo2+LwXYY/uwIA== - language-subtag-registry@~0.3.2: version "0.3.21" resolved "https://registry.yarnpkg.com/language-subtag-registry/-/language-subtag-registry-0.3.21.tgz#04ac218bea46f04cb039084602c6da9e788dd45a" @@ -6557,11 +6547,6 @@ parse-json@^4.0.0: error-ex "^1.3.1" json-parse-better-errors "^1.0.1" -parse-srcset@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/parse-srcset/-/parse-srcset-1.0.2.tgz#f2bd221f6cc970a938d88556abc589caaaa2bde1" - integrity sha1-8r0iH2zJcKk42IVWq8WJyqqiveE= - parse5@6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/parse5/-/parse5-6.0.1.tgz#e1a1c085c569b3dc08321184f19a39cc27f7c30b" @@ -6972,7 +6957,7 @@ postcss-value-parser@^4.0.2, postcss-value-parser@^4.1.0: resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.1.0.tgz#443f6a20ced6481a2bda4fa8532a6e55d789a2cb" integrity sha512-97DXOFbQJhk71ne5/Mt6cOu6yxsSfM0QGQyl0L25Gca4yGWEGJaig7l7gbCX623VqTBNGLRLaVUCnNkcedlRSQ== -postcss@^8.0.2, postcss@^8.2.15, postcss@^8.3.5: +postcss@^8.2.15, postcss@^8.3.5: version "8.3.6" resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.3.6.tgz#2730dd76a97969f37f53b9a6096197be311cc4ea" integrity sha512-wG1cc/JhRgdqB6WHEuyLTedf3KIRuD0hG6ldkFEZNCjRxiC+3i6kkWUUbiJQayP28iwG35cEmAbe98585BYV0A== @@ -7568,19 +7553,6 @@ safe-regex@^1.1.0: resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== -sanitize-html@^2.4.0: - version "2.4.0" - resolved "https://registry.yarnpkg.com/sanitize-html/-/sanitize-html-2.4.0.tgz#8da7524332eb210d968971621b068b53f17ab5a3" - integrity sha512-Y1OgkUiTPMqwZNRLPERSEi39iOebn2XJLbeiGOBhaJD/yLqtLGu6GE5w7evx177LeGgSE+4p4e107LMiydOf6A== - dependencies: - deepmerge "^4.2.2" - escape-string-regexp "^4.0.0" - htmlparser2 "^6.0.0" - is-plain-object "^5.0.0" - klona "^2.0.3" - parse-srcset "^1.0.2" - postcss "^8.0.2" - saxes@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/saxes/-/saxes-5.0.1.tgz#eebab953fa3b7608dbe94e5dadb15c888fa6696d" From 32351674cb01ddb709c9dc6697ffabfed9b2f709 Mon Sep 17 00:00:00 2001 From: yoonminsang Date: Sat, 28 Aug 2021 17:18:07 +0900 Subject: [PATCH 06/84] =?UTF-8?q?chore:=20react-daum-postcode=20=EC=84=A4?= =?UTF-8?q?=EC=B9=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 주소 검색해주는 완전 좋은 라이브러리 --- client/package.json | 1 + client/yarn.lock | 19 ++++++++++++++++++- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/client/package.json b/client/package.json index 62b191e..a4518f8 100644 --- a/client/package.json +++ b/client/package.json @@ -27,6 +27,7 @@ "axios": "^0.21.1", "nanoid": "^3.1.25", "react": "^17.0.2", + "react-daum-postcode": "^2.0.6", "react-dom": "^17.0.2", "react-redux": "^7.2.4", "redux": "^4.1.1", diff --git a/client/yarn.lock b/client/yarn.lock index 46a5ba6..298d251 100644 --- a/client/yarn.lock +++ b/client/yarn.lock @@ -7044,7 +7044,7 @@ prompts@^2.0.1: kleur "^3.0.3" sisteransi "^1.0.5" -prop-types@^15.7.2: +prop-types@^15.6.2, prop-types@^15.7.2: version "15.7.2" resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5" integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ== @@ -7140,6 +7140,14 @@ raw-body@2.4.0: iconv-lite "0.4.24" unpipe "1.0.0" +react-daum-postcode@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/react-daum-postcode/-/react-daum-postcode-2.0.6.tgz#4f3ca34cd11ad81bc42aaad9f1d5bd339a878927" + integrity sha512-CuDM0WdVgdTeu07uG12iHlECLYsJahZF8yFTLuwkOD09DiepbjrLc8B7Qxt/ebkfXh3v3KXuUY5hyK6Y3rnVSA== + dependencies: + prop-types "^15.6.2" + react "^16.4.2" + react-dom@^17.0.2: version "17.0.2" resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-17.0.2.tgz#ecffb6845e3ad8dbfcdc498f0d0a939736502c23" @@ -7171,6 +7179,15 @@ react-redux@^7.2.4: prop-types "^15.7.2" react-is "^16.13.1" +react@^16.4.2: + version "16.14.0" + resolved "https://registry.yarnpkg.com/react/-/react-16.14.0.tgz#94d776ddd0aaa37da3eda8fc5b6b18a4c9a3114d" + integrity sha512-0X2CImDkJGApiAlcf0ODKIneSwBPhqJawOa5wCtKbu7ZECrmS26NvtSILynQ66cgkT/RJ4LidJOc3bUESwmU8g== + dependencies: + loose-envify "^1.1.0" + object-assign "^4.1.1" + prop-types "^15.6.2" + react@^17.0.2: version "17.0.2" resolved "https://registry.yarnpkg.com/react/-/react-17.0.2.tgz#d0b5cc516d29eb3eee383f75b62864cfb6800037" From 667a0fac6e7b07bc94e1121499dba1332fd9cff2 Mon Sep 17 00:00:00 2001 From: yoonminsang Date: Sat, 28 Aug 2021 17:19:27 +0900 Subject: [PATCH 07/84] =?UTF-8?q?feat:=20=EB=9D=BC=EC=9D=B4=EB=B8=8C?= =?UTF-8?q?=EB=9F=AC=EB=A6=AC=EB=A5=BC=20=EA=B0=90=EC=8B=B8=EB=8A=94=20?= =?UTF-8?q?=EB=AA=A8=EB=8B=AC=20=EC=BB=B4=ED=8F=AC=EB=84=8C=ED=8A=B8=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 재사용하면 좋은데 형식이 너무 달라서 할 수가 없었음 - 이런부분때문에 처음에 팀원이 모달창을 그렇게 만드는걸 추천하지 않았던 것 - 물론 타입넘겨줘서 재사용하는건 매우 좋은 방법중한가지라고 생각 --- .../src/components/common/address-modal.tsx | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 client/src/components/common/address-modal.tsx diff --git a/client/src/components/common/address-modal.tsx b/client/src/components/common/address-modal.tsx new file mode 100644 index 0000000..b95ff9a --- /dev/null +++ b/client/src/components/common/address-modal.tsx @@ -0,0 +1,47 @@ +import styled from 'lib/woowahan-components'; +import React, { FC } from 'react'; +import DaumPostcode from 'react-daum-postcode'; + +interface IAddressData { + roadAddress: string; +} + +interface AddressModalProps { + handleComplete: (data: IAddressData) => void; + setModal: React.Dispatch>; +} +const Modal = styled.div` + position: fixed; + left: 0; + top: 0; + width: 100%; + height: 100%; + background-color: rgba(0, 0, 0, 0.3); + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + z-index: 10; +`; + +const ModalInner = styled.div` + width: 80%; + #__daum__layer_1 { + border-radius: 10px; + } +`; + +const AddressModal: FC = ({ handleComplete, setModal }) => { + const modalClickHandler = (e: Event) => { + if (e.target === e.currentTarget) setModal(false); + }; + return ( + + + + + + ); +}; + +export default AddressModal; From 4a68c9d944632c1e31593e39732597121853bc76 Mon Sep 17 00:00:00 2001 From: yoonminsang Date: Sat, 28 Aug 2021 17:20:21 +0900 Subject: [PATCH 08/84] =?UTF-8?q?feat:=20=EC=A3=BC=EC=86=8C=ED=8F=BC?= =?UTF-8?q?=EC=97=90=20=EB=9D=BC=EC=9D=B4=EB=B8=8C=EB=9F=AC=EB=A6=AC=20?= =?UTF-8?q?=EC=A0=81=EC=9A=A9=ED=95=98=EA=B8=B0=20=EC=9C=84=ED=95=B4=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../my/my-address/my-address-form.tsx | 79 ++++++++++++++----- 1 file changed, 58 insertions(+), 21 deletions(-) diff --git a/client/src/components/my/my-address/my-address-form.tsx b/client/src/components/my/my-address/my-address-form.tsx index 0b30751..476bfee 100644 --- a/client/src/components/my/my-address/my-address-form.tsx +++ b/client/src/components/my/my-address/my-address-form.tsx @@ -1,22 +1,30 @@ -import React, { FC } from 'react'; +import React, { FC, useEffect, useState } from 'react'; import styled from 'lib/woowahan-components'; import GridForm from 'components/common/grid-form'; import TextButton from 'components/common/button/text-button'; +import AddressModal from 'components/common/address-modal'; interface MyAddressFormProps { name: string; receiver: string; address: string; + setAddress: React.Dispatch>; + addressDetail: string; onChange: (e: React.ChangeEvent) => void; onSubmit: (e: React.FormEvent) => void; nameError: string; receiverError: string; addressError: string; + addressDetailError: string; addError: string; loading: boolean; } +interface IAddressData { + roadAddress: string; +} + const InputWrapper = styled.div` display: flex; align-items: center; @@ -46,35 +54,64 @@ const MyAddressForm: FC = ({ name, receiver, address, + setAddress, + addressDetail, onChange, onSubmit, nameError, receiverError, addressError, + addressDetailError, addError, loading, }) => { + const [modal, setModal] = useState(false); + const handleComplete = (data: IAddressData) => { + setAddress(data.roadAddress); + }; + useEffect(() => { + if (address) setModal(false); + }, [address]); return ( - - - - - {nameError} - - - - {receiverError} - - - - {addressError} - - - -
{addError}
- -
- + <> +
+ + + + {nameError} + + + + {receiverError} + + + setModal(true)} + placeholder="서울 강남구 가로수길" + /> + {addressError} + + + + {addressDetailError} + + + +
{addError}
+ +
+
+ {modal && } + ); }; From c3a93fb5c09ba8883b188b9a1a18af6666e8c018 Mon Sep 17 00:00:00 2001 From: yoonminsang Date: Sat, 28 Aug 2021 17:22:04 +0900 Subject: [PATCH 09/84] =?UTF-8?q?feat:=20=EC=A3=BC=EC=86=8C=20=EC=BB=A8?= =?UTF-8?q?=ED=85=8C=EC=9D=B4=EB=84=88=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/containers/my-address-container.tsx | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/client/src/containers/my-address-container.tsx b/client/src/containers/my-address-container.tsx index a0d8016..c1d5aba 100644 --- a/client/src/containers/my-address-container.tsx +++ b/client/src/containers/my-address-container.tsx @@ -14,14 +14,16 @@ const MyAddressContainer: FC = () => { const [nameError, setNameError] = useState(''); const [receiverError, setReceiverError] = useState(''); const [addressError, setAddressError] = useState(''); + const [addressDetailError, setAddressDetailError] = useState(''); const [addError, setAddError] = useState(''); const dispatch = useDispatch(); const history = useHistory(); + const [address, setAddress] = useState(''); - const [{ name, receiver, address }, onChange, reset] = useInputs({ + const [{ name, receiver, addressDetail }, onChange, reset] = useInputs({ name: '', receiver: '', - address: '', + addressDetail: '', }); const { loading, addLoading, removeLoading, user, userLoading, addressList, error } = useSelector( @@ -49,9 +51,10 @@ const MyAddressContainer: FC = () => { if (!name) setNameError('배송지를 입력하세요'); if (!receiver) setReceiverError('받는분을 입력하세요'); if (!address) setAddressError('주소를 입력하세요'); + if (!addressDetail) setAddressDetailError('상세주소를 입력하세요'); if (addressList.length >= 3) setAddError('배송지는 최대 3개까지 입력할 수 있습니다'); - if (name && receiver && address && addressList.length < 3) { - dispatch({ type: addAddress.type, payload: { name, receiver, address } }); + if (name && receiver && addressDetail && addressList.length < 3) { + dispatch({ type: addAddress.type, payload: { name, receiver, address: `${address} ${addressDetail}` } }); reset(); } }; @@ -75,11 +78,14 @@ const MyAddressContainer: FC = () => { name={name} receiver={receiver} address={address} + setAddress={setAddress} + addressDetail={addressDetail} onChange={onChange} onSubmit={onSubmit} nameError={nameError} receiverError={receiverError} addressError={addressError} + addressDetailError={addressDetailError} addError={addError} loading={addLoading} /> From ad5ba97f70491c772b5ff1939e9085f03c700333 Mon Sep 17 00:00:00 2001 From: yoonminsang Date: Sat, 28 Aug 2021 17:44:28 +0900 Subject: [PATCH 10/84] =?UTF-8?q?wip:=20cart=ED=8E=98=EC=9D=B4=EC=A7=80=20?= =?UTF-8?q?=EB=AA=A8=EB=B0=94=EC=9D=BC=20=EC=9E=98=EB=A6=AC=EB=8A=94?= =?UTF-8?q?=EA=B2=83=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/components/common/price-calculator.tsx | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/client/src/components/common/price-calculator.tsx b/client/src/components/common/price-calculator.tsx index eb4d954..209b377 100644 --- a/client/src/components/common/price-calculator.tsx +++ b/client/src/components/common/price-calculator.tsx @@ -17,6 +17,9 @@ const Box = styled.div` display: flex; flex-wrap: wrap; justify-content: flex-end; + ${props => props.theme?.mobile} { + justify-content: center; + } align-items: center; border: 2px solid ${({ theme }) => theme?.colorLineLight}; margin: 50px 0 30px; @@ -45,6 +48,9 @@ const BoxItem = styled.div` .title { font-size: 16px; + ${props => props.theme?.mobile} { + font-size: 12px; + } color: ${({ theme }) => theme?.colorSoftBlack}; } @@ -52,6 +58,9 @@ const BoxItem = styled.div` font-size: 18px; font-weight: ${({ theme }) => theme?.weightBold}; color: ${({ theme }) => theme?.colorSoftBlack}; + ${props => props.theme?.mobile} { + font-size: 14px; + } } span { From 2af9c39c91dd91e213d219c4ec0610cb213011c7 Mon Sep 17 00:00:00 2001 From: yoonminsang Date: Sat, 28 Aug 2021 18:09:28 +0900 Subject: [PATCH 11/84] =?UTF-8?q?fix:=20=EA=B7=B8=EB=A6=AC=EB=93=9C?= =?UTF-8?q?=ED=8F=BC=20=EB=AA=A8=EB=B0=94=EC=9D=BC=20=ED=8F=B0=ED=8A=B8?= =?UTF-8?q?=EC=82=AC=EC=9D=B4=EC=A6=88=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/components/common/grid-form.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/client/src/components/common/grid-form.tsx b/client/src/components/common/grid-form.tsx index 1567ece..e9cd218 100644 --- a/client/src/components/common/grid-form.tsx +++ b/client/src/components/common/grid-form.tsx @@ -27,6 +27,7 @@ const FormContainer = styled.div` input, textarea { width: 100%; + font-size: 12px; } textarea { height: 120px; @@ -72,6 +73,7 @@ const RowHead = styled.div` const RowContent = styled.div` flex: 1; padding: 8px 16px; + font-size: 12px; `; const GridForm: FC = ({ titles, children }) => { From 92e94290b974cf726b3924d29dc3a9b27c916bdc Mon Sep 17 00:00:00 2001 From: yoonminsang Date: Sat, 28 Aug 2021 18:09:52 +0900 Subject: [PATCH 12/84] =?UTF-8?q?fix:=20=EB=82=B4=20=EC=A3=BC=EC=86=8C=20?= =?UTF-8?q?=EB=A7=88=EC=A7=84=ED=83=91=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/components/my/my-address/my-address-form.tsx | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/client/src/components/my/my-address/my-address-form.tsx b/client/src/components/my/my-address/my-address-form.tsx index 476bfee..d18d18a 100644 --- a/client/src/components/my/my-address/my-address-form.tsx +++ b/client/src/components/my/my-address/my-address-form.tsx @@ -25,11 +25,14 @@ interface IAddressData { roadAddress: string; } +const Form = styled.form` + margin-top: 10px; +`; + const InputWrapper = styled.div` display: flex; align-items: center; flex-wrap: wrap; - gap: 8px; `; const InputErrorMessage = styled.div` @@ -74,7 +77,7 @@ const MyAddressForm: FC = ({ }, [address]); return ( <> -
+ @@ -109,7 +112,7 @@ const MyAddressForm: FC = ({
{addError}
- + {modal && } ); From 85ebd7b984b7af984d4cfd1ba24d6d32ad5d977b Mon Sep 17 00:00:00 2001 From: yoonminsang Date: Sat, 28 Aug 2021 18:15:00 +0900 Subject: [PATCH 13/84] =?UTF-8?q?wip:=20order=EC=BB=B4=ED=8F=AC=EB=84=8C?= =?UTF-8?q?=ED=8A=B8=EC=97=90=20gap=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 밑에만 gap이 적용되고 있더라구요 이러면 이상하지 않나요?? 의도한거라면 말씀해주세요 다시 복구할게요 --- client/src/components/order/index.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/client/src/components/order/index.tsx b/client/src/components/order/index.tsx index 3d97d81..5730029 100644 --- a/client/src/components/order/index.tsx +++ b/client/src/components/order/index.tsx @@ -68,7 +68,6 @@ const InputWrapper = styled.div` display: flex; align-items: center; flex-wrap: wrap; - gap: 8px; `; const InputErrorMessage = styled.div` From de70e16646b09a3e180d285fd6c42413d9d2a948 Mon Sep 17 00:00:00 2001 From: yoonminsang Date: Sat, 28 Aug 2021 18:36:53 +0900 Subject: [PATCH 14/84] =?UTF-8?q?fix:=20=EB=9D=BC=EB=94=94=EC=98=A4?= =?UTF-8?q?=EB=B2=84=ED=8A=BC=EB=9D=BC=EB=B2=A8=20=EC=82=AC=EC=9D=B4?= =?UTF-8?q?=EC=97=90=20=EA=B0=84=EA=B2=A9=EC=9D=B4=20=EC=97=86=EC=96=B4?= =?UTF-8?q?=EC=84=9C=20=EB=A7=88=EC=A7=84=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/components/order/radio-button.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/client/src/components/order/radio-button.tsx b/client/src/components/order/radio-button.tsx index 43e592c..04937c8 100644 --- a/client/src/components/order/radio-button.tsx +++ b/client/src/components/order/radio-button.tsx @@ -13,6 +13,7 @@ const Label = styled.label` display: flex; align-items: center; font-size: 14px; + margin-right: 5px; input[type='radio'] { width: 13px; From a0ab28d21eef641cb6131d94868e9290a920c2f5 Mon Sep 17 00:00:00 2001 From: yoonminsang Date: Sat, 28 Aug 2021 18:37:43 +0900 Subject: [PATCH 15/84] =?UTF-8?q?wip:=20=EC=A3=BC=EB=AC=B8=20=EC=BB=B4?= =?UTF-8?q?=ED=8F=AC=EB=84=8C=ED=8A=B8=EC=97=90=20=EA=B8=B0=ED=83=80?= =?UTF-8?q?=EC=B6=94=EA=B0=80=ED=95=98=EA=B3=A0=20=EC=A3=BC=EC=86=8C=20?= =?UTF-8?q?=EC=84=A0=ED=83=9D=ED=95=9C=20=EA=B2=BD=EC=9A=B0=EC=97=90?= =?UTF-8?q?=EB=8A=94=20readonly?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 서버코드 수정해야되서 그냥 막해놓음. 서버리팩토링받고나서 서버수정하고 프론트수정할예정 --- client/src/components/order/index.tsx | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/client/src/components/order/index.tsx b/client/src/components/order/index.tsx index 5730029..ae838ad 100644 --- a/client/src/components/order/index.tsx +++ b/client/src/components/order/index.tsx @@ -1,5 +1,6 @@ import React, { useState, Fragment, FC, Dispatch, SetStateAction } from 'react'; import styled from 'lib/woowahan-components'; +import { Link } from 'lib/router'; import { TextButton, CheckBox, GridForm, PriceCalculator } from 'components'; import TableSection, { OrderItem } from './table-section'; @@ -147,7 +148,7 @@ const Order: FC = ({
배송정보 - + {addresses.map(address => { return ( @@ -161,13 +162,33 @@ const Order: FC = ({ /> ); })} + - + {receiverError} - + {addressError} From 5c3e59aabc1990067a64c4b44611d6dd19a5e01e Mon Sep 17 00:00:00 2001 From: yoonminsang Date: Sat, 28 Aug 2021 19:25:33 +0900 Subject: [PATCH 16/84] =?UTF-8?q?wip:=20=EC=95=84=EC=9D=B4=ED=85=9C=20?= =?UTF-8?q?=EC=83=81=EC=84=B8=20count=20=EC=A1=B0=EC=A0=95=20=EC=84=B8?= =?UTF-8?q?=EB=A1=9C=EC=97=90=EC=84=9C=20=EA=B0=80=EB=A1=9C=EB=A1=9C=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 모바일에서 세로로하면 터치가 너무 힘듬. 그렇다고 마진을 주거나 너무 크게해도 이상해짐 - 다른 앱을 보니 가로로 count를 조정하고 있음. - ui 이상하면 말해주세요 --- .../components/item-detail/item-counter.tsx | 57 +++++++++---------- 1 file changed, 26 insertions(+), 31 deletions(-) diff --git a/client/src/components/item-detail/item-counter.tsx b/client/src/components/item-detail/item-counter.tsx index f35f787..d90aef8 100644 --- a/client/src/components/item-detail/item-counter.tsx +++ b/client/src/components/item-detail/item-counter.tsx @@ -14,14 +14,9 @@ const Container = styled.div` background-color: ${({ theme }) => theme?.colorFooter}; border-radius: 17px; display: flex; - align-items: center; - justify-content: space-between; + flex-direction: column; padding: 15px 30px; - .title { - flex: 1; - } - ${({ theme }) => theme?.mobile} { flex-direction: column; @@ -33,44 +28,38 @@ const Container = styled.div` font-size: 14px; } } + + .price { + margin-top: 20px; + font-weight: ${props => props.theme?.weightBold}; + font-size: 18px; + } `; const Counter = styled.div` display: flex; align-items: center; - .count { - margin-right: 24px; - } - - .price { - text-overflow: clip; - text-align: end; + margin: 0 15px; } ${({ theme }) => theme?.mobile} { align-self: flex-end; } -`; - -const ButtonBox = styled.div` - display: flex; - flex-direction: column; - align-items: center; - margin-right: 24px; button { background: ${({ theme }) => theme?.colorPointBeigeLight}; - width: 24px; - height: 20px; + width: 34px; + height: 30px; + font-size: 20px; &:first-child { border-top-left-radius: 5px; - border-top-right-radius: 5px; + border-bottom-left-radius: 5px; } &:last-child { - border-bottom-left-radius: 5px; + border-top-right-radius: 5px; border-bottom-right-radius: 5px; } @@ -80,6 +69,12 @@ const ButtonBox = styled.div` } `; +const Flex = styled.div` + display: flex; + align-items: center; + justify-content: space-between; +`; + const ItemCounter: FC = ({ title, price, onChange }: ItenCounterProps) => { const [count, setCount] = useState(1); @@ -93,19 +88,19 @@ const ItemCounter: FC = ({ title, price, onChange }: ItenCount return ( -
{title}
- -
{count}
- + +
{title}
+ +
{count}
-
-
{formatPrice(count * price)}원
-
+ + +
{formatPrice(count * price)}원
); }; From f9a2f17c3d7e247c62d168934afabf3d9e29f105 Mon Sep 17 00:00:00 2001 From: yoonminsang Date: Sat, 28 Aug 2021 19:33:05 +0900 Subject: [PATCH 17/84] =?UTF-8?q?fix:=20=EC=A3=BC=EB=AC=B8=ED=95=98?= =?UTF-8?q?=EA=B8=B0=EC=97=90=EC=84=9C=20=EA=B8=B0=EB=B3=B8=20=EB=B0=B0?= =?UTF-8?q?=EC=86=A1=EC=A7=80=EB=A5=BC=20=EA=B8=B0=ED=83=80=EB=A1=9C=20?= =?UTF-8?q?=EC=84=A4=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/containers/order-container.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/containers/order-container.tsx b/client/src/containers/order-container.tsx index 07065f9..7b9f98e 100644 --- a/client/src/containers/order-container.tsx +++ b/client/src/containers/order-container.tsx @@ -57,7 +57,7 @@ const OrderContainer: FC = () => { const [user, setUser] = useState(''); const [receiver, setReceiver] = useState(''); const [address, setAddress] = useState(''); - const [addressChecked, setaddressChecked] = useState(''); + const [addressChecked, setaddressChecked] = useState('기타'); const { userId, submitError, itemsData, getLoading, submitLoading, addresses } = useSelector( ({ auth, order, loading, address }: RootState) => ({ userId: auth.user.userId || '', From 55cd928fee2ef6a9a9f36fa57c5f4c5fb470304c Mon Sep 17 00:00:00 2001 From: yoonminsang Date: Sat, 28 Aug 2021 19:45:35 +0900 Subject: [PATCH 18/84] =?UTF-8?q?feat:=20=EC=A3=BC=EB=AC=B8=ED=95=98?= =?UTF-8?q?=EA=B8=B0=20focusout=20=EB=B0=8F=20validation=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/components/order/index.tsx | 10 ++++++---- client/src/containers/order-container.tsx | 5 +++++ 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/client/src/components/order/index.tsx b/client/src/components/order/index.tsx index ae838ad..1c9c649 100644 --- a/client/src/components/order/index.tsx +++ b/client/src/components/order/index.tsx @@ -1,6 +1,5 @@ -import React, { useState, Fragment, FC, Dispatch, SetStateAction } from 'react'; +import React, { useState, FC, Dispatch, SetStateAction } from 'react'; import styled from 'lib/woowahan-components'; -import { Link } from 'lib/router'; import { TextButton, CheckBox, GridForm, PriceCalculator } from 'components'; import TableSection, { OrderItem } from './table-section'; @@ -25,6 +24,7 @@ interface OrderProps { addresses: { name: string; address: string }[]; pickAddress: (e: React.ChangeEvent) => void; addressChecked: string; + onFocusOutPhone: () => void; } const SectionTitle = styled.h4` @@ -105,8 +105,10 @@ const Order: FC = ({ addresses, pickAddress, addressChecked, + onFocusOutPhone, }) => { const [agreed, setAgreed] = useState(false); + const agr = agreed && user && phone && address && addresses; const onChangePhone = (e: React.ChangeEvent) => { const { value } = e.target; @@ -143,7 +145,7 @@ const Order: FC = ({ {userError} - + {phoneError}
@@ -209,7 +211,7 @@ const Order: FC = ({ - + {submitError} diff --git a/client/src/containers/order-container.tsx b/client/src/containers/order-container.tsx index 7b9f98e..012292d 100644 --- a/client/src/containers/order-container.tsx +++ b/client/src/containers/order-container.tsx @@ -145,6 +145,10 @@ const OrderContainer: FC = () => { localStorage.setItem('cart', cartItemsString); }; + const onFocusOutPhone = () => { + if (phoneValidation(phone)) setPhoneError(phoneValidation(phone)); + }; + const onSubmit = (e: React.FormEvent) => { e.preventDefault(); @@ -207,6 +211,7 @@ const OrderContainer: FC = () => { addresses={addresses} pickAddress={pickAddress} addressChecked={addressChecked} + onFocusOutPhone={onFocusOutPhone} /> ); }; From 6924f7d8b085326df4e30e87661f36f4de1d8dc5 Mon Sep 17 00:00:00 2001 From: negu63 Date: Sat, 28 Aug 2021 20:04:39 +0900 Subject: [PATCH 19/84] =?UTF-8?q?fix:=20=EC=8A=A4=EB=A7=88=ED=8A=B8=20?= =?UTF-8?q?=EB=A9=94=EB=89=B4=20=EC=9E=91=EB=8F=99=EB=B0=A9=EC=8B=9D=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/components/smart-menu/index.tsx | 22 +++++++------ .../src/components/smart-menu/large-menu.tsx | 32 ++++++++++++++----- .../src/components/smart-menu/medium-menu.tsx | 11 +++++-- 3 files changed, 45 insertions(+), 20 deletions(-) diff --git a/client/src/components/smart-menu/index.tsx b/client/src/components/smart-menu/index.tsx index 3539080..b17f436 100644 --- a/client/src/components/smart-menu/index.tsx +++ b/client/src/components/smart-menu/index.tsx @@ -6,7 +6,8 @@ import useWindowSize from 'hooks/use-window-size'; import { IMenu } from 'types/category'; -import { SMART_MENU_LARGE_WIDTH, SMART_MENU_SMALL_WIDTH, SMART_MENU_BLOCK_DELAY } from 'constants/index'; +import { SMART_MENU_BLOCK_DELAY } from 'constants/index'; +import { isLaptop, isSmall } from 'utils/checkWidth'; import LargeMenu from './large-menu'; import MediumMenu from './medium-menu'; @@ -53,14 +54,6 @@ const MenuTitle = styled.div` } `; -const isLaptop = (width: number) => { - return width >= SMART_MENU_LARGE_WIDTH; -}; - -const isSmall = (width: number) => { - return width <= SMART_MENU_SMALL_WIDTH; -}; - const SmartMenu: FC = ({ currentMenu, menu }) => { const [isOpen, setOpenStatus] = useState(false); const [selectedLargeId, setLargeId] = useState(''); @@ -80,7 +73,9 @@ const SmartMenu: FC = ({ currentMenu, menu }) => { return ( { - setOpenStatus(true); + if (isLaptop(width)) { + setOpenStatus(true); + } }} onMouseLeave={() => { setOpenStatus(false); @@ -90,6 +85,11 @@ const SmartMenu: FC = ({ currentMenu, menu }) => { setLargeId(''); }, SMART_MENU_BLOCK_DELAY); }} + onClick={() => { + if (isSmall(width)) { + setOpenStatus(!isOpen); + } + }} > {isOpen && ( = ({ currentMenu, menu }) => { selectedLargeId={selectedLargeId} isLaptop={isLaptop(width)} setLargeId={setLargeId} + setMediumId={setMediumId} setPosition={setPosition} /> )} @@ -106,6 +107,7 @@ const SmartMenu: FC = ({ currentMenu, menu }) => { menu={menu} selectedLargeId={selectedLargeId} selectedMediumId={selectedMediumId} + isLaptop={isLaptop(width)} setMediumId={setMediumId} /> )} diff --git a/client/src/components/smart-menu/large-menu.tsx b/client/src/components/smart-menu/large-menu.tsx index 0d579c8..7b56fa9 100644 --- a/client/src/components/smart-menu/large-menu.tsx +++ b/client/src/components/smart-menu/large-menu.tsx @@ -15,6 +15,7 @@ interface LargeMenuProps { selectedLargeId: string; isLaptop: boolean; setLargeId: React.Dispatch>; + setMediumId: React.Dispatch>; setPosition: React.Dispatch< React.SetStateAction<{ x: number; @@ -90,7 +91,15 @@ const Image = styled.img` } `; -const LargeMenu: FC = ({ menu, position, selectedLargeId, isLaptop, setLargeId, setPosition }) => { +const LargeMenu: FC = ({ + menu, + position, + selectedLargeId, + isLaptop, + setLargeId, + setMediumId, + setPosition, +}) => { const history = useHistory(); const goCategoryPage = useCallback( (code: string) => () => history.push(`${ITEM_LIST_URL}?categoryId=${code}`), @@ -106,19 +115,26 @@ const LargeMenu: FC = ({ menu, position, selectedLargeId, isLapt { - setTimeout(() => { - if (e.clientX < position.x + 10) { - setLargeId(largeId); - } - setPosition({ x: e.clientX, y: e.clientY }); - }, SMART_MENU_BLOCK_DELAY); + if (isLaptop) { + setMediumId(''); + setTimeout(() => { + if (e.clientX < position.x + 10) { + setLargeId(largeId); + } + setPosition({ x: e.clientX, y: e.clientY }); + }, SMART_MENU_BLOCK_DELAY); + } }} - onClick={() => { + onClick={(e: React.MouseEvent) => { if (!isLaptop) { setLargeId(largeId); + e.stopPropagation(); + } else { + history.push(`${ITEM_LIST_URL}?categoryId=${large.code}`); } }} isSelected={selectedLargeId === largeId} + isLaptop={isLaptop} > {large.name} diff --git a/client/src/components/smart-menu/medium-menu.tsx b/client/src/components/smart-menu/medium-menu.tsx index 43c81b4..a094732 100644 --- a/client/src/components/smart-menu/medium-menu.tsx +++ b/client/src/components/smart-menu/medium-menu.tsx @@ -12,6 +12,7 @@ interface MediumMenuProps { menu: IMenu; selectedLargeId: string; selectedMediumId: string; + isLaptop: boolean; setMediumId: React.Dispatch>; } @@ -73,7 +74,7 @@ const Image = styled.img` } `; -const MediumMenu: FC = ({ menu, selectedLargeId, selectedMediumId, setMediumId }) => { +const MediumMenu: FC = ({ menu, selectedLargeId, selectedMediumId, isLaptop, setMediumId }) => { const history = useHistory(); const goCategoryPage = useCallback( (code: string) => () => history.push(`${ITEM_LIST_URL}?categoryId=${code}`), @@ -90,7 +91,13 @@ const MediumMenu: FC = ({ menu, selectedLargeId, selectedMedium { - setMediumId(mediumId); + if (isLaptop) { + setMediumId(mediumId); + e.stopPropagation(); + } + }} + onClick={(e: React.MouseEvent) => { + history.push(`${ITEM_LIST_URL}?categoryId=${medium.code}`); e.stopPropagation(); }} isSelected={selectedMediumId === mediumId} From 4a378be7da00322c0bf32abf235e22e26d5d538b Mon Sep 17 00:00:00 2001 From: negu63 Date: Sat, 28 Aug 2021 20:11:22 +0900 Subject: [PATCH 20/84] =?UTF-8?q?refactor:=20=ED=99=94=EB=A9=B4=20?= =?UTF-8?q?=ED=81=AC=EA=B8=B0=20=EC=B2=B4=ED=81=AC=20=ED=95=A8=EC=88=98=20?= =?UTF-8?q?=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/utils/checkWidth.ts | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 client/src/utils/checkWidth.ts diff --git a/client/src/utils/checkWidth.ts b/client/src/utils/checkWidth.ts new file mode 100644 index 0000000..22f90b1 --- /dev/null +++ b/client/src/utils/checkWidth.ts @@ -0,0 +1,11 @@ +import { SMART_MENU_LARGE_WIDTH, SMART_MENU_SMALL_WIDTH } from 'constants/index'; + +const isLaptop = (width: number): boolean => { + return width >= SMART_MENU_LARGE_WIDTH; +}; + +const isSmall = (width: number): boolean => { + return width <= SMART_MENU_SMALL_WIDTH; +}; + +export { isLaptop, isSmall }; From 0cc054c36b8c537db38f8047ac07efa68d2597c4 Mon Sep 17 00:00:00 2001 From: negu63 Date: Sat, 28 Aug 2021 20:13:19 +0900 Subject: [PATCH 21/84] =?UTF-8?q?fix:=20=EC=9E=A5=EB=B0=94=EA=B5=AC?= =?UTF-8?q?=EB=8B=88=20=EC=82=AD=EC=A0=9C=20=EB=B2=84=EA=B7=B8=20=EB=B0=8F?= =?UTF-8?q?=20=EC=A0=84=EC=B2=B4=20=EC=84=A0=ED=83=9D=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/components/cart/index.tsx | 40 +++++++++++++++++--- client/src/components/cart/table-section.tsx | 21 +--------- 2 files changed, 37 insertions(+), 24 deletions(-) diff --git a/client/src/components/cart/index.tsx b/client/src/components/cart/index.tsx index a0752ca..0a74277 100644 --- a/client/src/components/cart/index.tsx +++ b/client/src/components/cart/index.tsx @@ -1,4 +1,4 @@ -import React, { useState, useCallback, Fragment, FC } from 'react'; +import React, { useState, useCallback, Fragment, FC, useEffect } from 'react'; import { useSelector } from 'react-redux'; import styled from 'lib/woowahan-components'; import { useHistory } from 'lib/router'; @@ -48,12 +48,19 @@ const OrderButtonDiv = styled.div` gap: 10px; `; +const getCartItemIndexes = () => { + const cartItems = cartGenerator(); + const indexes: number[] = []; + cartItems.forEach((item, index) => indexes.push(index)); + return indexes; +}; + const Cart: FC = () => { const [prices, setPrices] = useState([0]); const [totalCount, setTotalCount] = useState(0); const [cartItems, setCartItems] = useState(cartGenerator()); - const [checkAll, setCheckAll] = useState(false); - const [checkedItems, setCheckedItems] = useState(new Set()); + const [checkAll, setCheckAll] = useState(true); + const [checkedItems, setCheckedItems] = useState(new Set(getCartItemIndexes())); const [modalVisible, setModalVisible] = useState(false); const history = useHistory(); @@ -104,12 +111,36 @@ const Cart: FC = () => { const onClickOrder = (isAll: boolean) => () => { if (userId) { + localStorage.removeItem('select'); orderCartItem(isAll); } else { setModalVisible(true); } }; + const updatePrice = useCallback( + (set: Set) => { + const cartItems = cartGenerator(); + const prices = [] as number[]; + let totalCount = 0; + Array.from(set).forEach(index => { + const item = cartItems[Number(index)]; + prices.push(item.price * item.count); + totalCount += item.count; + }); + if (prices.length === 0) { + prices.push(0); + } + setPrices(prices); + setTotalCount(totalCount); + }, + [setPrices, setTotalCount], + ); + + useEffect(() => { + updatePrice(checkedItems); + }, [updatePrice, checkedItems]); + return ( <> @@ -117,8 +148,7 @@ const Cart: FC = () => { cartItems={cartItems} checkedItems={checkedItems} checkAll={checkAll} - setPrices={setPrices} - setTotalCount={setTotalCount} + updatePrice={updatePrice} setCheckAll={setCheckAll} setCheckedItems={setCheckedItems} /> diff --git a/client/src/components/cart/table-section.tsx b/client/src/components/cart/table-section.tsx index 4b163c5..22733f1 100644 --- a/client/src/components/cart/table-section.tsx +++ b/client/src/components/cart/table-section.tsx @@ -13,8 +13,7 @@ interface TableSectionProps { cartItems: CartItem[]; checkedItems: Set; checkAll: boolean; - setPrices: React.Dispatch>; - setTotalCount: React.Dispatch>; + updatePrice: (set: Set) => void; setCheckAll: React.Dispatch>; setCheckedItems: React.Dispatch>>; } @@ -72,26 +71,10 @@ const TableSection: FC = ({ cartItems, checkedItems, checkAll, - setPrices, - setTotalCount, + updatePrice, setCheckAll, setCheckedItems, }) => { - const updatePrice = (set: Set) => { - const prices = [] as number[]; - let totalCount = 0; - Array.from(set).forEach(index => { - const item = cartItems[Number(index)]; - prices.push(item.price * item.count); - totalCount += item.count; - }); - if (prices.length === 0) { - prices.push(0); - } - setPrices(prices); - setTotalCount(totalCount); - }; - const checkedItemHandler = (id: number) => () => { const checkedSet = new Set(checkedItems); if (checkedSet.has(id)) { From e90878a1bb5588f004f78485258229c5d6c91340 Mon Sep 17 00:00:00 2001 From: yoonminsang Date: Sat, 28 Aug 2021 20:18:26 +0900 Subject: [PATCH 22/84] =?UTF-8?q?fix:=20=EC=95=84=EC=9D=B4=ED=85=9C=20?= =?UTF-8?q?=EC=B9=B4=EC=9A=B4=ED=84=B0=20ui=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - ui너무어렵다.. --- .../src/components/item-detail/item-counter.tsx | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/client/src/components/item-detail/item-counter.tsx b/client/src/components/item-detail/item-counter.tsx index d90aef8..4ae822a 100644 --- a/client/src/components/item-detail/item-counter.tsx +++ b/client/src/components/item-detail/item-counter.tsx @@ -14,12 +14,15 @@ const Container = styled.div` background-color: ${({ theme }) => theme?.colorFooter}; border-radius: 17px; display: flex; - flex-direction: column; + align-items: center; + justify-content: space-between; padding: 15px 30px; + margin-top: 15px; ${({ theme }) => theme?.mobile} { flex-direction: column; - + justify-content: normal; + align-items: normal; .title { align-self: flex-start; width: 100%; @@ -30,14 +33,15 @@ const Container = styled.div` } .price { - margin-top: 20px; font-weight: ${props => props.theme?.weightBold}; font-size: 18px; + margin-left: 15px; } `; const Counter = styled.div` display: flex; + justify-content: flex-end; align-items: center; .count { margin: 0 15px; @@ -73,6 +77,9 @@ const Flex = styled.div` display: flex; align-items: center; justify-content: space-between; + ${props => props.theme?.mobile} { + justify-content: flex-end; + } `; const ItemCounter: FC = ({ title, price, onChange }: ItenCounterProps) => { @@ -88,8 +95,8 @@ const ItemCounter: FC = ({ title, price, onChange }: ItenCount return ( +
{title}
-
{title}
+
{formatPrice(count * price)}원
-
{formatPrice(count * price)}원
); }; From e92ba30b8f9f95ffac331287cd5c70384195293c Mon Sep 17 00:00:00 2001 From: negu63 Date: Sat, 28 Aug 2021 20:26:43 +0900 Subject: [PATCH 23/84] =?UTF-8?q?fix:=20=EC=84=A0=ED=83=9D=20=EC=83=81?= =?UTF-8?q?=ED=83=9C=20=EB=88=84=EB=9D=BD=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/components/cart/index.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/client/src/components/cart/index.tsx b/client/src/components/cart/index.tsx index 0a74277..c28535d 100644 --- a/client/src/components/cart/index.tsx +++ b/client/src/components/cart/index.tsx @@ -139,6 +139,7 @@ const Cart: FC = () => { useEffect(() => { updatePrice(checkedItems); + localStorage.setItem('select', Array.from(checkedItems).join(',')); }, [updatePrice, checkedItems]); return ( From 6b639479dc035085251baa32cd7187f11a00abc5 Mon Sep 17 00:00:00 2001 From: edegiil Date: Thu, 26 Aug 2021 16:31:54 +0900 Subject: [PATCH 24/84] =?UTF-8?q?refactor:=20validation=20empty=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server/src/validation/address.ts | 5 ++++- server/src/validation/auth.ts | 2 ++ server/src/validation/orders.ts | 6 +++--- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/server/src/validation/address.ts b/server/src/validation/address.ts index 1e00b66..914999b 100644 --- a/server/src/validation/address.ts +++ b/server/src/validation/address.ts @@ -28,6 +28,7 @@ export const addAddressValidation = ( .min(ADDRESS.NAME_MIN_LENGTH) .max(ADDRESS.NAME_MAX_LENGTH) .required() + .empty('') .messages({ 'string.min': `이름은 ${ADDRESS.NAME_MIN_LENGTH}자 이상 입력해야 합니다.`, 'string.max': `이름은 ${ADDRESS.NAME_MAX_LENGTH}자를 넘길 수 없습니다.`, @@ -37,6 +38,7 @@ export const addAddressValidation = ( .min(ADDRESS.RECEIVER_MIN_LENGTH) .max(ADDRESS.RECEIVER_MAX_LENGTH) .required() + .empty('') .messages({ 'string.min': `받는분은 ${ADDRESS.RECEIVER_MIN_LENGTH}자 이상 입력해야 합니다.`, 'string.max': `받는분은 ${ADDRESS.RECEIVER_MIN_LENGTH}자를 넘길 수 없습니다.`, @@ -46,6 +48,7 @@ export const addAddressValidation = ( .min(ADDRESS.ADDRESS_MIN_LENGTH) .max(ADDRESS.ADDRESS_MAX_LENGTH) .required() + .empty('') .messages({ 'string.min': `주소는 ${ADDRESS.ADDRESS_MIN_LENGTH}자 이상 입력해야 합니다.`, 'string.max': `주소는 ${ADDRESS.ADDRESS_MAX_LENGTH}자를 넘길 수 없습니다.`, @@ -78,7 +81,7 @@ export const removeAddressValidation = ( ): void => { try { const schema = Joi.object({ - id: Joi.number().min(1).required().messages({ + id: Joi.number().min(1).required().empty('').messages({ 'any.required': '아이디를 입력해주세요.', }), }); diff --git a/server/src/validation/auth.ts b/server/src/validation/auth.ts index aa263ec..eb5bb00 100644 --- a/server/src/validation/auth.ts +++ b/server/src/validation/auth.ts @@ -13,6 +13,7 @@ export const authValidation = (req: Request, res: Response, next: NextFunction): .min(USER.ID_MIN_LENGTH) .max(USER.ID_MAX_LENGTH) .required() + .empty('') .messages({ 'string.min': `아이디는 ${USER.ID_MIN_LENGTH}자 이상 입력해야 합니다`, 'string.max': `아이디는 ${USER.ID_MAX_LENGTH}자를 넘길 수 없습니다`, @@ -22,6 +23,7 @@ export const authValidation = (req: Request, res: Response, next: NextFunction): .max(USER.PASSWORD_MAX_LENGTH) .min(USER.PASSWORD_MIN_LENGTH) .required() + .empty('') .messages({ 'string.min': `비밀번호는 ${USER.PASSWORD_MIN_LENGTH}자 이상 입력해야 합니다`, 'string.max': `비밀번호는 ${USER.PASSWORD_MAX_LENGTH}자를 넘길 수 없습니다`, diff --git a/server/src/validation/orders.ts b/server/src/validation/orders.ts index c46984a..97be888 100644 --- a/server/src/validation/orders.ts +++ b/server/src/validation/orders.ts @@ -21,15 +21,15 @@ export const getOrdersValidation = ( ): void => { try { const schema = Joi.object({ - pageId: Joi.number().required().messages({ + pageId: Joi.number().required().empty('').messages({ 'any.required': '페이지 아이디가 없습니다.', }), - prevDate: Joi.string().min(10).max(10).required().messages({ + prevDate: Joi.string().min(10).max(10).required().empty('').messages({ 'string.min': `올바르지 않은 형식입니다`, 'string.max': `올바르지 않은 형식입니다`, 'any.required': `이전 날짜가 없습니다`, }), - currentDate: Joi.string().max(10).min(10).required().messages({ + currentDate: Joi.string().max(10).min(10).required().empty('').messages({ 'string.min': `올바르지 않은 형식입니다`, 'string.max': `올바르지 않은 형식입니다`, 'any.required': `현재 날짜가 없습니다`, From bb737b4d7a684c157d944eaa382c2e18b0fd7ba4 Mon Sep 17 00:00:00 2001 From: edegiil Date: Thu, 26 Aug 2021 16:32:52 +0900 Subject: [PATCH 25/84] =?UTF-8?q?chore:=20=ED=85=8C=EC=8A=A4=ED=8A=B8?= =?UTF-8?q?=EC=9A=A9=20=EC=BD=94=EB=93=9C=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server/src/routes/auth/index.ts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/server/src/routes/auth/index.ts b/server/src/routes/auth/index.ts index a10a7b3..69dff45 100644 --- a/server/src/routes/auth/index.ts +++ b/server/src/routes/auth/index.ts @@ -1,7 +1,6 @@ import { Router } from 'express'; import { signIn, checkAuth, signOut } from 'controllers/auth'; -import validateToken from 'middlewares/validateToken'; import { authValidation } from 'validation/auth'; import github from './github'; @@ -13,8 +12,5 @@ router.use('/github', github); router.post('/', authValidation, signIn); router.get('/', checkAuth); router.delete('/', signOut); -router.get('/test', validateToken, (req, res) => { - res.status(200).json({ message: 'validateToken 미들웨어 테스트 성공' }); -}); export default router; From 06812c754c469541a22deb240392721bd5810a56 Mon Sep 17 00:00:00 2001 From: edegiil Date: Thu, 26 Aug 2021 17:04:59 +0900 Subject: [PATCH 26/84] =?UTF-8?q?refactor:=20=EB=B6=88=ED=95=84=EC=9A=94?= =?UTF-8?q?=ED=95=9C=20req=20=ED=83=80=EC=9E=85=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server/src/controllers/address.ts | 12 +++--------- server/src/controllers/items.ts | 2 +- server/src/controllers/orders.ts | 2 +- server/src/validation/address.ts | 4 ++-- server/src/validation/orders.ts | 2 +- 5 files changed, 8 insertions(+), 14 deletions(-) diff --git a/server/src/controllers/address.ts b/server/src/controllers/address.ts index 0eb3c67..83529b5 100644 --- a/server/src/controllers/address.ts +++ b/server/src/controllers/address.ts @@ -15,7 +15,7 @@ interface IRemoveReqBody { }; } -export const getAddress = async (req: Request, res: Response): Promise => { +export const getAddress = async (req: Request, res: Response): Promise => { const token = getAccessToken(req.headers.authorization); const { uid } = decodeToken('access', token); try { @@ -28,10 +28,7 @@ export const getAddress = async (req: Request, - res: Response, -): Promise => { +export const addAddress = async (req: Request, res: Response): Promise => { const token = getAccessToken(req.headers.authorization); const { uid } = decodeToken('access', token); const { name, receiver, address } = req.body; @@ -45,10 +42,7 @@ export const addAddress = async ( } }; -export const removeAddress = async ( - req: Request, - res: Response, -): Promise => { +export const removeAddress = async (req: Request, res: Response): Promise => { const token = getAccessToken(req.headers.authorization); const { uid } = decodeToken('access', token); const { id } = req.body.data; diff --git a/server/src/controllers/items.ts b/server/src/controllers/items.ts index 91139a4..534be3b 100644 --- a/server/src/controllers/items.ts +++ b/server/src/controllers/items.ts @@ -52,7 +52,7 @@ export const getItems = async (req: Request, } }; -export const getItem = async (req: Request, res: Response): Promise => { +export const getItem = async (req: Request, res: Response): Promise => { const { id } = req.params; try { let uid; diff --git a/server/src/controllers/orders.ts b/server/src/controllers/orders.ts index 2492c7c..a0cbdcf 100644 --- a/server/src/controllers/orders.ts +++ b/server/src/controllers/orders.ts @@ -35,7 +35,7 @@ export const getOrders = async (req: Request, } }; -export const postOrder = async (req: Request, res: Response): Promise => { +export const postOrder = async (req: Request, res: Response): Promise => { try { const orderItems = req.body; const token = getAccessToken(req.headers.authorization); diff --git a/server/src/validation/address.ts b/server/src/validation/address.ts index 914999b..b28f4f9 100644 --- a/server/src/validation/address.ts +++ b/server/src/validation/address.ts @@ -18,7 +18,7 @@ interface IRemoveReqBody { } export const addAddressValidation = ( - req: Request, + req: Request, res: Response, next: NextFunction, ): void => { @@ -75,7 +75,7 @@ export const addAddressValidation = ( }; export const removeAddressValidation = ( - req: Request, + req: Request, res: Response, next: NextFunction, ): void => { diff --git a/server/src/validation/orders.ts b/server/src/validation/orders.ts index 97be888..855e23b 100644 --- a/server/src/validation/orders.ts +++ b/server/src/validation/orders.ts @@ -55,7 +55,7 @@ export const getOrdersValidation = ( }; export const postOrderValidation = ( - req: Request, + req: Request, res: Response, next: NextFunction, ): void => { From 56cf09f3e882833abfe53ae12da806c8a86955c3 Mon Sep 17 00:00:00 2001 From: edegiil Date: Sun, 29 Aug 2021 00:23:25 +0900 Subject: [PATCH 27/84] =?UTF-8?q?refactor:=20=ED=83=80=EC=9E=85=20?= =?UTF-8?q?=EC=A0=95=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server/src/controllers/address.ts | 12 +----------- server/src/controllers/auth.ts | 17 +++++----------- server/src/services/auth.ts | 24 +---------------------- server/src/types/address.ts | 11 +++++++++++ server/src/types/auth.ts | 32 +++++++++++++++++++++++++++++++ server/src/validation/address.ts | 12 +----------- 6 files changed, 51 insertions(+), 57 deletions(-) create mode 100644 server/src/types/address.ts create mode 100644 server/src/types/auth.ts diff --git a/server/src/controllers/address.ts b/server/src/controllers/address.ts index 83529b5..41cc16d 100644 --- a/server/src/controllers/address.ts +++ b/server/src/controllers/address.ts @@ -3,17 +3,7 @@ import addressService from 'services/address'; import errorHandler from 'utils/error/error-handler'; import { decodeToken, getAccessToken } from 'utils/jwt'; -interface IAddReqBody { - name: string; - receiver: string; - address: string; -} - -interface IRemoveReqBody { - data: { - id: string; - }; -} +import { IAddReqBody, IRemoveReqBody } from 'types/address'; export const getAddress = async (req: Request, res: Response): Promise => { const token = getAccessToken(req.headers.authorization); diff --git a/server/src/controllers/auth.ts b/server/src/controllers/auth.ts index 9d8cb6a..b7d9839 100644 --- a/server/src/controllers/auth.ts +++ b/server/src/controllers/auth.ts @@ -8,18 +8,11 @@ import { getAccessToken, getRefreshToken } from 'utils/jwt'; import { REFRESH_TOKEN_NAME } from 'config/constants'; -interface IReqBody { - id: string; - password: string; -} +import { ISigninReqBody, IGithub } from 'types/auth'; -interface IGithub { - code: string; -} - -export const signIn = async (req: Request, res: Response): Promise => { +export const signIn = async (req: Request, res: Response): Promise => { try { - const { id, password } = req.body as IReqBody; + const { id, password } = req.body; const { accessToken, refreshToken } = await authService.signIn(id, false, password); @@ -65,9 +58,9 @@ export const signInGithub = (req: Request, res: Response): void => { res.redirect(url); }; -export const handleGithubAuth = async (req: Request, res: Response): Promise => { +export const handleGithubAuth = async (req: Request, res: Response): Promise => { try { - const { code } = req.body as IGithub; + const { code } = req.body; const { isUserExists, userId } = await authService.handleGithubAuth(code); if (isUserExists) { diff --git a/server/src/services/auth.ts b/server/src/services/auth.ts index b72c58d..d29ec63 100644 --- a/server/src/services/auth.ts +++ b/server/src/services/auth.ts @@ -7,29 +7,7 @@ import errorGenerator from 'utils/error/error-generator'; import { checkTokenExpiration, decodeToken, createToken } from 'utils/jwt'; import { checkPassword } from 'utils/crypto'; -interface IToken { - accessToken: string; - refreshToken: string; -} - -interface ICheckAuth { - isAccessTokenExpired: boolean; - newAccessToken: string; - userId: string; -} - -interface IHandleGithubAuth { - isUserExists: boolean; - userId: string; -} - -interface IGithubAccessToken { - access_token: string; -} - -interface IGithubId { - login: string; -} +import { IToken, ICheckAuth, IHandleGithubAuth, IGithubAccessToken, IGithubId } from 'types/auth'; async function signIn(userId: string, isOAuth: boolean, password: string): Promise { const userSnapshot = await getUser(userId); diff --git a/server/src/types/address.ts b/server/src/types/address.ts new file mode 100644 index 0000000..fc24d2b --- /dev/null +++ b/server/src/types/address.ts @@ -0,0 +1,11 @@ +export interface IAddReqBody { + name: string; + receiver: string; + address: string; +} + +export interface IRemoveReqBody { + data: { + id: string; + }; +} diff --git a/server/src/types/auth.ts b/server/src/types/auth.ts new file mode 100644 index 0000000..2a1d6f5 --- /dev/null +++ b/server/src/types/auth.ts @@ -0,0 +1,32 @@ +export interface ISigninReqBody { + id: string; + password: string; +} + +export interface IGithub { + code: string; +} + +export interface IToken { + accessToken: string; + refreshToken: string; +} + +export interface ICheckAuth { + isAccessTokenExpired: boolean; + newAccessToken: string; + userId: string; +} + +export interface IHandleGithubAuth { + isUserExists: boolean; + userId: string; +} + +export interface IGithubAccessToken { + access_token: string; +} + +export interface IGithubId { + login: string; +} diff --git a/server/src/validation/address.ts b/server/src/validation/address.ts index b28f4f9..35561c7 100644 --- a/server/src/validation/address.ts +++ b/server/src/validation/address.ts @@ -5,17 +5,7 @@ import { ADDRESS } from 'config/constants'; import errorGenerator from 'utils/error/error-generator'; import errorHandler from 'utils/error/error-handler'; -interface IAddReqBody { - name: string; - receiver: string; - address: string; -} - -interface IRemoveReqBody { - data: { - id: string; - }; -} +import { IAddReqBody, IRemoveReqBody } from 'types/address'; export const addAddressValidation = ( req: Request, From 3a5e214db40c5cc5fe43bcb026253fc9e3af8c1b Mon Sep 17 00:00:00 2001 From: edegiil Date: Sun, 29 Aug 2021 00:38:12 +0900 Subject: [PATCH 28/84] =?UTF-8?q?refactor:=20=EC=B9=B4=ED=85=8C=EA=B3=A0?= =?UTF-8?q?=EB=A6=AC=20=EB=B6=88=EB=9F=AC=EC=98=A4=EA=B8=B0=20API=20?= =?UTF-8?q?=EA=B0=80=EA=B3=B5=20=EA=B3=BC=EC=A0=95=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server/src/repositories/category.ts | 13 +++++++++++-- server/src/services/category.ts | 17 ++++------------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/server/src/repositories/category.ts b/server/src/repositories/category.ts index 004b164..c57b795 100644 --- a/server/src/repositories/category.ts +++ b/server/src/repositories/category.ts @@ -5,8 +5,15 @@ import { CategoryAttributes, CategoryCreationAttributes } from 'models/category' import errorGenerator from 'utils/error/error-generator'; -export const getAllCategories = async (): Promise[]> => { - const categorySnapshot = await db.Category.findAll(); +export type CategoryModel = Model[]; + +const getCategories = async (): Promise => { + const categorySnapshot = await db.Category.findAll({ + attributes: [['id', 'code'], 'name'], + raw: true, + }); + + console.log(categorySnapshot); if (!categorySnapshot || categorySnapshot.length === 0) { throw errorGenerator({ @@ -17,3 +24,5 @@ export const getAllCategories = async (): Promise { - const categories = await getAllCategories(); - - const result = categories.map(category => { - return { code: category.getDataValue('id'), name: category.getDataValue('name') }; - }); +async function getCategories(): Promise { + const categories = await categoryRepository.getCategories(); - return result; + return categories; } export default { getCategories }; From ffe34a2f87523efadadca5fde5001ae425246575 Mon Sep 17 00:00:00 2001 From: edegiil Date: Sun, 29 Aug 2021 00:51:22 +0900 Subject: [PATCH 29/84] =?UTF-8?q?refactor:=20=EC=A2=8B=EC=95=84=EC=9A=94?= =?UTF-8?q?=20API=20=EB=A6=AC=ED=8C=A9=ED=86=A0=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server/src/controllers/like.ts | 21 +++--------- server/src/repositories/like.ts | 44 ++++++++++++++----------- server/src/services/like.ts | 14 ++++---- server/src/utils/error/error-handler.ts | 4 +-- 4 files changed, 38 insertions(+), 45 deletions(-) diff --git a/server/src/controllers/like.ts b/server/src/controllers/like.ts index a4b8bff..b70540b 100644 --- a/server/src/controllers/like.ts +++ b/server/src/controllers/like.ts @@ -3,22 +3,15 @@ import { Request, Response } from 'express'; import likeService from 'services/like'; import errorHandler from 'utils/error/error-handler'; -import errorGenerator from 'utils/error/error-generator'; import { getAccessToken, getUIDFromToken } from 'utils/jwt'; export const addLike = async (req: Request, res: Response): Promise => { try { const uid = getUIDFromToken(getAccessToken(req.headers.authorization)); const itemId = parseInt(req.params.id, 10); - const success = await likeService.addLike(uid, itemId); + await likeService.addLike(uid, itemId); - if (success) res.status(200).json('create like success'); - else { - throw errorGenerator({ - message: 'POST /api/likes - create failed', - code: 'likes/no-create', - }); - } + res.status(200).json(); } catch (err) { console.log(err); const { statusCode, errorMessage } = errorHandler(err); @@ -30,15 +23,9 @@ export const deleteLike = async (req: Request, res: Response): Promise => try { const uid = getUIDFromToken(getAccessToken(req.headers.authorization)); const itemId = parseInt(req.params.id, 10); - const success = await likeService.deleteLike(uid, itemId); + await likeService.deleteLike(uid, itemId); - if (success) res.status(200).json('delete like success'); - else { - throw errorGenerator({ - message: 'DELETE /api/likes - delete failed', - code: 'likes/no-delete', - }); - } + res.status(200).json(); } catch (err) { console.log(err); const { statusCode, errorMessage } = errorHandler(err); diff --git a/server/src/repositories/like.ts b/server/src/repositories/like.ts index f06cd1c..26ada96 100644 --- a/server/src/repositories/like.ts +++ b/server/src/repositories/like.ts @@ -1,30 +1,34 @@ import { db } from 'models'; -export const createLike = async (userId: string, itemId: number): Promise => { - try { - const createResult = await db.Like.create({ - UserId: userId, - ItemId: itemId, - }); +import errorGenerator from 'utils/error/error-generator'; - return createResult !== null; - } catch (err) { - return false; +export const createLike = async (userId: string, itemId: number): Promise => { + const createResult = await db.Like.create({ + UserId: userId, + ItemId: itemId, + }); + + if (!createResult) { + throw errorGenerator({ + message: 'POST /api/likes - create failed', + code: 'likes/fail-to-create', + }); } }; -export const destroyLike = async (userId: string, itemId: number): Promise => { - try { - const destroyResult = await db.Like.destroy({ - where: { - UserId: userId, - ItemId: itemId, - }, - }); +export const destroyLike = async (userId: string, itemId: number): Promise => { + const destroyResult = await db.Like.destroy({ + where: { + UserId: userId, + ItemId: itemId, + }, + }); - return destroyResult === 1; - } catch (err) { - return false; + if (destroyResult !== 1) { + throw errorGenerator({ + message: 'DELETE /api/likes - delete failed', + code: 'likes/fail-to-delete', + }); } }; diff --git a/server/src/services/like.ts b/server/src/services/like.ts index 5496e31..a1220b8 100644 --- a/server/src/services/like.ts +++ b/server/src/services/like.ts @@ -1,15 +1,17 @@ import { createLike, destroyLike, findIsUserLikeItem } from 'repositories/like'; -function addLike(userId: string, itemId: number): Promise { - return createLike(userId, itemId); +async function addLike(userId: string, itemId: number): Promise { + await createLike(userId, itemId); } -function deleteLike(userId: string, itemId: number): Promise { - return destroyLike(userId, itemId); +async function deleteLike(userId: string, itemId: number): Promise { + await destroyLike(userId, itemId); } -function isUserLikeItem(userId: string, itemId: number): Promise { - return findIsUserLikeItem(userId, itemId); +async function isUserLikeItem(userId: string, itemId: number): Promise { + const isLike = await findIsUserLikeItem(userId, itemId); + + return isLike; } export default { addLike, deleteLike, isUserLikeItem }; diff --git a/server/src/utils/error/error-handler.ts b/server/src/utils/error/error-handler.ts index 22e03e5..97d0432 100644 --- a/server/src/utils/error/error-handler.ts +++ b/server/src/utils/error/error-handler.ts @@ -48,12 +48,12 @@ function errorHandler(err: CustomError): ErrorType { return { statusCode: 500, errorMessage: err.customMessage || 'db 오류' }; case 'address/maximun address': return { statusCode: 409, errorMessage: err.customMessage || '배송지는 최대 3개까지 입력할 수 있습니다' }; - case 'likes/no-create': + case 'likes/fail-to-create': return { statusCode: 400, errorMessage: err.customMessage || '존재하지 않는 아이템이거나 이미 좋아요를 누른 아이템입니다.', }; - case 'likes/no-delete': + case 'likes/fail-to-delete': return { statusCode: 400, errorMessage: err.customMessage || '좋아요를 누른 적이 없는 아이템입니다.' }; case 'reviews/user-not-paid': return { statusCode: 403, errorMessage: err.customMessage || '잘못된 요청입니다' }; From 1858547f613efb4a0b2c4a690b4cc5e236f2fd61 Mon Sep 17 00:00:00 2001 From: edegiil Date: Sun, 29 Aug 2021 01:07:56 +0900 Subject: [PATCH 30/84] =?UTF-8?q?refactor:=20orders=20=EB=A6=AC=ED=8C=A9?= =?UTF-8?q?=ED=86=A0=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server/src/repositories/orders.ts | 102 +++++++++++------------- server/src/services/orders.ts | 20 ++++- server/src/utils/error/error-handler.ts | 2 - 3 files changed, 67 insertions(+), 57 deletions(-) diff --git a/server/src/repositories/orders.ts b/server/src/repositories/orders.ts index 3017963..52e8bf9 100644 --- a/server/src/repositories/orders.ts +++ b/server/src/repositories/orders.ts @@ -2,7 +2,7 @@ import { db } from 'models'; import { OrderAttributes, OrderCreationAttributes } from 'models/order'; import { Op, Model, Sequelize } from 'sequelize'; -import { PostOrder } from 'controllers/orders'; +import { OrderList } from 'services/orders'; import errorGenerator from 'utils/error/error-generator'; @@ -23,73 +23,67 @@ const getUserOrders = async ( prevDate: string, currentDate: string, ): Promise => { - const orders = await db.Order.findAll({ - attributes: [ - [Sequelize.fn('date_format', Sequelize.col('Order.createdAt'), '%Y-%m-%d'), 'createdAt'], - [Sequelize.col('Item.id'), 'id'], - [Sequelize.col('Item.thumbnail'), 'thumbnail'], - [Sequelize.col('Item.title'), 'title'], - 'quantity', - [Sequelize.literal(`CASE WHEN status=1 THEN '배송완료' ELSE '주문완료' END`), 'status'], - [ - Sequelize.literal( - 'CASE WHEN Item.salePercent !=0 THEN ROUND(Item.price - (Item.price * Item.salePercent /100),0) ELSE Item.price END', - ), - 'price', + const [orders, totalCount] = await Promise.all([ + db.Order.findAll({ + attributes: [ + [Sequelize.fn('date_format', Sequelize.col('Order.createdAt'), '%Y-%m-%d'), 'createdAt'], + [Sequelize.col('Item.id'), 'id'], + [Sequelize.col('Item.thumbnail'), 'thumbnail'], + [Sequelize.col('Item.title'), 'title'], + 'quantity', + [Sequelize.literal(`CASE WHEN status=1 THEN '배송완료' ELSE '주문완료' END`), 'status'], + [ + Sequelize.literal( + 'CASE WHEN Item.salePercent !=0 THEN ROUND(Item.price - (Item.price * Item.salePercent /100),0) ELSE Item.price END', + ), + 'price', + ], ], - ], - where: { - UserId: uid, - createdAt: { - [Op.gte]: prevDate, - [Op.lte]: currentDate, + where: { + UserId: uid, + createdAt: { + [Op.gte]: prevDate, + [Op.lte]: currentDate, + }, }, - }, - limit: LIMIT_COUNT, - offset: (pageId - 1) * LIMIT_COUNT, - order: [['createdAt', 'DESC']], - include: [ - { - model: db.Item, - attributes: [], + limit: LIMIT_COUNT, + offset: (pageId - 1) * LIMIT_COUNT, + order: [['createdAt', 'DESC']], + include: [ + { + model: db.Item, + attributes: [], + }, + ], + }), + db.Order.count({ + where: { + UserId: uid, + createdAt: { + [Op.gte]: prevDate, + [Op.lte]: currentDate, + }, }, - ], - }); + }), + ]); - const totalCount = await db.Order.count({ - where: { - UserId: uid, - createdAt: { - [Op.gte]: prevDate, - [Op.lte]: currentDate, - }, - }, - }); const pageCount = Math.ceil(totalCount / LIMIT_COUNT); if (!orders) { throw errorGenerator({ - message: 'GET /api/orders - orders not found', - code: 'orders/orders-not-found', + message: 'GET /api/orders - fail to load orders', + code: 'orders/fail-to-load-orders', }); } return { orders, totalCount, pageCount }; }; -const postOrder = async (uid: string, orderItems: PostOrder): Promise => { - const { address, receiver, phone, itemList } = orderItems; - const createQueue = itemList.map(({ quantity, itemId }) => { - return db.Order.create({ - address, - receiver, - quantity, - ItemId: itemId, - UserId: uid, - }); - }); - - await Promise.all([createQueue, db.User.update({ phone }, { where: { id: uid } })]); +const postOrder = async (uid: string, phone: string, orderList: OrderList[]): Promise => { + await Promise.all([ + db.Order.bulkCreate(orderList, { validate: true }), + db.User.update({ phone }, { where: { id: uid } }), + ]); }; const checkPaidUser = async (uid: string, itemId: number): Promise => { diff --git a/server/src/services/orders.ts b/server/src/services/orders.ts index 686de2f..ce616bf 100644 --- a/server/src/services/orders.ts +++ b/server/src/services/orders.ts @@ -1,12 +1,30 @@ import { PostOrder } from 'controllers/orders'; import orderRepisitory, { IOrdersData } from 'repositories/orders'; +export interface OrderList { + address: string; + receiver: string; + quantity: number; + ItemId: number; + UserId: string; +} + async function getOrders(uid: string, pageId = 1, prevDate: string, currentDate: string): Promise { return orderRepisitory.getUserOrders(uid, pageId, prevDate, currentDate); } async function postOrder(uid: string, orderItems: PostOrder): Promise { - await orderRepisitory.postOrder(uid, orderItems); + const { address, receiver, phone, itemList } = orderItems; + + const orderList = itemList.map(({ quantity, itemId }) => ({ + address, + receiver, + quantity, + ItemId: itemId, + UserId: uid, + })); + + await orderRepisitory.postOrder(uid, phone, orderList); } export default { diff --git a/server/src/utils/error/error-handler.ts b/server/src/utils/error/error-handler.ts index 97d0432..921dca1 100644 --- a/server/src/utils/error/error-handler.ts +++ b/server/src/utils/error/error-handler.ts @@ -42,8 +42,6 @@ function errorHandler(err: CustomError): ErrorType { return { statusCode: 404, errorMessage: err.customMessage || '존재하지 않는 상품입니다.' }; case 'item/no-exist-querystring': return { statusCode: 500, errorMessage: err.customMessage || '쿼리스트링을 확인해주세요.' }; - case 'orders/orders-not-found': - return { statusCode: 500, errorMessage: err.customMessage || '주문내역 데이터가 없습니다.' }; case 'address/address-error': return { statusCode: 500, errorMessage: err.customMessage || 'db 오류' }; case 'address/maximun address': From efefb812cdab14bf69aec55625f4c69f77f8c469 Mon Sep 17 00:00:00 2001 From: edegiil Date: Sun, 29 Aug 2021 01:23:56 +0900 Subject: [PATCH 31/84] =?UTF-8?q?refactor:=20=EB=A6=AC=EB=B7=B0=20?= =?UTF-8?q?=EB=A6=AC=ED=8C=A9=ED=86=A0=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server/src/repositories/reviews.ts | 50 ++++++++++++++---------------- server/src/services/reviews.ts | 4 +-- 2 files changed, 26 insertions(+), 28 deletions(-) diff --git a/server/src/repositories/reviews.ts b/server/src/repositories/reviews.ts index 55d888e..a33d96d 100644 --- a/server/src/repositories/reviews.ts +++ b/server/src/repositories/reviews.ts @@ -4,37 +4,34 @@ import { ReviewAttribures, ReviewCreationAttributes } from 'models/review'; import errorGenerator from 'utils/error/error-generator'; -interface ReviewData extends ReviewAttribures { - userId: string; -} - const LIMIT_COUNT = 10; const getReviews = async ( itemId: number, pageId: number, -): Promise<{ reviewData: Model[]; totalCount: number }> => { - const reviewData = (await db.Review.findAll({ - attributes: ['title', 'contents', 'imgUrl', 'score', [Sequelize.col('User.userId'), 'userId']], - where: { - ItemId: itemId, - }, - order: [['createdAt', 'DESC']], - limit: LIMIT_COUNT, - offset: (pageId - 1) * LIMIT_COUNT, - include: [ - { - model: db.User, - attributes: ['userId'], +): Promise<{ reviewData: Model[]; totalCount: number }> => { + const [reviewData, totalCount] = await Promise.all([ + db.Review.findAll({ + attributes: ['title', 'contents', 'imgUrl', 'score', [Sequelize.col('User.UserId'), 'UserId']], + where: { + ItemId: itemId, }, - ], - })) as Model[]; - - const totalCount = await db.Review.count({ - where: { - ItemId: itemId, - }, - }); + order: [['createdAt', 'DESC']], + limit: LIMIT_COUNT, + offset: (pageId - 1) * LIMIT_COUNT, + include: [ + { + model: db.User, + attributes: ['userId'], + }, + ], + }), + db.Review.count({ + where: { + ItemId: itemId, + }, + }), + ]); if (!reviewData) { throw errorGenerator({ @@ -64,7 +61,7 @@ const postReview = async ( contents: string, score: number, imgUrl: string, -): Promise<{ reviewData: Model[]; totalCount: number }> => { +): Promise<{ reviewData: Model[]; totalCount: number }> => { await db.Review.create({ title, contents, @@ -73,6 +70,7 @@ const postReview = async ( ItemId: itemId, UserId: uid, }); + return getReviews(itemId, 1); }; diff --git a/server/src/services/reviews.ts b/server/src/services/reviews.ts index e754ec1..d385883 100644 --- a/server/src/services/reviews.ts +++ b/server/src/services/reviews.ts @@ -53,7 +53,7 @@ async function postReview( score: review.getDataValue('score'), contents: review.getDataValue('contents'), imgUrl: review.getDataValue('imgUrl'), - userId: review.getDataValue('userId'), + userId: review.getDataValue('UserId'), }; }); @@ -75,7 +75,7 @@ async function getReviews(itemId: number, pageId: number): Promise { score: review.getDataValue('score'), contents: review.getDataValue('contents'), imgUrl: review.getDataValue('imgUrl'), - userId: review.getDataValue('userId'), + userId: review.getDataValue('UserId'), }; }); From f3a84b93cc58d2ecc5cd9c7178b5427a312ac544 Mon Sep 17 00:00:00 2001 From: edegiil Date: Sun, 29 Aug 2021 01:29:28 +0900 Subject: [PATCH 32/84] =?UTF-8?q?refactor:=20=EC=9E=90=EB=8F=99=EC=99=84?= =?UTF-8?q?=EC=84=B1=20=ED=82=A4=EC=9B=8C=EB=93=9C=20API?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server/src/controllers/search.ts | 9 +++++++-- server/src/repositories/search.ts | 4 +++- server/src/services/search.ts | 14 ++++++-------- 3 files changed, 16 insertions(+), 11 deletions(-) diff --git a/server/src/controllers/search.ts b/server/src/controllers/search.ts index d75f3b7..e3be3d8 100644 --- a/server/src/controllers/search.ts +++ b/server/src/controllers/search.ts @@ -4,9 +4,14 @@ import searchService from 'services/search'; import errorHandler from 'utils/error/error-handler'; -export const getKeywords = async (req: Request, res: Response): Promise => { +interface ReqQuery { + keyword: string; +} + +export const getKeywords = async (req: Request, res: Response): Promise => { try { - const keywords = await searchService.getKeywords(req); + const { keyword } = req.query; + const keywords = await searchService.getKeywords(keyword); res.status(200).json(keywords); } catch (err) { console.log(err); diff --git a/server/src/repositories/search.ts b/server/src/repositories/search.ts index 9f02716..955f1d4 100644 --- a/server/src/repositories/search.ts +++ b/server/src/repositories/search.ts @@ -4,7 +4,7 @@ import { ItemAttributes, ItemCreationAttributes } from 'models/item'; import errorGenerator from 'utils/error/error-generator'; -export const getAllKeywords = async (regExp: string): Promise[]> => { +const getAllKeywords = async (regExp: string): Promise[]> => { const searchSnapshot = await db.Item.findAll({ attributes: ['title'], where: { @@ -24,3 +24,5 @@ export const getAllKeywords = async (regExp: string): Promise { +async function getKeywords(keyword: string): Promise { const regExp = String( - getRegExp(engToKor(req.query.keyword as string), { + getRegExp(engToKor(keyword), { initialSearch: true, }), ); - const keywords = await getAllKeywords(regExp.substring(0, regExp.length - 2).slice(1)); - const result = keywords.map(keyword => { - return keyword.getDataValue('title'); - }); + const keywords = await searchRepository.getAllKeywords(regExp.substring(0, regExp.length - 2).slice(1)); + const result = keywords.map(v => v.getDataValue('title')); + return result; } From b8e1cd63cb892be804537e4eeac8f15bcc17e372 Mon Sep 17 00:00:00 2001 From: edegiil Date: Sun, 29 Aug 2021 01:31:39 +0900 Subject: [PATCH 33/84] =?UTF-8?q?refactor:=20=ED=9A=8C=EC=9B=90=EA=B0=80?= =?UTF-8?q?=EC=9E=85=20API?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server/src/controllers/user.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/server/src/controllers/user.ts b/server/src/controllers/user.ts index 0b6e246..0bd1fa9 100644 --- a/server/src/controllers/user.ts +++ b/server/src/controllers/user.ts @@ -6,14 +6,14 @@ import errorHandler from 'utils/error/error-handler'; import { REFRESH_TOKEN_NAME } from 'config/constants'; -interface IReqBody { +interface ReqBody { id: string; password: string; } -export const signUp = async (req: Request, res: Response): Promise => { +export const signUp = async (req: Request, res: Response): Promise => { try { - const { id, password } = req.body as IReqBody; + const { id, password } = req.body; const { accessToken, refreshToken, userId } = await userService.signUp(id, false, password); From bd01f4a916e2e5b0e8b8cd19875fc79c77915ff6 Mon Sep 17 00:00:00 2001 From: edegiil Date: Sun, 29 Aug 2021 02:09:09 +0900 Subject: [PATCH 34/84] refactor: item API --- server/src/controllers/items.ts | 12 +++++++--- server/src/models/item.ts | 5 ++-- server/src/repositories/items.ts | 41 ++++++++++++++++++++------------ server/src/services/items.ts | 17 +++++++++++-- 4 files changed, 53 insertions(+), 22 deletions(-) diff --git a/server/src/controllers/items.ts b/server/src/controllers/items.ts index 534be3b..61ec8f4 100644 --- a/server/src/controllers/items.ts +++ b/server/src/controllers/items.ts @@ -23,10 +23,16 @@ export const getMainItems = async (req: Request, res: Response): Promise = const { popularItems, newItems, recommendItems } = await itemService.mainItems(req.body); + const [popularItemsWithLike, newItemsWithLike, recommendItemsWithLike] = await Promise.all([ + itemService.matchUserLikeItem(popularItems.items, uid), + itemService.matchUserLikeItem(newItems.items, uid), + itemService.matchUserLikeItem(recommendItems.items, uid), + ]); + res.status(200).json({ - popularItems: await itemService.matchUserLikeItem(popularItems.items, uid), - newItems: await itemService.matchUserLikeItem(newItems.items, uid), - recommendItems: await itemService.matchUserLikeItem(recommendItems.items, uid), + popularItems: popularItemsWithLike, + newItems: newItemsWithLike, + recommendItems: recommendItemsWithLike, }); } catch (err) { console.log(err); diff --git a/server/src/models/item.ts b/server/src/models/item.ts index fe2974f..35032a5 100644 --- a/server/src/models/item.ts +++ b/server/src/models/item.ts @@ -1,11 +1,11 @@ import { Sequelize, DataTypes, ModelCtor, Model, Optional } from 'sequelize'; export interface ItemAttributes { - id: string; + id: number; title: string; thumbnail: string; contents: string; - price: string | number; + price: number; originalPrice: number; salePercent: number; amount: number; @@ -13,6 +13,7 @@ export interface ItemAttributes { updatedAt: string; CategoryId: string; isNew: boolean; + isBest: boolean; } export type ItemCreationAttributes = Optional; diff --git a/server/src/repositories/items.ts b/server/src/repositories/items.ts index a891248..727664f 100644 --- a/server/src/repositories/items.ts +++ b/server/src/repositories/items.ts @@ -19,23 +19,34 @@ export interface IScore { score: number; } +export interface Item { + id: number; + title: string; + tumbnail: string; + price: number; + salePercent: number; + amount: number; + isGreen: boolean; + isBest: boolean; + updatedAt: string; + isLike: boolean; +} + const LIMIT_COUNT = 12; -const filterItems = (items: Model[]) => { - items.forEach(item => { - const standardDate = new Date(); - standardDate.setMonth(standardDate.getMonth() - 6); - const itemDate = new Date(item.getDataValue('updatedAt')); - if (standardDate < itemDate) item.setDataValue('isNew', true); - - const salePercent = item.getDataValue('salePercent'); - const price = parseInt(item.getDataValue('price') as string, 10); - if (salePercent !== 0) { - item.setDataValue('price', Math.round((price * (100 - salePercent)) / 100)); - item.setDataValue('originalPrice', price); - } - }); -}; +const filterItems = (items: Model[]): Item[] => + items.map(item => ({ + id: item.getDataValue('id'), + title: item.getDataValue('title'), + tumbnail: item.getDataValue('thumbnail'), + price: item.getDataValue('price'), + salePercent: item.getDataValue('salePercent'), + amount: item.getDataValue('amount'), + isGreen: item.getDataValue('isGreen'), + isBest: item.getDataValue('isBest'), + updatedAt: item.getDataValue('updatedAt'), + isLike: false, + })); const getRecommendItems = async (visited: string[], isCategoryItem: boolean): Promise => { if (visited.length > 0) { diff --git a/server/src/services/items.ts b/server/src/services/items.ts index dab25a2..10e419a 100644 --- a/server/src/services/items.ts +++ b/server/src/services/items.ts @@ -26,7 +26,7 @@ export interface IGetItem { } export interface IOrderItem { - id: string; + id: number; title: string; thumbnail: string; price: number; @@ -34,6 +34,19 @@ export interface IOrderItem { export type ItemType = 'recommend' | 'popular' | 'recent' | 'cheap' | 'expensive' | undefined; +export interface Item { + id: number; + title: string; + tumbnail: string; + price: number; + salePercent: number; + amount: number; + isGreen: boolean; + isBest: boolean; + updatedAt: string; + isLike: boolean; +} + async function mainItems(visited: string[]): Promise { const [popularItems, newItems, recommendItems] = await Promise.all([ itemRepository.getMainItems([['saleCount', 'DESC']], 4), @@ -122,7 +135,7 @@ async function matchUserLikeItem( ): Promise { const result = await Promise.all( itemList.map(async item => { - const itemId = parseInt(item.getDataValue('id'), 10); + const itemId = item.getDataValue('id'); return { ...item.toJSON(), isLike: userId ? await likeService.isUserLikeItem(userId, itemId) : false, From 5987f0c9cffe61fb7c4cd0a1bd594a78cc36fde2 Mon Sep 17 00:00:00 2001 From: edegiil Date: Sun, 29 Aug 2021 02:26:34 +0900 Subject: [PATCH 35/84] =?UTF-8?q?refactor:=20=EC=97=90=EB=9F=AC=20?= =?UTF-8?q?=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server/src/repositories/items.ts | 8 +- server/src/services/reviews.ts | 1 - server/src/utils/error/error-handler.ts | 132 +++++++++++++++++++----- server/src/validation/orders.ts | 4 +- 4 files changed, 113 insertions(+), 32 deletions(-) diff --git a/server/src/repositories/items.ts b/server/src/repositories/items.ts index 727664f..6686dd0 100644 --- a/server/src/repositories/items.ts +++ b/server/src/repositories/items.ts @@ -185,7 +185,7 @@ const getCategoryItems = async (pageId: number, order: string[][], categoryReg: if (!items) { throw errorGenerator({ message: 'POST /api/items - items not found', - code: 'items/not-found', + code: 'items/items-not-found', }); } @@ -227,7 +227,7 @@ const getCategoryRecommendItems = async ( if (!items) { throw errorGenerator({ message: 'POST /api/items - items not found', - code: 'items/not-found', + code: 'items/items-not-found', }); } @@ -268,7 +268,7 @@ const getSearchItems = async (pageId: number, order: string[][], regExp: string) if (!items) { throw errorGenerator({ message: 'POST /api/items - items not found', - code: 'items/not-found', + code: 'items/items-not-found', }); } @@ -308,7 +308,7 @@ const getOrderItems = async (itemIDs: string[]): Promise Date: Sun, 29 Aug 2021 02:28:23 +0900 Subject: [PATCH 36/84] =?UTF-8?q?refactor:=20=EC=84=B1=EA=B3=B5=20?= =?UTF-8?q?=EC=9D=91=EB=8B=B5=20=EB=B9=88=20=EA=B0=9D=EC=B2=B4=20=EC=82=AD?= =?UTF-8?q?=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server/src/controllers/auth.ts | 2 +- server/src/controllers/orders.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/server/src/controllers/auth.ts b/server/src/controllers/auth.ts index b7d9839..d4ee0f9 100644 --- a/server/src/controllers/auth.ts +++ b/server/src/controllers/auth.ts @@ -82,5 +82,5 @@ export const handleGithubAuth = async (req: Request, export const signOut = (req: Request, res: Response): void => { res.clearCookie(REFRESH_TOKEN_NAME); - res.status(200).json({}); + res.status(200).json(); }; diff --git a/server/src/controllers/orders.ts b/server/src/controllers/orders.ts index a0cbdcf..845aaa8 100644 --- a/server/src/controllers/orders.ts +++ b/server/src/controllers/orders.ts @@ -43,7 +43,7 @@ export const postOrder = async (req: Request, res: await ordersService.postOrder(uid, orderItems); - res.status(200).json({}); + res.status(200).json(); } catch (err) { console.log(err); const { statusCode, errorMessage } = errorHandler(err); From 5742e31d860f88426fb2f618954a43f3f25d7885 Mon Sep 17 00:00:00 2001 From: yoonminsang Date: Mon, 30 Aug 2021 13:40:45 +0900 Subject: [PATCH 37/84] =?UTF-8?q?fix:=20=EB=B3=80=EC=88=98=EB=AA=85=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/components/order/index.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/src/components/order/index.tsx b/client/src/components/order/index.tsx index 1c9c649..e9e0cf2 100644 --- a/client/src/components/order/index.tsx +++ b/client/src/components/order/index.tsx @@ -108,7 +108,7 @@ const Order: FC = ({ onFocusOutPhone, }) => { const [agreed, setAgreed] = useState(false); - const agr = agreed && user && phone && address && addresses; + const isValid = agreed && user && phone && address && addresses; const onChangePhone = (e: React.ChangeEvent) => { const { value } = e.target; @@ -211,7 +211,7 @@ const Order: FC = ({ - + {submitError} From bf8b4f2092f82398d90aefc3c831be007f7432b9 Mon Sep 17 00:00:00 2001 From: yoonminsang Date: Mon, 30 Aug 2021 13:41:21 +0900 Subject: [PATCH 38/84] =?UTF-8?q?fix:=20=EC=95=84=EC=9D=B4=ED=85=9C?= =?UTF-8?q?=EC=B9=B4=EC=9A=B4=ED=84=B0=20css=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/components/item-detail/item-counter.tsx | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/client/src/components/item-detail/item-counter.tsx b/client/src/components/item-detail/item-counter.tsx index 4ae822a..7bb42c4 100644 --- a/client/src/components/item-detail/item-counter.tsx +++ b/client/src/components/item-detail/item-counter.tsx @@ -53,19 +53,10 @@ const Counter = styled.div` button { background: ${({ theme }) => theme?.colorPointBeigeLight}; - width: 34px; - height: 30px; + width: 28px; + height: 24px; font-size: 20px; - - &:first-child { - border-top-left-radius: 5px; - border-bottom-left-radius: 5px; - } - - &:last-child { - border-top-right-radius: 5px; - border-bottom-right-radius: 5px; - } + border-radius: 5px; &:hover { background: ${({ theme }) => theme?.colorBg}; From 586435d5b44fd24fac4d6e762d771dbd7c81b4cf Mon Sep 17 00:00:00 2001 From: yoonminsang Date: Mon, 30 Aug 2021 13:48:45 +0900 Subject: [PATCH 39/84] =?UTF-8?q?fix:=20=EB=AA=A8=EB=8B=AC=EC=B0=BD=20?= =?UTF-8?q?=ED=81=AC=EA=B8=B0=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/components/common/address-modal.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/client/src/components/common/address-modal.tsx b/client/src/components/common/address-modal.tsx index b95ff9a..45cf4d2 100644 --- a/client/src/components/common/address-modal.tsx +++ b/client/src/components/common/address-modal.tsx @@ -26,6 +26,7 @@ const Modal = styled.div` const ModalInner = styled.div` width: 80%; + max-width: 600px; #__daum__layer_1 { border-radius: 10px; } @@ -38,7 +39,7 @@ const AddressModal: FC = ({ handleComplete, setModal }) => { return ( - + ); From ab887468b15621ad42e020a9dd3a34965b44ebac Mon Sep 17 00:00:00 2001 From: yoonminsang Date: Mon, 30 Aug 2021 14:00:59 +0900 Subject: [PATCH 40/84] =?UTF-8?q?fix:=20gripd=20gap=EC=9D=84=20=EC=82=AC?= =?UTF-8?q?=ED=8C=8C=EB=A6=AC=EC=97=90=EC=84=9C=EB=8F=84=20=EA=B0=80?= =?UTF-8?q?=EB=8A=A5=ED=95=98=EA=B2=8C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/components/my/my-address/my-address-form.tsx | 9 +++++++++ client/src/components/order/index.tsx | 9 +++++++++ 2 files changed, 18 insertions(+) diff --git a/client/src/components/my/my-address/my-address-form.tsx b/client/src/components/my/my-address/my-address-form.tsx index d18d18a..49e6251 100644 --- a/client/src/components/my/my-address/my-address-form.tsx +++ b/client/src/components/my/my-address/my-address-form.tsx @@ -38,6 +38,15 @@ const InputWrapper = styled.div` const InputErrorMessage = styled.div` font-size: 12px; color: ${({ theme }) => theme?.colorError}; + margin: 0 0 0 10px; + ${({ theme }) => theme?.tablet} { + @media all and (max-width: 741px) { + margin: 5px 40px 0 0; + } + } + ${({ theme }) => theme?.mobile} { + margin: 5px 0 0 0; + } `; const ButtonWrapper = styled.div` diff --git a/client/src/components/order/index.tsx b/client/src/components/order/index.tsx index e9e0cf2..364f28d 100644 --- a/client/src/components/order/index.tsx +++ b/client/src/components/order/index.tsx @@ -74,6 +74,15 @@ const InputWrapper = styled.div` const InputErrorMessage = styled.div` font-size: 12px; color: ${({ theme }) => theme?.colorError}; + margin: 0 0 0 10px; + ${({ theme }) => theme?.tablet} { + @media all and (max-width: 741px) { + margin: 5px 40px 0 0; + } + } + ${({ theme }) => theme?.mobile} { + margin: 5px 0 0 0; + } `; const SubmitErrorMessage = styled.div` From 045617912b41ca157e64150cb86176bcd218dbb1 Mon Sep 17 00:00:00 2001 From: negu63 Date: Mon, 30 Aug 2021 14:06:39 +0900 Subject: [PATCH 41/84] =?UTF-8?q?feat:=20=EB=AA=A8=EB=B0=94=EC=9D=BC=20?= =?UTF-8?q?=EC=B2=B4=ED=81=AC=20=EC=9C=A0=ED=8B=B8=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/utils/checkWidth.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/client/src/utils/checkWidth.ts b/client/src/utils/checkWidth.ts index 22f90b1..7e2dce3 100644 --- a/client/src/utils/checkWidth.ts +++ b/client/src/utils/checkWidth.ts @@ -1,4 +1,4 @@ -import { SMART_MENU_LARGE_WIDTH, SMART_MENU_SMALL_WIDTH } from 'constants/index'; +import { SMART_MENU_LARGE_WIDTH, SMART_MENU_SMALL_WIDTH, SMART_MENU_MOBILE_WIDTH } from 'constants/index'; const isLaptop = (width: number): boolean => { return width >= SMART_MENU_LARGE_WIDTH; @@ -8,4 +8,8 @@ const isSmall = (width: number): boolean => { return width <= SMART_MENU_SMALL_WIDTH; }; -export { isLaptop, isSmall }; +const isMobile = (width: number): boolean => { + return width <= SMART_MENU_MOBILE_WIDTH; +}; + +export { isLaptop, isSmall, isMobile }; From dfee61d51cbbd50106e0508a47edebee07b96da1 Mon Sep 17 00:00:00 2001 From: negu63 Date: Mon, 30 Aug 2021 14:06:55 +0900 Subject: [PATCH 42/84] =?UTF-8?q?chore:=20=EB=AA=A8=EB=B0=94=EC=9D=BC=20?= =?UTF-8?q?=EA=B0=80=EB=A1=9C=20=EC=83=81=EC=88=98=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/constants/index.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/client/src/constants/index.ts b/client/src/constants/index.ts index d85c59c..622a944 100644 --- a/client/src/constants/index.ts +++ b/client/src/constants/index.ts @@ -6,6 +6,7 @@ export const DELAY_TIME = 1000; export const SMART_MENU_LARGE_WIDTH = 1200; export const SMART_MENU_SMALL_WIDTH = 600; +export const SMART_MENU_MOBILE_WIDTH = 480; export const SMART_MENU_BLOCK_DELAY = 100; export const INNER_ERROR = '알 수 없는 에러가 발생했습니다.'; From ff48f45a32ace1e89db2443afe6591ca41bfb5a2 Mon Sep 17 00:00:00 2001 From: negu63 Date: Mon, 30 Aug 2021 14:07:13 +0900 Subject: [PATCH 43/84] =?UTF-8?q?feat:=20=ED=83=9C=EB=B8=94=EB=A6=BF=20?= =?UTF-8?q?=ED=98=B8=EB=B2=84=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/components/smart-menu/index.tsx | 10 ++++---- .../src/components/smart-menu/large-menu.tsx | 24 +++++++++---------- .../src/components/smart-menu/medium-menu.tsx | 16 +++++++------ 3 files changed, 24 insertions(+), 26 deletions(-) diff --git a/client/src/components/smart-menu/index.tsx b/client/src/components/smart-menu/index.tsx index b17f436..e1106e6 100644 --- a/client/src/components/smart-menu/index.tsx +++ b/client/src/components/smart-menu/index.tsx @@ -7,7 +7,7 @@ import useWindowSize from 'hooks/use-window-size'; import { IMenu } from 'types/category'; import { SMART_MENU_BLOCK_DELAY } from 'constants/index'; -import { isLaptop, isSmall } from 'utils/checkWidth'; +import { isLaptop, isSmall, isMobile } from 'utils/checkWidth'; import LargeMenu from './large-menu'; import MediumMenu from './medium-menu'; @@ -73,9 +73,7 @@ const SmartMenu: FC = ({ currentMenu, menu }) => { return ( { - if (isLaptop(width)) { - setOpenStatus(true); - } + setOpenStatus(true); }} onMouseLeave={() => { setOpenStatus(false); @@ -96,7 +94,7 @@ const SmartMenu: FC = ({ currentMenu, menu }) => { menu={menu} position={position} selectedLargeId={selectedLargeId} - isLaptop={isLaptop(width)} + isMobile={isMobile(width)} setLargeId={setLargeId} setMediumId={setMediumId} setPosition={setPosition} @@ -107,7 +105,7 @@ const SmartMenu: FC = ({ currentMenu, menu }) => { menu={menu} selectedLargeId={selectedLargeId} selectedMediumId={selectedMediumId} - isLaptop={isLaptop(width)} + isMobile={isMobile(width)} setMediumId={setMediumId} /> )} diff --git a/client/src/components/smart-menu/large-menu.tsx b/client/src/components/smart-menu/large-menu.tsx index 7b56fa9..3e4c32e 100644 --- a/client/src/components/smart-menu/large-menu.tsx +++ b/client/src/components/smart-menu/large-menu.tsx @@ -13,7 +13,7 @@ interface LargeMenuProps { menu: IMenu; position: { x: number; y: number }; selectedLargeId: string; - isLaptop: boolean; + isMobile: boolean; setLargeId: React.Dispatch>; setMediumId: React.Dispatch>; setPosition: React.Dispatch< @@ -95,7 +95,7 @@ const LargeMenu: FC = ({ menu, position, selectedLargeId, - isLaptop, + isMobile, setLargeId, setMediumId, setPosition, @@ -115,18 +115,16 @@ const LargeMenu: FC = ({ { - if (isLaptop) { - setMediumId(''); - setTimeout(() => { - if (e.clientX < position.x + 10) { - setLargeId(largeId); - } - setPosition({ x: e.clientX, y: e.clientY }); - }, SMART_MENU_BLOCK_DELAY); - } + setMediumId(''); + setTimeout(() => { + if (e.clientX < position.x + 10) { + setLargeId(largeId); + } + setPosition({ x: e.clientX, y: e.clientY }); + }, SMART_MENU_BLOCK_DELAY); }} onClick={(e: React.MouseEvent) => { - if (!isLaptop) { + if (isMobile) { setLargeId(largeId); e.stopPropagation(); } else { @@ -134,7 +132,7 @@ const LargeMenu: FC = ({ } }} isSelected={selectedLargeId === largeId} - isLaptop={isLaptop} + isLaptop={isMobile} > {large.name} diff --git a/client/src/components/smart-menu/medium-menu.tsx b/client/src/components/smart-menu/medium-menu.tsx index a094732..33c24aa 100644 --- a/client/src/components/smart-menu/medium-menu.tsx +++ b/client/src/components/smart-menu/medium-menu.tsx @@ -12,7 +12,7 @@ interface MediumMenuProps { menu: IMenu; selectedLargeId: string; selectedMediumId: string; - isLaptop: boolean; + isMobile: boolean; setMediumId: React.Dispatch>; } @@ -74,7 +74,7 @@ const Image = styled.img` } `; -const MediumMenu: FC = ({ menu, selectedLargeId, selectedMediumId, isLaptop, setMediumId }) => { +const MediumMenu: FC = ({ menu, selectedLargeId, selectedMediumId, isMobile, setMediumId }) => { const history = useHistory(); const goCategoryPage = useCallback( (code: string) => () => history.push(`${ITEM_LIST_URL}?categoryId=${code}`), @@ -91,15 +91,17 @@ const MediumMenu: FC = ({ menu, selectedLargeId, selectedMedium { - if (isLaptop) { + setMediumId(mediumId); + e.stopPropagation(); + }} + onClick={(e: React.MouseEvent) => { + if (isMobile) { setMediumId(mediumId); e.stopPropagation(); + } else { + history.push(`${ITEM_LIST_URL}?categoryId=${medium.code}`); } }} - onClick={(e: React.MouseEvent) => { - history.push(`${ITEM_LIST_URL}?categoryId=${medium.code}`); - e.stopPropagation(); - }} isSelected={selectedMediumId === mediumId} > {medium.name} From 44ce3ae8852c583a450390baf5aa6ff0fd94584e Mon Sep 17 00:00:00 2001 From: edegiil Date: Mon, 30 Aug 2021 14:50:42 +0900 Subject: [PATCH 44/84] =?UTF-8?q?fix:=20console.log=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server/src/repositories/category.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/server/src/repositories/category.ts b/server/src/repositories/category.ts index c57b795..a4486f9 100644 --- a/server/src/repositories/category.ts +++ b/server/src/repositories/category.ts @@ -13,8 +13,6 @@ const getCategories = async (): Promise => { raw: true, }); - console.log(categorySnapshot); - if (!categorySnapshot || categorySnapshot.length === 0) { throw errorGenerator({ message: 'GET /api/categories - categories not found', From d1de033bdc68ce360ea67c24e9acdf2ba844101c Mon Sep 17 00:00:00 2001 From: yoonminsang Date: Sat, 28 Aug 2021 23:32:38 +0900 Subject: [PATCH 45/84] =?UTF-8?q?feat:=20useselector=20=EC=B5=9C=EC=A0=81?= =?UTF-8?q?=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/containers/item-detail-container.tsx | 41 ++++++++++--------- client/src/containers/main-item-container.tsx | 17 ++++---- .../src/containers/my-address-container.tsx | 3 +- .../containers/my-order-list-container.tsx | 3 +- client/src/containers/order-container.tsx | 3 +- .../src/containers/search-item-container.tsx | 17 ++++---- client/src/containers/signin-container.tsx | 17 ++++---- client/src/containers/signup-container.tsx | 17 ++++---- 8 files changed, 68 insertions(+), 50 deletions(-) diff --git a/client/src/containers/item-detail-container.tsx b/client/src/containers/item-detail-container.tsx index ae42f84..61ae66e 100644 --- a/client/src/containers/item-detail-container.tsx +++ b/client/src/containers/item-detail-container.tsx @@ -1,5 +1,5 @@ import React, { FC, useEffect, useRef, useState } from 'react'; -import { useDispatch, useSelector } from 'react-redux'; +import { shallowEqual, useDispatch, useSelector } from 'react-redux'; import { useParams, useHistory } from 'lib/router'; import { PAYMENT_URL } from 'constants/urls'; @@ -44,24 +44,27 @@ const ItemDetailContainer: FC = () => { reviewSubmitLoading, itemLoading, isPaid, - } = useSelector(({ item, auth, review, loading }: RootState) => ({ - thumbnail: item.item.thumbnail, - title: item.item.title, - price: item.item.price, - contents: item.item.contents, - salePercent: item.item.salePercent, - isLike: item.item.isLike, - isSoldOut: item.item.isSoldOut, - userId: auth.user.userId, - error: review.error, - reviews: review.list.reviews, - pageCount: review.list.pageCount, - totalCount: review.list.totalCount, - reviewLoading: loading['review/getReviews'], - reviewSubmitLoading: loading['review/postReview'], - itemLoading: loading['item/getItem'], - isPaid: item.item.isPaid, - })); + } = useSelector( + ({ item, auth, review, loading }: RootState) => ({ + thumbnail: item.item.thumbnail, + title: item.item.title, + price: item.item.price, + contents: item.item.contents, + salePercent: item.item.salePercent, + isLike: item.item.isLike, + isSoldOut: item.item.isSoldOut, + userId: auth.user.userId, + error: review.error, + reviews: review.list.reviews, + pageCount: review.list.pageCount, + totalCount: review.list.totalCount, + reviewLoading: loading['review/getReviews'], + reviewSubmitLoading: loading['review/postReview'], + itemLoading: loading['item/getItem'], + isPaid: item.item.isPaid, + }), + shallowEqual, + ); const [isLiked, setIsLiked] = useState(false); const fileRef = useRef(null); diff --git a/client/src/containers/main-item-container.tsx b/client/src/containers/main-item-container.tsx index 48bcf7f..f903129 100644 --- a/client/src/containers/main-item-container.tsx +++ b/client/src/containers/main-item-container.tsx @@ -1,5 +1,5 @@ import React, { FC, useEffect } from 'react'; -import { useDispatch, useSelector } from 'react-redux'; +import { shallowEqual, useDispatch, useSelector } from 'react-redux'; import MainItemWrapper from 'components/item/main-item/main-item-wrapper'; @@ -7,12 +7,15 @@ import { RootState } from 'store'; import { getMainItem } from 'store/item'; const MainItemContainer: FC = () => { - const { popularItems, newItems, recommendItems, loading } = useSelector(({ item, loading }: RootState) => ({ - popularItems: item.main.popularItems, - newItems: item.main.newItems, - recommendItems: item.main.recommendItems, - loading: loading['item/getMainItem'], - })); + const { popularItems, newItems, recommendItems, loading } = useSelector( + ({ item, loading }: RootState) => ({ + popularItems: item.main.popularItems, + newItems: item.main.newItems, + recommendItems: item.main.recommendItems, + loading: loading['item/getMainItem'], + }), + shallowEqual, + ); const dispatch = useDispatch(); useEffect(() => { dispatch({ type: getMainItem.type }); diff --git a/client/src/containers/my-address-container.tsx b/client/src/containers/my-address-container.tsx index c1d5aba..adb52c5 100644 --- a/client/src/containers/my-address-container.tsx +++ b/client/src/containers/my-address-container.tsx @@ -1,5 +1,5 @@ import React, { FC, useState, useEffect } from 'react'; -import { useDispatch, useSelector } from 'react-redux'; +import { shallowEqual, useDispatch, useSelector } from 'react-redux'; import { useHistory } from 'lib/router'; import useInputs from 'hooks/use-inputs'; @@ -36,6 +36,7 @@ const MyAddressContainer: FC = () => { addressList: address.list, error: address.error, }), + shallowEqual, ); useEffect(() => { diff --git a/client/src/containers/my-order-list-container.tsx b/client/src/containers/my-order-list-container.tsx index b89c481..199caad 100644 --- a/client/src/containers/my-order-list-container.tsx +++ b/client/src/containers/my-order-list-container.tsx @@ -1,5 +1,5 @@ import React, { FC, useState, useEffect, useCallback } from 'react'; -import { useDispatch, useSelector } from 'react-redux'; +import { shallowEqual, useDispatch, useSelector } from 'react-redux'; import { useHistory } from 'lib/router'; import { RootState } from 'store'; @@ -29,6 +29,7 @@ const MyOrderListContainer: FC = () => { totalCount: order.list.totalCount, userLoading: loading['auth/getUser'], }), + shallowEqual, ); useEffect(() => { diff --git a/client/src/containers/order-container.tsx b/client/src/containers/order-container.tsx index 012292d..68f29bc 100644 --- a/client/src/containers/order-container.tsx +++ b/client/src/containers/order-container.tsx @@ -1,5 +1,5 @@ import React, { useState, useEffect, FC } from 'react'; -import { useDispatch, useSelector } from 'react-redux'; +import { shallowEqual, useDispatch, useSelector } from 'react-redux'; import { useHistory } from 'lib/router'; import { RootState } from 'store'; @@ -67,6 +67,7 @@ const OrderContainer: FC = () => { submitLoading: loading['order/postOrder'], addresses: address.list, }), + shallowEqual, ); const history = useHistory(); diff --git a/client/src/containers/search-item-container.tsx b/client/src/containers/search-item-container.tsx index c1d4b2e..ba19fbd 100644 --- a/client/src/containers/search-item-container.tsx +++ b/client/src/containers/search-item-container.tsx @@ -1,5 +1,5 @@ import React, { FC, useState, useEffect } from 'react'; -import { useDispatch, useSelector } from 'react-redux'; +import { shallowEqual, useDispatch, useSelector } from 'react-redux'; import { useQuery } from 'lib/router'; import { ESortType } from 'types/item'; @@ -15,12 +15,15 @@ const SearchItemContainer: FC = () => { const [sortType, setSortType] = useState(ESortType.RECOMMEND); const dispatch = useDispatch(); - const { items, totalCount, pageCount, loading } = useSelector(({ item, loading }: RootState) => ({ - items: item.list.items, - totalCount: item.list.totalCount, - pageCount: item.list.pageCount, - loading: loading['item/getListItem'], - })); + const { items, totalCount, pageCount, loading } = useSelector( + ({ item, loading }: RootState) => ({ + items: item.list.items, + totalCount: item.list.totalCount, + pageCount: item.list.pageCount, + loading: loading['item/getListItem'], + }), + shallowEqual, + ); useEffect(() => { setSortType(ESortType.RECOMMEND); diff --git a/client/src/containers/signin-container.tsx b/client/src/containers/signin-container.tsx index 587fe39..a3a1a63 100644 --- a/client/src/containers/signin-container.tsx +++ b/client/src/containers/signin-container.tsx @@ -1,5 +1,5 @@ import React, { FC, useEffect, useState } from 'react'; -import { useSelector, useDispatch } from 'react-redux'; +import { useSelector, useDispatch, shallowEqual } from 'react-redux'; import { useHistory } from 'lib/router'; import useInputs from 'hooks/use-inputs'; @@ -17,12 +17,15 @@ const SigninContainer: FC = () => { const [{ id, password }, onChange] = useInputs({ id: '', password: '' }); const [authError, setAuthError] = useState(null); - const { loading, error, userId, userLoading } = useSelector(({ auth, loading }: RootState) => ({ - loading: loading['auth/getLogin'], - error: auth.login.error, - userId: auth.user.userId, - userLoading: loading['auth/getUser'], - })); + const { loading, error, userId, userLoading } = useSelector( + ({ auth, loading }: RootState) => ({ + loading: loading['auth/getLogin'], + error: auth.login.error, + userId: auth.user.userId, + userLoading: loading['auth/getUser'], + }), + shallowEqual, + ); const dispatch = useDispatch(); useEffect(() => { diff --git a/client/src/containers/signup-container.tsx b/client/src/containers/signup-container.tsx index 0917378..0a74df0 100644 --- a/client/src/containers/signup-container.tsx +++ b/client/src/containers/signup-container.tsx @@ -1,5 +1,5 @@ import React, { FC, useCallback, useEffect, useState } from 'react'; -import { useSelector, useDispatch } from 'react-redux'; +import { useSelector, useDispatch, shallowEqual } from 'react-redux'; import { useHistory } from 'lib/router'; import useInputs from 'hooks/use-inputs'; @@ -19,12 +19,15 @@ const SignupContainer: FC = () => { const [authError, setAuthError] = useState(null); const [check, setCheck] = useState(false); const [modalVisible, setModalVisible] = useState(false); - const { loading, error, userId, userLoading } = useSelector(({ auth, loading }: RootState) => ({ - loading: loading['auth/getSignup'], - error: auth.signup.error, - userId: auth.user.userId, - userLoading: loading['auth/getUser'], - })); + const { loading, error, userId, userLoading } = useSelector( + ({ auth, loading }: RootState) => ({ + loading: loading['auth/getSignup'], + error: auth.signup.error, + userId: auth.user.userId, + userLoading: loading['auth/getUser'], + }), + shallowEqual, + ); const dispatch = useDispatch(); useEffect(() => { From 53f6598c87da81b57fc7c75e3dcf9ba6e8186d9f Mon Sep 17 00:00:00 2001 From: yoonminsang Date: Sun, 29 Aug 2021 17:09:00 +0900 Subject: [PATCH 46/84] =?UTF-8?q?feat:=20react.memo=20=EC=B5=9C=EC=A0=81?= =?UTF-8?q?=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 사실상 헤더,푸터,네브바 말고는 안됨. - 시간문제상 포기 --- client/src/components/common/layout/footer.tsx | 6 ++++-- client/src/components/common/layout/header.tsx | 6 ++++-- client/src/components/common/navbar.tsx | 6 ++++-- client/src/components/item-detail/detail-wrapper.tsx | 4 ++-- client/src/components/smart-menu/index.tsx | 6 ++++-- client/src/containers/navbar-container.tsx | 9 +++------ client/src/containers/smart-menu-container.tsx | 10 +++++++--- 7 files changed, 28 insertions(+), 19 deletions(-) diff --git a/client/src/components/common/layout/footer.tsx b/client/src/components/common/layout/footer.tsx index affc2d3..cace0e2 100644 --- a/client/src/components/common/layout/footer.tsx +++ b/client/src/components/common/layout/footer.tsx @@ -97,7 +97,7 @@ const Info = styled.div` } `; -const Footer: FC = ({ isMobile }) => { +const Footer: FC = React.memo(({ isMobile }) => { return ( @@ -150,6 +150,8 @@ const Footer: FC = ({ isMobile }) => { ); -}; +}); + +Footer.displayName = 'footer'; export default Footer; diff --git a/client/src/components/common/layout/header.tsx b/client/src/components/common/layout/header.tsx index e221c94..a46ebf3 100644 --- a/client/src/components/common/layout/header.tsx +++ b/client/src/components/common/layout/header.tsx @@ -45,7 +45,7 @@ const LogoWrapper = styled.div` padding: 25px 0; `; -const Header: FC = ({ displayMain, isMobile }) => { +const Header: FC = React.memo(({ displayMain, isMobile }) => { const renderLogo = () => { if (isMobile) { if (displayMain) return ; @@ -71,6 +71,8 @@ const Header: FC = ({ displayMain, isMobile }) => { }; return {renderLogo()}; -}; +}); + +Header.displayName = 'header'; export default Header; diff --git a/client/src/components/common/navbar.tsx b/client/src/components/common/navbar.tsx index 8d7baa8..adc6105 100644 --- a/client/src/components/common/navbar.tsx +++ b/client/src/components/common/navbar.tsx @@ -69,7 +69,7 @@ const Wrapper = styled.nav` } `; -const Navbar: FC = ({ displayMain, isMobile, userId, onLogout }) => { +const Navbar: FC = React.memo(({ displayMain, isMobile, userId, onLogout }) => { return ( {isMobile && ( @@ -98,6 +98,8 @@ const Navbar: FC = ({ displayMain, isMobile, userId, onLogout }) => ); -}; +}); + +Navbar.displayName = 'navbar'; export default Navbar; diff --git a/client/src/components/item-detail/detail-wrapper.tsx b/client/src/components/item-detail/detail-wrapper.tsx index 087c828..d0306e0 100644 --- a/client/src/components/item-detail/detail-wrapper.tsx +++ b/client/src/components/item-detail/detail-wrapper.tsx @@ -75,12 +75,12 @@ const DetailWrapper: FC = ({
- detailExecuteScroll()}> + detailExecuteScroll()}> 상품상세정보
- reviewExecuteScroll()}> + reviewExecuteScroll()}> 상품후기 {reviewCount}
diff --git a/client/src/components/smart-menu/index.tsx b/client/src/components/smart-menu/index.tsx index e1106e6..905ceaa 100644 --- a/client/src/components/smart-menu/index.tsx +++ b/client/src/components/smart-menu/index.tsx @@ -54,7 +54,7 @@ const MenuTitle = styled.div` } `; -const SmartMenu: FC = ({ currentMenu, menu }) => { +const SmartMenu: FC = React.memo(({ currentMenu, menu }) => { const [isOpen, setOpenStatus] = useState(false); const [selectedLargeId, setLargeId] = useState(''); const [selectedMediumId, setMediumId] = useState(''); @@ -127,6 +127,8 @@ const SmartMenu: FC = ({ currentMenu, menu }) => {
); -}; +}); + +SmartMenu.displayName = 'smartMenu'; export default SmartMenu; diff --git a/client/src/containers/navbar-container.tsx b/client/src/containers/navbar-container.tsx index d2c53a7..88b96a4 100644 --- a/client/src/containers/navbar-container.tsx +++ b/client/src/containers/navbar-container.tsx @@ -1,4 +1,4 @@ -import React, { FC, useState } from 'react'; +import React, { FC, useCallback, useState } from 'react'; import { useSelector, useDispatch } from 'react-redux'; import { Navbar } from 'components'; @@ -11,7 +11,6 @@ interface NavbarProps { displayMain?: boolean; isMobile: boolean; } - const NavbarContainer: FC = ({ displayMain = false, isMobile }) => { const [modalVisible, setModalVisible] = useState(false); const { userId } = useSelector(({ auth }: RootState) => ({ @@ -19,9 +18,7 @@ const NavbarContainer: FC = ({ displayMain = false, isMobile }) => })); const dispatch = useDispatch(); - const onLogout = (): void => { - setModalVisible(true); - }; + const onLogout = useCallback((): void => setModalVisible(true), []); const handleLogout = (): void => { dispatch({ type: logout.type }); @@ -30,7 +27,7 @@ const NavbarContainer: FC = ({ displayMain = false, isMobile }) => return ( <> - + {modalVisible && } ); }; diff --git a/client/src/containers/smart-menu-container.tsx b/client/src/containers/smart-menu-container.tsx index 26ad9de..074fcdf 100644 --- a/client/src/containers/smart-menu-container.tsx +++ b/client/src/containers/smart-menu-container.tsx @@ -1,4 +1,4 @@ -import React, { FC } from 'react'; +import React, { FC, useMemo } from 'react'; import { useSelector } from 'react-redux'; import { IMenu, IMenuChild, ICategory } from 'types/category'; @@ -44,8 +44,12 @@ const SmartMenuContainer: FC = ({ currentCode }) => { const { data } = useSelector(({ category }: RootState) => ({ data: category.categories.data, })); - const currentName = currentCode ? data.find(category => category.code === currentCode)?.name : '캇테고리'; - return ; + const currentName = useMemo( + () => (currentCode ? data.find(category => category.code === currentCode)?.name : '캇테고리'), + [currentCode, data], + ); + const menu = useMemo(() => generateMenu(data), [data]); + return ; }; export default SmartMenuContainer; From 8c336220d86cfdbf50c9bf1c23bbf52069887aae Mon Sep 17 00:00:00 2001 From: yoonminsang Date: Sun, 29 Aug 2021 19:23:02 +0900 Subject: [PATCH 47/84] =?UTF-8?q?feat:=20=EC=84=9C=EB=B2=84=EB=B6=80?= =?UTF-8?q?=EB=B6=84=20originalPrice=EC=82=AD=EC=A0=9C=EB=90=9C=20?= =?UTF-8?q?=EB=B6=80=EB=B6=84=EA=B3=BC=20=EC=97=86=EC=97=88=EB=8D=98=20?= =?UTF-8?q?=EB=B6=80=EB=B6=84=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server/src/repositories/items.ts | 116 +++++++++++++++++++++---------- server/src/services/items.ts | 5 +- 2 files changed, 85 insertions(+), 36 deletions(-) diff --git a/server/src/repositories/items.ts b/server/src/repositories/items.ts index 6686dd0..9c9fdc7 100644 --- a/server/src/repositories/items.ts +++ b/server/src/repositories/items.ts @@ -22,7 +22,7 @@ export interface IScore { export interface Item { id: number; title: string; - tumbnail: string; + thumbnail: string; price: number; salePercent: number; amount: number; @@ -34,20 +34,6 @@ export interface Item { const LIMIT_COUNT = 12; -const filterItems = (items: Model[]): Item[] => - items.map(item => ({ - id: item.getDataValue('id'), - title: item.getDataValue('title'), - tumbnail: item.getDataValue('thumbnail'), - price: item.getDataValue('price'), - salePercent: item.getDataValue('salePercent'), - amount: item.getDataValue('amount'), - isGreen: item.getDataValue('isGreen'), - isBest: item.getDataValue('isBest'), - updatedAt: item.getDataValue('updatedAt'), - isLike: false, - })); - const getRecommendItems = async (visited: string[], isCategoryItem: boolean): Promise => { if (visited.length > 0) { const scores = await db.Score.findAll({ @@ -85,7 +71,13 @@ const getRecommendItems = async (visited: string[], isCategoryItem: boolean): Pr 'id', 'title', 'thumbnail', - 'price', + [ + Sequelize.literal( + 'CASE WHEN salePercent !=0 THEN ROUND(price - (price * salePercent /100),0) ELSE price END', + ), + 'price', + ], + ['price', 'originalPrice'], 'salePercent', 'amount', 'isGreen', @@ -108,8 +100,6 @@ const getRecommendItems = async (visited: string[], isCategoryItem: boolean): Pr if (findItem) sortedItems.items.push(findItem); }); - filterItems(sortedItems.items); - return { items: sortedItems.items }; } @@ -119,7 +109,11 @@ const getRecommendItems = async (visited: string[], isCategoryItem: boolean): Pr 'id', 'title', 'thumbnail', - 'price', + [ + Sequelize.literal('CASE WHEN salePercent !=0 THEN ROUND(price - (price * salePercent /100),0) ELSE price END'), + 'price', + ], + ['price', 'originalPrice'], 'salePercent', 'amount', 'isGreen', @@ -129,8 +123,6 @@ const getRecommendItems = async (visited: string[], isCategoryItem: boolean): Pr limit: LIMIT_COUNT, }); - filterItems(items); - return { items }; }; @@ -140,7 +132,11 @@ const getMainItems = async (order: string[][], limit: number): Promise = 'id', 'title', 'thumbnail', - 'price', + [ + Sequelize.literal('CASE WHEN salePercent !=0 THEN ROUND(price - (price * salePercent /100),0) ELSE price END'), + 'price', + ], + ['price', 'originalPrice'], 'salePercent', 'amount', 'isGreen', @@ -158,14 +154,24 @@ const getMainItems = async (order: string[][], limit: number): Promise = }); } - filterItems(items); - return { items }; }; const getCategoryItems = async (pageId: number, order: string[][], categoryReg: string): Promise => { const items = await db.Item.findAll({ - attributes: ['id', 'title', 'thumbnail', 'price', 'salePercent', 'amount', 'isGreen'], + attributes: [ + 'id', + 'title', + 'thumbnail', + [ + Sequelize.literal('CASE WHEN salePercent !=0 THEN ROUND(price - (price * salePercent /100),0) ELSE price END'), + 'price', + ], + ['price', 'originalPrice'], + 'salePercent', + 'amount', + 'isGreen', + ], order: order as Order, where: { CategoryId: { [Op.regexp]: `^${categoryReg}` } }, offset: (pageId - 1) * LIMIT_COUNT, @@ -189,8 +195,6 @@ const getCategoryItems = async (pageId: number, order: string[][], categoryReg: }); } - filterItems(items); - return { items, totalCount, pageCount }; }; @@ -200,7 +204,19 @@ const getCategoryRecommendItems = async ( visited: string[], ): Promise => { let items = await db.Item.findAll({ - attributes: ['id', 'title', 'thumbnail', 'price', 'salePercent', 'amount', 'isGreen'], + attributes: [ + 'id', + 'title', + 'thumbnail', + [ + Sequelize.literal('CASE WHEN salePercent !=0 THEN ROUND(price - (price * salePercent /100),0) ELSE price END'), + 'price', + ], + ['price', 'originalPrice'], + 'salePercent', + 'amount', + 'isGreen', + ], where: { CategoryId: { [Op.regexp]: `^${categoryReg}` } }, include: [ { @@ -231,14 +247,24 @@ const getCategoryRecommendItems = async ( }); } - filterItems(items); - return { items, totalCount, pageCount }; }; const getSearchItems = async (pageId: number, order: string[][], regExp: string): Promise => { const items = await db.Item.findAll({ - attributes: ['id', 'title', 'thumbnail', 'price', 'salePercent', 'amount', 'isGreen'], + attributes: [ + 'id', + 'title', + 'thumbnail', + [ + Sequelize.literal('CASE WHEN salePercent !=0 THEN ROUND(price - (price * salePercent /100),0) ELSE price END'), + 'price', + ], + ['price', 'originalPrice'], + 'salePercent', + 'amount', + 'isGreen', + ], order: order as Order, where: { title: { @@ -272,14 +298,24 @@ const getSearchItems = async (pageId: number, order: string[][], regExp: string) }); } - filterItems(items); - return { items, totalCount, pageCount }; }; const getItem = async (id: string): Promise> => { const item = await db.Item.findOne({ - attributes: ['title', 'thumbnail', 'price', 'salePercent', 'amount', 'isGreen', 'contents'], + attributes: [ + 'title', + 'thumbnail', + [ + Sequelize.literal('CASE WHEN salePercent !=0 THEN ROUND(price - (price * salePercent /100),0) ELSE price END'), + 'price', + ], + ['price', 'originalPrice'], + 'salePercent', + 'amount', + 'isGreen', + 'contents', + ], where: { id }, }); @@ -299,7 +335,17 @@ const getOrderItems = async (itemIDs: string[]): Promise { thumbnail: item.getDataValue('thumbnail'), title: item.getDataValue('title'), price: Number.parseInt(`${item.getDataValue('price')}`, 10), + originalPrice: Number.parseInt(`${item.getDataValue('originalPrice')}`, 10), salePercent: item.getDataValue('salePercent'), contents: JSON.parse(item.getDataValue('contents').replace(/^'|'$/g, '').replace(/'/g, '"')) as string[], isSoldOut: item.getDataValue('amount') < 1, @@ -153,7 +156,7 @@ async function getOrderItems(id: string): Promise { const salePercent = item.getDataValue('salePercent'); const price = Number(item.getDataValue('price')); - const saledPrice = Math.floor(price - (price * salePercent) / 100); + const saledPrice = Math.round(price - (price * salePercent) / 100); return { id: item.getDataValue('id'), From b2a92a24a705e6d3bc01c2a2a507a6355d122a57 Mon Sep 17 00:00:00 2001 From: yoonminsang Date: Sun, 29 Aug 2021 19:23:23 +0900 Subject: [PATCH 48/84] =?UTF-8?q?feat:=20=ED=94=84=EB=A1=A0=ED=8A=B8=20?= =?UTF-8?q?=EC=98=A4=EB=A6=AC=EC=A7=80=EB=84=90=20=ED=94=84=EB=9D=BC?= =?UTF-8?q?=EC=9D=B4=EC=8A=A4=20=EC=97=86=EB=8A=94=EB=B6=80=EB=B6=84=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/components/item-detail/item-info.tsx | 15 +++++++++++++++ client/src/containers/item-detail-container.tsx | 5 +++++ client/src/store/item.ts | 1 + client/src/types/item.ts | 1 + 4 files changed, 22 insertions(+) diff --git a/client/src/components/item-detail/item-info.tsx b/client/src/components/item-detail/item-info.tsx index 926a658..4d39194 100644 --- a/client/src/components/item-detail/item-info.tsx +++ b/client/src/components/item-detail/item-info.tsx @@ -21,6 +21,7 @@ export interface ItemInfoProps { thumbnail: string; title: string; price: number; + originalPrice: number; likeShow: boolean; isLiked: boolean; setIsLiked: Dispatch>; @@ -28,6 +29,7 @@ export interface ItemInfoProps { onSubmitCart: (count: number) => void; onBuy: () => void; setCount: React.Dispatch>; + salePercent: number; } const Wrapper = styled.section` @@ -135,6 +137,15 @@ const ItemPrice = styled.div` color: ${({ theme }) => theme?.colorGreyDark}; } + .original-price { + font-size: 18px; + font-family: ${({ theme }) => theme?.fontHanna}; + color: ${({ theme }) => theme?.colorPrimary}; + color: rgb(174, 174, 174); + text-decoration: line-through; + margin-bottom: 10px; + } + .price { font-size: 24px; font-family: ${({ theme }) => theme?.fontHanna}; @@ -246,6 +257,7 @@ const ItemInfo: FC = ({ thumbnail, title, price, + originalPrice, likeShow, isLiked, setIsLiked, @@ -253,6 +265,7 @@ const ItemInfo: FC = ({ onSubmitCart, onBuy, setCount, + salePercent, }) => { const [totalPrice, setTotalPrice] = useState(price); const [modalVisible, setModalVisible] = useState(false); @@ -292,6 +305,8 @@ const ItemInfo: FC = ({
판매가격
+ {/* {salePercent &&
{formatPrice(originalPrice)}원
} */} +
{formatPrice(originalPrice)}원
{formatPrice(price)}원
배송정보
데모기념 오늘만 배송비 무료!!!
diff --git a/client/src/containers/item-detail-container.tsx b/client/src/containers/item-detail-container.tsx index 61ae66e..5ea8938 100644 --- a/client/src/containers/item-detail-container.tsx +++ b/client/src/containers/item-detail-container.tsx @@ -32,7 +32,9 @@ const ItemDetailContainer: FC = () => { thumbnail, title, price, + originalPrice, contents, + salePercent, isLike, isSoldOut, userId, @@ -49,6 +51,7 @@ const ItemDetailContainer: FC = () => { thumbnail: item.item.thumbnail, title: item.item.title, price: item.item.price, + originalPrice: item.item.originalPrice, contents: item.item.contents, salePercent: item.item.salePercent, isLike: item.item.isLike, @@ -155,6 +158,7 @@ const ItemDetailContainer: FC = () => { thumbnail={thumbnail} title={title} price={price} + originalPrice={originalPrice} likeShow={!!userId} isLiked={isLiked} setIsLiked={toggleIsLiked} @@ -162,6 +166,7 @@ const ItemDetailContainer: FC = () => { onSubmitCart={onSubmitCart} onBuy={onBuy} setCount={setCount} + salePercent={salePercent} /> Date: Sun, 29 Aug 2021 19:59:51 +0900 Subject: [PATCH 49/84] =?UTF-8?q?fix:=20=EC=A3=BC=EC=84=9D=EC=A0=9C?= =?UTF-8?q?=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/components/item-detail/item-info.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/client/src/components/item-detail/item-info.tsx b/client/src/components/item-detail/item-info.tsx index 4d39194..133be4e 100644 --- a/client/src/components/item-detail/item-info.tsx +++ b/client/src/components/item-detail/item-info.tsx @@ -305,8 +305,7 @@ const ItemInfo: FC = ({
판매가격
- {/* {salePercent &&
{formatPrice(originalPrice)}원
} */} -
{formatPrice(originalPrice)}원
+ {salePercent !== 0 &&
{formatPrice(originalPrice)}원
}
{formatPrice(price)}원
배송정보
데모기념 오늘만 배송비 무료!!!
From 7f3669ac6b66d24ff30e8a90c04a634085f85cd0 Mon Sep 17 00:00:00 2001 From: yoonminsang Date: Sun, 29 Aug 2021 21:28:54 +0900 Subject: [PATCH 50/84] =?UTF-8?q?feat:=20=EC=84=9C=EB=B2=84=EC=97=90=20add?= =?UTF-8?q?ressDetail=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server/src/controllers/address.ts | 4 ++-- server/src/models/address.ts | 5 +++++ server/src/repositories/address.ts | 4 +++- server/src/services/address.ts | 3 ++- server/src/types/address.ts | 1 + server/src/validation/address.ts | 10 ++++++++++ 6 files changed, 23 insertions(+), 4 deletions(-) diff --git a/server/src/controllers/address.ts b/server/src/controllers/address.ts index 41cc16d..0ad75fc 100644 --- a/server/src/controllers/address.ts +++ b/server/src/controllers/address.ts @@ -21,9 +21,9 @@ export const getAddress = async (req: Request, res: Response): Promise => export const addAddress = async (req: Request, res: Response): Promise => { const token = getAccessToken(req.headers.authorization); const { uid } = decodeToken('access', token); - const { name, receiver, address } = req.body; + const { name, receiver, address, addressDetail } = req.body; try { - const adrs = await addressService.addAddress(uid, name, receiver, address); + const adrs = await addressService.addAddress(uid, name, receiver, address, addressDetail); res.status(200).json(adrs); } catch (err) { console.log(err); diff --git a/server/src/models/address.ts b/server/src/models/address.ts index fd2f979..f7913a7 100644 --- a/server/src/models/address.ts +++ b/server/src/models/address.ts @@ -5,6 +5,7 @@ export interface AddressAttribures { id: string; name: string; address: string; + addressDetail: string; receiver: string; UserId: string; } @@ -26,6 +27,10 @@ const addressSchema = (sequelize: Sequelize): ModelCtor[]> => { const address = await db.Address.findAll({ - attributes: ['id', 'name', 'receiver', 'address'], + attributes: ['id', 'name', 'receiver', 'address', 'addressDetail'], where: { UserId: uid, }, @@ -28,6 +28,7 @@ const addAddress = async ( name: string, receiver: string, address: string, + addressDetail: string, ): Promise[]> => { const count = await db.Address.count({ where: { @@ -44,6 +45,7 @@ const addAddress = async ( name, receiver, address, + addressDetail, UserId: uid, }); return getAddress(uid); diff --git a/server/src/services/address.ts b/server/src/services/address.ts index 7ce6bd3..54a6be6 100644 --- a/server/src/services/address.ts +++ b/server/src/services/address.ts @@ -11,8 +11,9 @@ async function addAddress( name: string, receiver: string, address: string, + addressDetail: string, ): Promise[]> { - return addressRepisitory.addAddress(uid, name, receiver, address); + return addressRepisitory.addAddress(uid, name, receiver, address, addressDetail); } async function removeAddress(id: string, uid: string): Promise[]> { diff --git a/server/src/types/address.ts b/server/src/types/address.ts index fc24d2b..5060eda 100644 --- a/server/src/types/address.ts +++ b/server/src/types/address.ts @@ -2,6 +2,7 @@ export interface IAddReqBody { name: string; receiver: string; address: string; + addressDetail: string; } export interface IRemoveReqBody { diff --git a/server/src/validation/address.ts b/server/src/validation/address.ts index 35561c7..070529a 100644 --- a/server/src/validation/address.ts +++ b/server/src/validation/address.ts @@ -44,6 +44,16 @@ export const addAddressValidation = ( 'string.max': `주소는 ${ADDRESS.ADDRESS_MAX_LENGTH}자를 넘길 수 없습니다.`, 'any.required': `주소를 입력해주세요.`, }), + addressDetail: Joi.string() + .min(ADDRESS.ADDRESS_MIN_LENGTH) + .max(ADDRESS.ADDRESS_MAX_LENGTH) + .required() + .empty('') + .messages({ + 'string.min': `상세주소는 ${ADDRESS.ADDRESS_MIN_LENGTH}자 이상 입력해야 합니다.`, + 'string.max': `상세주소는 ${ADDRESS.ADDRESS_MAX_LENGTH}자를 넘길 수 없습니다.`, + 'any.required': `상세주소를 입력해주세요.`, + }), }); const validationResult = schema.validate(req.body); From d11eea79c73f814ae7d836b15b50acffef258d8f Mon Sep 17 00:00:00 2001 From: yoonminsang Date: Sun, 29 Aug 2021 21:29:16 +0900 Subject: [PATCH 51/84] =?UTF-8?q?fix:=20address=20api=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/utils/api/address.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/src/utils/api/address.ts b/client/src/utils/api/address.ts index 0d5aae9..36a1100 100644 --- a/client/src/utils/api/address.ts +++ b/client/src/utils/api/address.ts @@ -4,8 +4,8 @@ import request from './request'; export const getAddress = (): Promise => request('GET', '/api/address'); -export const addAddress = ({ name, receiver, address }: IAddressState): Promise => - request('POST', '/api/address', { name, receiver, address }); +export const addAddress = ({ name, receiver, address, addressDetail }: IAddressState): Promise => + request('POST', '/api/address', { name, receiver, address, addressDetail }); export const removeAddress = ({ id }: IAddressRemoveState): Promise => request<{ data: IAddressRemoveState }>('DELETE', '/api/address', { data: { id } }); From b3b97ade7c6416a5e4b2cac41ef258d218f88ea0 Mon Sep 17 00:00:00 2001 From: yoonminsang Date: Sun, 29 Aug 2021 21:30:20 +0900 Subject: [PATCH 52/84] =?UTF-8?q?feat:=20addressDetail=20=ED=94=84?= =?UTF-8?q?=EB=A1=A0=ED=8A=B8=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../my/my-address/my-address-form.tsx | 1 + .../my/my-address/my-address-table.tsx | 4 +- client/src/components/order/index.tsx | 46 ++++++++++++++----- .../src/containers/my-address-container.tsx | 2 +- client/src/containers/order-container.tsx | 44 ++++++++++++------ client/src/types/address.ts | 2 + .../src/utils/validation/order-validation.ts | 12 ++++- 7 files changed, 81 insertions(+), 30 deletions(-) diff --git a/client/src/components/my/my-address/my-address-form.tsx b/client/src/components/my/my-address/my-address-form.tsx index 49e6251..aee00fa 100644 --- a/client/src/components/my/my-address/my-address-form.tsx +++ b/client/src/components/my/my-address/my-address-form.tsx @@ -33,6 +33,7 @@ const InputWrapper = styled.div` display: flex; align-items: center; flex-wrap: wrap; + gap: 8px; `; const InputErrorMessage = styled.div` diff --git a/client/src/components/my/my-address/my-address-table.tsx b/client/src/components/my/my-address/my-address-table.tsx index 951e685..cd76252 100644 --- a/client/src/components/my/my-address/my-address-table.tsx +++ b/client/src/components/my/my-address/my-address-table.tsx @@ -39,12 +39,12 @@ const MyAddressTable: FC = ({ loading, addressList, onRemov {addressList.map(adrs => { - const { id, name, receiver, address } = adrs; + const { id, name, receiver, address, addressDetail } = adrs; return ( {name} {receiver} - {address} + {`${address} ${addressDetail}`} onRemove(id)}> 삭제 diff --git a/client/src/components/order/index.tsx b/client/src/components/order/index.tsx index 364f28d..915f395 100644 --- a/client/src/components/order/index.tsx +++ b/client/src/components/order/index.tsx @@ -1,6 +1,7 @@ -import React, { useState, FC, Dispatch, SetStateAction } from 'react'; +import React, { useState, FC, Dispatch, SetStateAction, useEffect } from 'react'; import styled from 'lib/woowahan-components'; +import AddressModal from 'components/common/address-modal'; import { TextButton, CheckBox, GridForm, PriceCalculator } from 'components'; import TableSection, { OrderItem } from './table-section'; import RadioButton from './radio-button'; @@ -18,13 +19,20 @@ interface OrderProps { user: string; address: string; receiver: string; - onChange: (id: 'user' | 'receiver' | 'address') => (e: React.ChangeEvent) => void; + onChange: (id: 'user' | 'receiver' | 'address' | 'addressDetail') => (e: React.ChangeEvent) => void; getLoading: boolean; submitLoading: boolean; addresses: { name: string; address: string }[]; pickAddress: (e: React.ChangeEvent) => void; addressChecked: string; onFocusOutPhone: () => void; + addressDetail: string; + addressDetailError: string; + setAddress: React.Dispatch>; +} + +interface IAddressData { + roadAddress: string; } const SectionTitle = styled.h4` @@ -69,6 +77,7 @@ const InputWrapper = styled.div` display: flex; align-items: center; flex-wrap: wrap; + gap: 8px; `; const InputErrorMessage = styled.div` @@ -115,7 +124,17 @@ const Order: FC = ({ pickAddress, addressChecked, onFocusOutPhone, + addressDetail, + addressDetailError, + setAddress, }) => { + const [modal, setModal] = useState(false); + const handleComplete = (data: IAddressData) => { + setAddress(data.roadAddress); + }; + useEffect(() => { + if (address) setModal(false); + }, [address]); const [agreed, setAgreed] = useState(false); const isValid = agreed && user && phone && address && addresses; @@ -141,7 +160,7 @@ const Order: FC = ({ const onAgree = () => { setAgreed(state => !state); }; - + const etc = addressChecked === '기타'; return ( <> 주문상세내역 @@ -159,7 +178,7 @@ const Order: FC = ({ 배송정보 - + {addresses.map(address => { return ( @@ -188,19 +207,23 @@ const Order: FC = ({ name="receiver" value={receiver} onChange={onChange('receiver')} - readOnly={!!address} + readOnly={!etc} /> {receiverError} + + setModal(true)} /> + {addressError} + - {addressError} + {addressDetailError} 결제수단 선택 / 결제 @@ -224,6 +247,7 @@ const Order: FC = ({ {submitError} + {modal && } ); }; diff --git a/client/src/containers/my-address-container.tsx b/client/src/containers/my-address-container.tsx index adb52c5..dccfdb4 100644 --- a/client/src/containers/my-address-container.tsx +++ b/client/src/containers/my-address-container.tsx @@ -55,7 +55,7 @@ const MyAddressContainer: FC = () => { if (!addressDetail) setAddressDetailError('상세주소를 입력하세요'); if (addressList.length >= 3) setAddError('배송지는 최대 3개까지 입력할 수 있습니다'); if (name && receiver && addressDetail && addressList.length < 3) { - dispatch({ type: addAddress.type, payload: { name, receiver, address: `${address} ${addressDetail}` } }); + dispatch({ type: addAddress.type, payload: { name, receiver, address, addressDetail } }); reset(); } }; diff --git a/client/src/containers/order-container.tsx b/client/src/containers/order-container.tsx index 68f29bc..51ea8c4 100644 --- a/client/src/containers/order-container.tsx +++ b/client/src/containers/order-container.tsx @@ -13,6 +13,7 @@ import { addressValidation, receiverValidation, phoneValidation, + addressDetailValidation, } from 'utils/validation/order-validation'; import { cartGenerator } from 'utils/cart-generator'; import { CartItem } from 'types/cart'; @@ -53,10 +54,12 @@ const OrderContainer: FC = () => { const [phoneError, setPhoneError] = useState(''); const [receiverError, setReceiverError] = useState(''); const [addressError, setAddressError] = useState(''); + const [addressDetailError, setAddressDetailError] = useState(''); const [orderItems, setOrderItems] = useState([]); const [user, setUser] = useState(''); const [receiver, setReceiver] = useState(''); const [address, setAddress] = useState(''); + const [addressDetail, setAddressDetail] = useState(''); const [addressChecked, setaddressChecked] = useState('기타'); const { userId, submitError, itemsData, getLoading, submitLoading, addresses } = useSelector( ({ auth, order, loading, address }: RootState) => ({ @@ -101,28 +104,31 @@ const OrderContainer: FC = () => { } }, [dispatch, history]); - const onChange = (id: 'user' | 'receiver' | 'address') => (e: React.ChangeEvent) => { - switch (id) { - case 'user': - setUser(e.target.value); - break; - case 'receiver': - setReceiver(e.target.value); - break; - case 'address': - setAddress(e.target.value); - break; - default: - } - }; + const onChange = + (id: 'user' | 'receiver' | 'address' | 'addressDetail') => (e: React.ChangeEvent) => { + switch (id) { + case 'user': + setUser(e.target.value); + break; + case 'receiver': + setReceiver(e.target.value); + break; + case 'addressDetail': + setAddressDetail(e.target.value); + break; + default: + } + }; const pickAddress = (e: React.ChangeEvent) => { - const { address, receiver } = addresses.find(address => address.name === e.target.value) || { + const { address, addressDetail, receiver } = addresses.find(address => address.name === e.target.value) || { address: '', + addressDetail: '', receiver: '', }; setReceiver(receiver); setAddress(address); + setAddressDetail(addressDetail); setaddressChecked(e.target.value); }; @@ -157,6 +163,7 @@ const OrderContainer: FC = () => { setPhoneError(''); setReceiverError(''); setAddressError(''); + setAddressDetailError(''); if (userValidation(user)) { setUserError(userValidation(user)); @@ -170,6 +177,10 @@ const OrderContainer: FC = () => { setAddressError(addressValidation(address)); return; } + if (addressDetailValidation(addressDetail)) { + setAddressError(addressDetailValidation(addressDetail)); + return; + } if (receiverValidation(receiver)) { setAddressError(receiverValidation(receiver)); return; @@ -213,6 +224,9 @@ const OrderContainer: FC = () => { pickAddress={pickAddress} addressChecked={addressChecked} onFocusOutPhone={onFocusOutPhone} + addressDetail={addressDetail} + addressDetailError={addressDetailError} + setAddress={setAddress} /> ); }; diff --git a/client/src/types/address.ts b/client/src/types/address.ts index 368889f..d5ae031 100644 --- a/client/src/types/address.ts +++ b/client/src/types/address.ts @@ -3,12 +3,14 @@ export interface IListAddress { name: string; receiver: string; address: string; + addressDetail: string; } export interface IAddressState { name: string; receiver: string; address: string; + addressDetail: string; } export interface IAddressRemoveState { diff --git a/client/src/utils/validation/order-validation.ts b/client/src/utils/validation/order-validation.ts index 0b56076..054d9c8 100644 --- a/client/src/utils/validation/order-validation.ts +++ b/client/src/utils/validation/order-validation.ts @@ -8,6 +8,9 @@ const USER_EMPTY = '주문하시는 분을 입력해주세요'; const ADDRESS_EMPTY = '주소를 입력해주세요'; const ADDRESS_TOO_SHORT = '주소는 3자 이상 입력해주세요'; +const ADDRESS_DETAIL_EMPTY = '상세주소를 입력해주세요'; +const ADDRESS_DETAIL_TOO_SHORT = '상세주소는 2자 이상 입력해주세요'; + const RECEIVER_TOO_LONG = '받는분은 20자 이하로 입력해주세요'; const phoneValidation = (phone: string): string => { @@ -30,10 +33,17 @@ const addressValidation = (address: string): string => { return ''; }; +const addressDetailValidation = (address: string): string => { + if (!address) return ADDRESS_DETAIL_EMPTY; + if (address.length < 2) return ADDRESS_DETAIL_TOO_SHORT; + + return ''; +}; + const receiverValidation = (receiver: string): string => { if (receiver.length > 20) return RECEIVER_TOO_LONG; return ''; }; -export { phoneValidation, userValidation, addressValidation, receiverValidation }; +export { phoneValidation, userValidation, addressValidation, addressDetailValidation, receiverValidation }; From 0900af0da494ae47cda95d0e2e1b9a02cb20566d Mon Sep 17 00:00:00 2001 From: yoonminsang Date: Mon, 30 Aug 2021 15:51:03 +0900 Subject: [PATCH 53/84] =?UTF-8?q?fix:=20gap=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/components/my/my-address/my-address-form.tsx | 1 - client/src/components/order/index.tsx | 1 - 2 files changed, 2 deletions(-) diff --git a/client/src/components/my/my-address/my-address-form.tsx b/client/src/components/my/my-address/my-address-form.tsx index aee00fa..49e6251 100644 --- a/client/src/components/my/my-address/my-address-form.tsx +++ b/client/src/components/my/my-address/my-address-form.tsx @@ -33,7 +33,6 @@ const InputWrapper = styled.div` display: flex; align-items: center; flex-wrap: wrap; - gap: 8px; `; const InputErrorMessage = styled.div` diff --git a/client/src/components/order/index.tsx b/client/src/components/order/index.tsx index 915f395..5ac0fca 100644 --- a/client/src/components/order/index.tsx +++ b/client/src/components/order/index.tsx @@ -77,7 +77,6 @@ const InputWrapper = styled.div` display: flex; align-items: center; flex-wrap: wrap; - gap: 8px; `; const InputErrorMessage = styled.div` From a00e80d21346d220e1385cc957b93833974c5b32 Mon Sep 17 00:00:00 2001 From: yoonminsang Date: Mon, 30 Aug 2021 15:59:42 +0900 Subject: [PATCH 54/84] =?UTF-8?q?fix:=20=EC=A3=BC=EB=AC=B8=EC=84=9C=20?= =?UTF-8?q?=EC=9D=B4=EB=AF=B8=EC=A7=80,text=20css=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/components/order/table-section.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/client/src/components/order/table-section.tsx b/client/src/components/order/table-section.tsx index fef8e81..f18fb85 100644 --- a/client/src/components/order/table-section.tsx +++ b/client/src/components/order/table-section.tsx @@ -42,7 +42,9 @@ const TableRowText = styled.div` `; const ItemTitle = styled.div` + display: flex; font-size: 14px; + align-items: center; ${({ theme }) => theme?.mobile} { font-size: 12px; From 7b44f0d214436663a1719f661059f1ef68bc16f8 Mon Sep 17 00:00:00 2001 From: yoonminsang Date: Mon, 30 Aug 2021 16:21:43 +0900 Subject: [PATCH 55/84] =?UTF-8?q?feat:=20=EC=B9=B4=ED=8A=B8=20=EC=B9=B4?= =?UTF-8?q?=EC=9A=B4=ED=8A=B8=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/components/common/navbar.tsx | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/client/src/components/common/navbar.tsx b/client/src/components/common/navbar.tsx index adc6105..1edb669 100644 --- a/client/src/components/common/navbar.tsx +++ b/client/src/components/common/navbar.tsx @@ -10,6 +10,7 @@ import loginIcon from 'assets/icons/login.svg'; import { MAIN_URL, CART_URL, SIGNIN_URL, ORDER_LIST_URL } from 'constants/urls'; import { Logo } from 'components'; +import { cartGenerator } from 'utils/cart-generator'; interface NavbarProps { displayMain: boolean; @@ -26,6 +27,10 @@ const Wrapper = styled.nav` justify-content: flex-end; position: relative; + b { + ${props => props.theme?.weightBold}; + } + .nav-link-list { display: flex; align-items: center; @@ -69,6 +74,11 @@ const Wrapper = styled.nav` } `; +const cartCount = (): number => { + const cartItems = cartGenerator(); + return cartItems.length; +}; + const Navbar: FC = React.memo(({ displayMain, isMobile, userId, onLogout }) => { return ( @@ -84,7 +94,13 @@ const Navbar: FC = React.memo(({ displayMain, isMobile, userId, onL )} - {isMobile ? cart : '장바구니'} + {isMobile ? ( + cart + ) : ( + + 장바구니 {cartCount()} + + )} {userId ? (
{orders.map(order => { - const { createdAt, id, title, thumbnail, price, quantity, status } = order; + const { id, createdAt, itemId, title, thumbnail, price, quantity, status } = order; return ( - + {createdAt} - + {title} {title} diff --git a/client/src/types/order.ts b/client/src/types/order.ts index 6d91282..9aee360 100644 --- a/client/src/types/order.ts +++ b/client/src/types/order.ts @@ -1,4 +1,5 @@ export interface IOrder { + itemId: number; createdAt: string; id: number; thumbnail: string; diff --git a/server/src/repositories/orders.ts b/server/src/repositories/orders.ts index 52e8bf9..3c0967c 100644 --- a/server/src/repositories/orders.ts +++ b/server/src/repositories/orders.ts @@ -26,8 +26,9 @@ const getUserOrders = async ( const [orders, totalCount] = await Promise.all([ db.Order.findAll({ attributes: [ + 'id', [Sequelize.fn('date_format', Sequelize.col('Order.createdAt'), '%Y-%m-%d'), 'createdAt'], - [Sequelize.col('Item.id'), 'id'], + [Sequelize.col('Item.id'), 'itemId'], [Sequelize.col('Item.thumbnail'), 'thumbnail'], [Sequelize.col('Item.title'), 'title'], 'quantity', From acf52ae57c528952c722ce0285aa562af86cab39 Mon Sep 17 00:00:00 2001 From: Seogeurim Date: Mon, 30 Aug 2021 17:09:39 +0900 Subject: [PATCH 65/84] =?UTF-8?q?refactor:=20history=20push=20path?= =?UTF-8?q?=EC=97=90=EC=84=9C=20page=20=EB=B0=8F=20type=20=EC=A0=95?= =?UTF-8?q?=EB=B3=B4=EB=A5=BC=20=EB=8B=B4=EC=A7=80=20=EC=95=8A=EB=8F=84?= =?UTF-8?q?=EB=A1=9D=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/components/smart-menu/large-menu.tsx | 5 ++--- client/src/components/smart-menu/medium-menu.tsx | 5 ++--- client/src/containers/item-container.tsx | 2 +- client/src/containers/search-container.tsx | 2 +- 4 files changed, 6 insertions(+), 8 deletions(-) diff --git a/client/src/components/smart-menu/large-menu.tsx b/client/src/components/smart-menu/large-menu.tsx index 6a1e6c9..3e4c32e 100644 --- a/client/src/components/smart-menu/large-menu.tsx +++ b/client/src/components/smart-menu/large-menu.tsx @@ -5,7 +5,6 @@ import { useHistory } from 'lib/router'; import arrow from 'assets/icons/arrow_forward.svg'; import { IMenu } from 'types/category'; -import { ESortType } from 'types/item'; import { SMART_MENU_BLOCK_DELAY } from 'constants/index'; import { ITEM_LIST_URL } from 'constants/urls'; @@ -103,7 +102,7 @@ const LargeMenu: FC = ({ }) => { const history = useHistory(); const goCategoryPage = useCallback( - (code: string) => () => history.push(`${ITEM_LIST_URL}?categoryId=${code}&pageId=1&type=${ESortType.RECOMMEND}`), + (code: string) => () => history.push(`${ITEM_LIST_URL}?categoryId=${code}`), [history], ); @@ -129,7 +128,7 @@ const LargeMenu: FC = ({ setLargeId(largeId); e.stopPropagation(); } else { - history.push(`${ITEM_LIST_URL}?categoryId=${large.code}&pageId=1&type=${ESortType.RECOMMEND}`); + history.push(`${ITEM_LIST_URL}?categoryId=${large.code}`); } }} isSelected={selectedLargeId === largeId} diff --git a/client/src/components/smart-menu/medium-menu.tsx b/client/src/components/smart-menu/medium-menu.tsx index 4b4f58d..33c24aa 100644 --- a/client/src/components/smart-menu/medium-menu.tsx +++ b/client/src/components/smart-menu/medium-menu.tsx @@ -5,7 +5,6 @@ import { useHistory } from 'lib/router'; import arrow from 'assets/icons/arrow_forward.svg'; import { IMenu } from 'types/category'; -import { ESortType } from 'types/item'; import { ITEM_LIST_URL } from 'constants/urls'; @@ -78,7 +77,7 @@ const Image = styled.img` const MediumMenu: FC = ({ menu, selectedLargeId, selectedMediumId, isMobile, setMediumId }) => { const history = useHistory(); const goCategoryPage = useCallback( - (code: string) => () => history.push(`${ITEM_LIST_URL}?categoryId=${code}&pageId=1&type=${ESortType.RECOMMEND}`), + (code: string) => () => history.push(`${ITEM_LIST_URL}?categoryId=${code}`), [history], ); @@ -100,7 +99,7 @@ const MediumMenu: FC = ({ menu, selectedLargeId, selectedMedium setMediumId(mediumId); e.stopPropagation(); } else { - history.push(`${ITEM_LIST_URL}?categoryId=${medium.code}&pageId=1&type=${ESortType.RECOMMEND}`); + history.push(`${ITEM_LIST_URL}?categoryId=${medium.code}`); } }} isSelected={selectedMediumId === mediumId} diff --git a/client/src/containers/item-container.tsx b/client/src/containers/item-container.tsx index 4cb4b04..7cb476c 100644 --- a/client/src/containers/item-container.tsx +++ b/client/src/containers/item-container.tsx @@ -23,7 +23,7 @@ const ItemContainer: FC = ({ item }) => { userId: auth.user.userId, })); - const goDetailPage = useCallback((id: number) => () => history.push(`${ITEM_URL}/${id}?pageId=1`), [history]); + const goDetailPage = useCallback((id: number) => () => history.push(`${ITEM_URL}/${id}`), [history]); const toggleIsLiked = () => { if (!isLiked) { diff --git a/client/src/containers/search-container.tsx b/client/src/containers/search-container.tsx index 8b90709..aa64931 100644 --- a/client/src/containers/search-container.tsx +++ b/client/src/containers/search-container.tsx @@ -57,7 +57,7 @@ const SearchContainer: FC = () => { const moveToSearchPage = (keyword: string) => { setSearch(keyword); saveRecentKeywords(keyword); - history.push(`${ITEM_LIST_URL}?search=${keyword}&pageId=1`); + history.push(`${ITEM_LIST_URL}?search=${keyword}`); }; const onChange = (e: React.ChangeEvent) => { From 34caaeb05a59338df3059c47ed592dea4f7611a6 Mon Sep 17 00:00:00 2001 From: Seogeurim Date: Mon, 30 Aug 2021 17:12:11 +0900 Subject: [PATCH 66/84] =?UTF-8?q?refactor:=20container=20=EC=BB=B4?= =?UTF-8?q?=ED=8F=AC=EB=84=8C=ED=8A=B8=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit pagination과 filter 방식에 따라 컨테이너 컴포넌트 수정 --- client/src/containers/my-order-list-container.tsx | 7 ++++--- client/src/containers/search-item-container.tsx | 8 +++++--- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/client/src/containers/my-order-list-container.tsx b/client/src/containers/my-order-list-container.tsx index 71191af..c61e4db 100644 --- a/client/src/containers/my-order-list-container.tsx +++ b/client/src/containers/my-order-list-container.tsx @@ -1,6 +1,6 @@ import React, { FC, useState, useEffect, useCallback } from 'react'; import { shallowEqual, useDispatch, useSelector } from 'react-redux'; -import { useHistory } from 'lib/router'; +import { useHistory, useQuery } from 'lib/router'; import { RootState } from 'store'; import { getOrders } from 'store/order'; @@ -17,8 +17,8 @@ const MyOrderListContainer: FC = () => { const [currentDate, setCurrentDate] = useState(''); const [select, setSelect] = useState(undefined); const history = useHistory(); + const query = useQuery(); const dispatch = useDispatch(); - const [pageId, setPageId] = useState(1); const { loading, user, orders, pageCount, totalCount, userLoading } = useSelector( ({ auth, loading, order }: RootState) => ({ @@ -33,9 +33,10 @@ const MyOrderListContainer: FC = () => { ); useEffect(() => { + const { pageId } = query; if (prevDate && currentDate) dispatch({ type: getOrders.type, payload: { pageId, prevDate, currentDate: getNextDay(currentDate) } }); - }, [dispatch, pageId, prevDate, currentDate]); + }, [query, dispatch, prevDate, currentDate]); useEffect(() => { if (!userLoading && !user) history.push('/'); diff --git a/client/src/containers/search-item-container.tsx b/client/src/containers/search-item-container.tsx index 412df0e..62c152b 100644 --- a/client/src/containers/search-item-container.tsx +++ b/client/src/containers/search-item-container.tsx @@ -2,11 +2,13 @@ import React, { FC, useEffect } from 'react'; import { shallowEqual, useDispatch, useSelector } from 'react-redux'; import { useQuery } from 'lib/router'; -import SearchItemWrapper from 'components/item/search-item/search-item-wrapper'; +import { ESortType } from 'types/item'; import { RootState } from 'store'; import { getListItem } from 'store/item'; +import SearchItemWrapper from 'components/item/search-item/search-item-wrapper'; + const SearchItemContainer: FC = () => { const query = useQuery(); const dispatch = useDispatch(); @@ -22,8 +24,8 @@ const SearchItemContainer: FC = () => { ); useEffect(() => { - const { categoryId, search, pageId, type } = query; - if ((categoryId || search) && pageId) { + const { categoryId, search, pageId = 1, type = ESortType.RECOMMEND } = query; + if (categoryId || search) { dispatch({ type: getListItem.type, payload: { categoryId, pageId, type, search } }); window.scrollTo(0, 0); } From adf672b6f54c1a8403d3ff0939601107e8e40efb Mon Sep 17 00:00:00 2001 From: Seogeurim Date: Mon, 30 Aug 2021 17:12:40 +0900 Subject: [PATCH 67/84] =?UTF-8?q?fix:=20=EB=A6=B0=ED=8A=B8=20=EC=98=A4?= =?UTF-8?q?=EB=A5=98=20=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/components/item-detail/detail.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/components/item-detail/detail.tsx b/client/src/components/item-detail/detail.tsx index 755b99f..0b5fdfa 100644 --- a/client/src/components/item-detail/detail.tsx +++ b/client/src/components/item-detail/detail.tsx @@ -1,4 +1,4 @@ -import React, { FC, useRef, Dispatch, SetStateAction } from 'react'; +import React, { FC, useRef } from 'react'; import styled from 'lib/woowahan-components'; import { IReview } from 'types/review'; From d1a7f0d4f07e79b7c8df946862cff02961f103d5 Mon Sep 17 00:00:00 2001 From: edegiil Date: Mon, 30 Aug 2021 17:27:58 +0900 Subject: [PATCH 68/84] =?UTF-8?q?fix:=20=EC=9A=B0=EC=95=84=ED=95=9C=20?= =?UTF-8?q?=EC=BB=B4=ED=8F=AC=EB=84=8C=ED=8A=B8=20boolean=20=EA=B0=92?= =?UTF-8?q?=EC=9D=84=20=EB=B0=9B=EC=9D=84=20=EC=88=98=20=EC=9E=88=EB=8F=84?= =?UTF-8?q?=EB=A1=9D=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../lib/woowahan-components/components/woowahan-component.tsx | 4 ++-- client/src/lib/woowahan-components/configs/react-props.ts | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/client/src/lib/woowahan-components/components/woowahan-component.tsx b/client/src/lib/woowahan-components/components/woowahan-component.tsx index 7ecd04b..f4aa51e 100644 --- a/client/src/lib/woowahan-components/components/woowahan-component.tsx +++ b/client/src/lib/woowahan-components/components/woowahan-component.tsx @@ -62,8 +62,8 @@ const woowahanComponent = Object.entries(props).forEach(([key, value]) => { if (typeof value === 'boolean') { - if (!reactProps.includes(key)) newProps[key.toLowerCase()] = value.toString(); - else newProps[key] = value.toString(); + if (!reactProps.includes(key)) newProps[key.toLowerCase()] = value ? 'true' : ''; + else newProps[key] = value; } else if (!reactProps.includes(key)) { newProps[key.toLowerCase()] = value; } else { diff --git a/client/src/lib/woowahan-components/configs/react-props.ts b/client/src/lib/woowahan-components/configs/react-props.ts index e5a2386..af49a7f 100644 --- a/client/src/lib/woowahan-components/configs/react-props.ts +++ b/client/src/lib/woowahan-components/configs/react-props.ts @@ -26,6 +26,7 @@ const reactProps = [ 'maxLength', 'onSubmit', 'htmlFor', + 'selected', ]; export default reactProps; From b73698acfe73bc14d3a175f723eac278af14705e Mon Sep 17 00:00:00 2001 From: Seogeurim Date: Mon, 30 Aug 2021 17:39:53 +0900 Subject: [PATCH 69/84] =?UTF-8?q?refactor:=20=ED=98=84=EC=9E=AC=20pathname?= =?UTF-8?q?=EC=9D=84=20history=EC=9D=98=20currentPath=EB=A1=9C=20=EB=B0=9B?= =?UTF-8?q?=EC=95=84=EC=98=A4=EB=8A=94=20=EB=B0=A9=EC=8B=9D=EC=9C=BC?= =?UTF-8?q?=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/components/common/pagination.tsx | 2 +- client/src/components/item/search-item/filter.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/client/src/components/common/pagination.tsx b/client/src/components/common/pagination.tsx index 5223e1f..ad45a01 100644 --- a/client/src/components/common/pagination.tsx +++ b/client/src/components/common/pagination.tsx @@ -41,7 +41,7 @@ const Pagination: FC = ({ className = '', pageCount, showCnt = (pageId: number) => { const searchParams = new URLSearchParams(window.location.search); searchParams.set('pageId', pageId.toString()); - history.push(`${window.location.pathname}?${searchParams.toString()}`); + history.push(`${history.currentPath}?${searchParams.toString()}`); }, [history], ); diff --git a/client/src/components/item/search-item/filter.tsx b/client/src/components/item/search-item/filter.tsx index bb98123..f5160c5 100644 --- a/client/src/components/item/search-item/filter.tsx +++ b/client/src/components/item/search-item/filter.tsx @@ -65,7 +65,7 @@ const Filter: FC = ({ total }) => { const searchParams = new URLSearchParams(window.location.search); searchParams.set('type', sortType); searchParams.set('pageId', '1'); - history.push(`${window.location.pathname}?${searchParams.toString()}`); + history.push(`${history.currentPath}?${searchParams.toString()}`); }, [history], ); From af874c23b3c764c3bef633a0c391b9120d26d4d3 Mon Sep 17 00:00:00 2001 From: Seogeurim Date: Mon, 30 Aug 2021 17:56:00 +0900 Subject: [PATCH 70/84] =?UTF-8?q?style:=20=EB=84=A4=EB=B8=8C=EB=B0=94=20?= =?UTF-8?q?=EC=9E=A5=EB=B0=94=EA=B5=AC=EB=8B=88=20count=20=EC=8A=A4?= =?UTF-8?q?=ED=83=80=EC=9D=BC=20=EC=A1=B0=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/components/common/navbar.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/client/src/components/common/navbar.tsx b/client/src/components/common/navbar.tsx index 1edb669..45cc57b 100644 --- a/client/src/components/common/navbar.tsx +++ b/client/src/components/common/navbar.tsx @@ -28,7 +28,9 @@ const Wrapper = styled.nav` position: relative; b { - ${props => props.theme?.weightBold}; + font-weight: ${props => props.theme?.weightBold}; + color: ${props => props.theme?.colorPrimary}; + margin-left: 3px; } .nav-link-list { From 133bdc0ef2dd9e795fcbfc22372c091ba533b2f7 Mon Sep 17 00:00:00 2001 From: Seogeurim Date: Mon, 30 Aug 2021 17:56:14 +0900 Subject: [PATCH 71/84] =?UTF-8?q?style:=20=EC=9E=A5=EB=B0=94=EA=B5=AC?= =?UTF-8?q?=EB=8B=88=20=ED=8E=98=EC=9D=B4=EC=A7=80=20gap=EC=9D=84=20margin?= =?UTF-8?q?=EC=9C=BC=EB=A1=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/components/cart/index.tsx | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/client/src/components/cart/index.tsx b/client/src/components/cart/index.tsx index c28535d..78496af 100644 --- a/client/src/components/cart/index.tsx +++ b/client/src/components/cart/index.tsx @@ -37,15 +37,22 @@ const ButtonDiv = styled.div` flex-wrap: wrap; justify-content: space-between; padding-bottom: 50px; + @media all and (max-width: 800px) { - gap: 14px; justify-content: center; + + > button:first-child { + margin-bottom: 14px; + } } `; const OrderButtonDiv = styled.div` display: flex; - gap: 10px; + + button:first-child { + margin-right: 10px; + } `; const getCartItemIndexes = () => { From 5bdb5df30b1c259d63f20a8a6b2ea26c24bb7d36 Mon Sep 17 00:00:00 2001 From: Seogeurim Date: Mon, 30 Aug 2021 17:57:51 +0900 Subject: [PATCH 72/84] =?UTF-8?q?style:=20search=20bar=20=EC=A0=81?= =?UTF-8?q?=EC=9A=A9=EB=90=98=EC=A7=80=20=EC=95=8A=EB=8A=94=20gap=20style?= =?UTF-8?q?=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/components/search-bar/index.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/client/src/components/search-bar/index.tsx b/client/src/components/search-bar/index.tsx index cbf6053..0cf508e 100644 --- a/client/src/components/search-bar/index.tsx +++ b/client/src/components/search-bar/index.tsx @@ -55,7 +55,6 @@ const SearchBox = styled.div` width: 430px; display: flex; align-items: center; - gap: 12px; position: relative; .search-input { From bab23bd76a7feec28daf22d37957233d1de71e2c Mon Sep 17 00:00:00 2001 From: Seogeurim Date: Mon, 30 Aug 2021 18:03:08 +0900 Subject: [PATCH 73/84] =?UTF-8?q?style:=20price-calculator=20gap=EC=9D=84?= =?UTF-8?q?=20margin=EC=9C=BC=EB=A1=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/common/price-calculator.tsx | 24 ++++++++++--------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/client/src/components/common/price-calculator.tsx b/client/src/components/common/price-calculator.tsx index 209b377..7b97fcc 100644 --- a/client/src/components/common/price-calculator.tsx +++ b/client/src/components/common/price-calculator.tsx @@ -17,25 +17,24 @@ const Box = styled.div` display: flex; flex-wrap: wrap; justify-content: flex-end; - ${props => props.theme?.mobile} { - justify-content: center; - } align-items: center; border: 2px solid ${({ theme }) => theme?.colorLineLight}; margin: 50px 0 30px; - gap: 24px; + + .calc-icon { + margin: 0 24px; + } .column { display: flex; align-items: center; - gap: 24px; } ${({ theme }) => theme?.mobile} { - gap: 12px; + justify-content: center; - .column { - gap: 12px; + .calc-icon { + margin: 0 12px; } } `; @@ -44,7 +43,10 @@ const BoxItem = styled.div` display: flex; flex-direction: column; align-items: flex-end; - gap: 10px; + + div:first-child { + margin-bottom: 10px; + } .title { font-size: 16px; @@ -78,13 +80,13 @@ const PriceCalculator: FC = ({ prices, totalCount }) => {
총 {totalCount}개의 상품금액
{formatPrice(totalPrice)}원
- 더하기 + 더하기
배송비
0원
- 합계 + 합계
합계
From 4fa11166a886003289ca0f95ad34460bc6081020 Mon Sep 17 00:00:00 2001 From: Seogeurim Date: Mon, 30 Aug 2021 18:10:17 +0900 Subject: [PATCH 74/84] =?UTF-8?q?style:=20=EC=9E=A5=EB=B0=94=EA=B5=AC?= =?UTF-8?q?=EB=8B=88=20=EB=B2=84=ED=8A=BC=20margin=20=EB=AC=B8=EC=A0=9C=20?= =?UTF-8?q?=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit gap을 margin으로 바꾸면서 다른 버튼의 크기가 커지는 문제 때문에 margin 조정 --- client/src/components/cart/index.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/client/src/components/cart/index.tsx b/client/src/components/cart/index.tsx index 78496af..3a20b70 100644 --- a/client/src/components/cart/index.tsx +++ b/client/src/components/cart/index.tsx @@ -42,7 +42,8 @@ const ButtonDiv = styled.div` justify-content: center; > button:first-child { - margin-bottom: 14px; + margin: 14px; + margin-top: 0; } } `; From 834eeb4ff1d43289df6fbcba54893900d2b5eea0 Mon Sep 17 00:00:00 2001 From: negu63 Date: Mon, 30 Aug 2021 18:18:03 +0900 Subject: [PATCH 75/84] =?UTF-8?q?fix:=20=EC=8A=A4=EB=A7=88=ED=8A=B8?= =?UTF-8?q?=EB=A9=94=EB=89=B4=20=EC=9D=B4=EB=B2=A4=ED=8A=B8=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/components/smart-menu/index.tsx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/client/src/components/smart-menu/index.tsx b/client/src/components/smart-menu/index.tsx index 905ceaa..01cb810 100644 --- a/client/src/components/smart-menu/index.tsx +++ b/client/src/components/smart-menu/index.tsx @@ -73,7 +73,9 @@ const SmartMenu: FC = React.memo(({ currentMenu, menu }) => { return ( { - setOpenStatus(true); + if (isLaptop(width)) { + setOpenStatus(true); + } }} onMouseLeave={() => { setOpenStatus(false); @@ -84,7 +86,7 @@ const SmartMenu: FC = React.memo(({ currentMenu, menu }) => { }, SMART_MENU_BLOCK_DELAY); }} onClick={() => { - if (isSmall(width)) { + if (!isLaptop(width)) { setOpenStatus(!isOpen); } }} From ffe9392260a660589d69f9d75f05647b6ca5a218 Mon Sep 17 00:00:00 2001 From: yoonminsang Date: Mon, 30 Aug 2021 18:12:58 +0900 Subject: [PATCH 76/84] =?UTF-8?q?feat:=20react=20title=20=EC=A0=81?= =?UTF-8?q?=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/package.json | 1 + client/src/constants/index.ts | 2 ++ .../src/containers/item-detail-container.tsx | 8 +++++++ client/src/index.tsx | 5 +++- client/src/pages/cart-page.tsx | 5 ++++ client/src/pages/item-list-page.tsx | 4 ++++ client/src/pages/main-page.tsx | 4 ++++ client/src/pages/my-address-page.tsx | 5 ++++ client/src/pages/my-order-list-page.tsx | 5 ++++ client/src/pages/not-found-page.tsx | 4 ++++ client/src/pages/order-page.tsx | 5 ++++ client/src/pages/signin-page.tsx | 5 ++++ client/src/pages/signup-page.tsx | 5 ++++ client/yarn.lock | 23 ++++++++++++++++++- 14 files changed, 79 insertions(+), 2 deletions(-) diff --git a/client/package.json b/client/package.json index a4518f8..31f689c 100644 --- a/client/package.json +++ b/client/package.json @@ -29,6 +29,7 @@ "react": "^17.0.2", "react-daum-postcode": "^2.0.6", "react-dom": "^17.0.2", + "react-helmet-async": "^1.1.2", "react-redux": "^7.2.4", "redux": "^4.1.1", "redux-logger": "^3.0.6", diff --git a/client/src/constants/index.ts b/client/src/constants/index.ts index 622a944..f04c047 100644 --- a/client/src/constants/index.ts +++ b/client/src/constants/index.ts @@ -25,3 +25,5 @@ export const MY_PAGE_NAV = [ { link: ORDER_LIST_URL, name: '주문목록 조회' }, { link: ADDRESS_URL, name: '배송지 관리' }, ]; + +export const TITLE = '배민문구사 - '; diff --git a/client/src/containers/item-detail-container.tsx b/client/src/containers/item-detail-container.tsx index d5092d8..17f1544 100644 --- a/client/src/containers/item-detail-container.tsx +++ b/client/src/containers/item-detail-container.tsx @@ -15,6 +15,8 @@ import ItemInfo from 'components/item-detail/item-info'; import Detail from 'components/item-detail/detail'; import ReviewPost from 'components/item-detail/review-post'; import LoginModal from 'components/auth/login-modal'; +import { Helmet } from 'react-helmet-async'; +import { TITLE } from 'constants/index'; const ItemDetailContainer: FC = () => { const [postTitle, setPostTitle] = useState(''); @@ -155,6 +157,12 @@ const ItemDetailContainer: FC = () => { return ( <> + + + {TITLE} + {title} + + - + + + , document.getElementById('root'), ); diff --git a/client/src/pages/cart-page.tsx b/client/src/pages/cart-page.tsx index e687796..80fa716 100644 --- a/client/src/pages/cart-page.tsx +++ b/client/src/pages/cart-page.tsx @@ -1,10 +1,12 @@ import React, { ReactElement } from 'react'; +import { Helmet } from 'react-helmet-async'; import useWindowSize from 'hooks/use-window-size'; import NavbarContainer from 'containers/navbar-container'; import MenuHeader from 'components/common/menu-header'; import { Layout } from 'components'; import Cart from 'components/cart'; +import { TITLE } from 'constants/index'; const CartPage = (): ReactElement => { const { width } = useWindowSize(); @@ -12,6 +14,9 @@ const CartPage = (): ReactElement => { return ( <> + + {TITLE}장바구니 + diff --git a/client/src/pages/item-list-page.tsx b/client/src/pages/item-list-page.tsx index a149e02..ca274fb 100644 --- a/client/src/pages/item-list-page.tsx +++ b/client/src/pages/item-list-page.tsx @@ -1,6 +1,7 @@ import React, { ReactElement } from 'react'; import styled from 'lib/woowahan-components'; import { useQuery } from 'lib/router'; +import { Helmet } from 'react-helmet-async'; import useWindowSize from 'hooks/use-window-size'; @@ -23,6 +24,9 @@ const ItemListPage = (): ReactElement => { return ( <> + + 배민문구사 + diff --git a/client/src/pages/main-page.tsx b/client/src/pages/main-page.tsx index 37a925b..42582b6 100644 --- a/client/src/pages/main-page.tsx +++ b/client/src/pages/main-page.tsx @@ -1,5 +1,6 @@ import React, { ReactElement } from 'react'; import styled from 'lib/woowahan-components'; +import { Helmet } from 'react-helmet-async'; import useWindowSize from 'hooks/use-window-size'; @@ -30,6 +31,9 @@ const MainPage = (): ReactElement => { return ( <> + + 배민문구사 + diff --git a/client/src/pages/my-address-page.tsx b/client/src/pages/my-address-page.tsx index 5860c21..246422f 100644 --- a/client/src/pages/my-address-page.tsx +++ b/client/src/pages/my-address-page.tsx @@ -1,4 +1,5 @@ import React, { ReactElement } from 'react'; +import { Helmet } from 'react-helmet-async'; import useWindowSize from 'hooks/use-window-size'; @@ -6,6 +7,7 @@ import { Layout } from 'components'; import MenuHeader from 'components/common/menu-header'; import NavbarContainer from 'containers/navbar-container'; import MyAddressContainer from 'containers/my-address-container'; +import { TITLE } from 'constants/index'; const MyAddressPage = (): ReactElement => { const { width } = useWindowSize(); @@ -13,6 +15,9 @@ const MyAddressPage = (): ReactElement => { return ( <> + + {TITLE}마이페이지 + diff --git a/client/src/pages/my-order-list-page.tsx b/client/src/pages/my-order-list-page.tsx index 68e0557..e218423 100644 --- a/client/src/pages/my-order-list-page.tsx +++ b/client/src/pages/my-order-list-page.tsx @@ -1,8 +1,10 @@ import React, { ReactElement } from 'react'; +import { Helmet } from 'react-helmet-async'; import useWindowSize from 'hooks/use-window-size'; import { Layout } from 'components'; +import { TITLE } from 'constants/index'; import MenuHeader from 'components/common/menu-header'; import NavbarContainer from 'containers/navbar-container'; import MyOrderListContainer from 'containers/my-order-list-container'; @@ -13,6 +15,9 @@ const MyOrderListPage = (): ReactElement => { return ( <> + + {TITLE}마이페이지 + diff --git a/client/src/pages/not-found-page.tsx b/client/src/pages/not-found-page.tsx index 48f1c34..2f138e6 100644 --- a/client/src/pages/not-found-page.tsx +++ b/client/src/pages/not-found-page.tsx @@ -1,5 +1,6 @@ import React, { ReactElement } from 'react'; import styled from 'lib/woowahan-components'; +import { Helmet } from 'react-helmet-async'; import useWindowSize from 'hooks/use-window-size'; @@ -43,6 +44,9 @@ const NotFoundPage = (): ReactElement => { return ( <> + + 404 + diff --git a/client/src/pages/order-page.tsx b/client/src/pages/order-page.tsx index f812fc5..172ff8c 100644 --- a/client/src/pages/order-page.tsx +++ b/client/src/pages/order-page.tsx @@ -1,10 +1,12 @@ import React, { ReactElement } from 'react'; import useWindowSize from 'hooks/use-window-size'; +import { Helmet } from 'react-helmet-async'; import MenuHeader from 'components/common/menu-header'; import { Layout } from 'components'; import NavbarContainer from 'containers/navbar-container'; import OrderContainer from 'containers/order-container'; +import { TITLE } from 'constants/index'; const OrderPage = (): ReactElement => { const { width } = useWindowSize(); @@ -12,6 +14,9 @@ const OrderPage = (): ReactElement => { return ( <> + + {TITLE}주문하기 + diff --git a/client/src/pages/signin-page.tsx b/client/src/pages/signin-page.tsx index bb61455..7520e31 100644 --- a/client/src/pages/signin-page.tsx +++ b/client/src/pages/signin-page.tsx @@ -1,10 +1,12 @@ import React, { ReactElement } from 'react'; +import { Helmet } from 'react-helmet-async'; import useWindowSize from 'hooks/use-window-size'; import { Layout } from 'components'; import NavbarContainer from 'containers/navbar-container'; import SigninContainer from 'containers/signin-container'; +import { TITLE } from 'constants/index'; const SigninPage = (): ReactElement => { const { width } = useWindowSize(); @@ -12,6 +14,9 @@ const SigninPage = (): ReactElement => { return ( <> + + {TITLE}로그인 + diff --git a/client/src/pages/signup-page.tsx b/client/src/pages/signup-page.tsx index f00e994..fcf16b5 100644 --- a/client/src/pages/signup-page.tsx +++ b/client/src/pages/signup-page.tsx @@ -1,10 +1,12 @@ import React, { ReactElement } from 'react'; +import { Helmet } from 'react-helmet-async'; import useWindowSize from 'hooks/use-window-size'; import { Layout } from 'components'; import NavbarContainer from 'containers/navbar-container'; import SignupContainer from 'containers/signup-container'; +import { TITLE } from 'constants/index'; const SignupPage = (): ReactElement => { const { width } = useWindowSize(); @@ -12,6 +14,9 @@ const SignupPage = (): ReactElement => { return ( <> + + {TITLE}회원가입 + diff --git a/client/yarn.lock b/client/yarn.lock index 298d251..443dc30 100644 --- a/client/yarn.lock +++ b/client/yarn.lock @@ -4725,7 +4725,7 @@ interpret@^2.2.0: resolved "https://registry.yarnpkg.com/interpret/-/interpret-2.2.0.tgz#1a78a0b5965c40a5416d007ad6f50ad27c417df9" integrity sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw== -invariant@^2.2.2: +invariant@^2.2.2, invariant@^2.2.4: version "2.2.4" resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6" integrity sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA== @@ -7157,6 +7157,22 @@ react-dom@^17.0.2: object-assign "^4.1.1" scheduler "^0.20.2" +react-fast-compare@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/react-fast-compare/-/react-fast-compare-3.2.0.tgz#641a9da81b6a6320f270e89724fb45a0b39e43bb" + integrity sha512-rtGImPZ0YyLrscKI9xTpV8psd6I8VAtjKCzQDlzyDvqJA8XOW78TXYQwNRNd8g8JZnDu8q9Fu/1v4HPAVwVdHA== + +react-helmet-async@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/react-helmet-async/-/react-helmet-async-1.1.2.tgz#653b7e6bbfdd239c5dcd6b8df2811c7a363b8334" + integrity sha512-LTTzDDkyIleT/JJ6T/uqx7Y8qi1EuPPSiJawQY/nHHz0h7SPDT6HxP1YDDQx/fzcVxCqpWEEMS3QdrSrNkJYhg== + dependencies: + "@babel/runtime" "^7.12.5" + invariant "^2.2.4" + prop-types "^15.7.2" + react-fast-compare "^3.2.0" + shallowequal "^1.1.0" + react-is@^16.13.1, react-is@^16.7.0, react-is@^16.8.1: version "16.13.1" resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" @@ -7727,6 +7743,11 @@ shallow-clone@^3.0.0: dependencies: kind-of "^6.0.2" +shallowequal@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/shallowequal/-/shallowequal-1.1.0.tgz#188d521de95b9087404fd4dcb68b13df0ae4e7f8" + integrity sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ== + shebang-command@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" From e4ba0f3fa907745ca9b127e3f221e86941008de4 Mon Sep 17 00:00:00 2001 From: yoonminsang Date: Mon, 30 Aug 2021 20:42:05 +0900 Subject: [PATCH 77/84] =?UTF-8?q?feat:=20=EC=A0=84=EC=97=AD=20=EC=8A=A4?= =?UTF-8?q?=ED=86=A0=EC=96=B4=20cart=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/store/cart.ts | 30 ++++++++++++++++++++++++++++++ client/src/store/index.ts | 2 ++ 2 files changed, 32 insertions(+) create mode 100644 client/src/store/cart.ts diff --git a/client/src/store/cart.ts b/client/src/store/cart.ts new file mode 100644 index 0000000..893702a --- /dev/null +++ b/client/src/store/cart.ts @@ -0,0 +1,30 @@ +import { createSlice, PayloadAction } from '@reduxjs/toolkit'; + +interface StateProps { + cart: string; +} + +const initialState: StateProps = { + cart: '', +}; + +const cartSlice = createSlice({ + name: 'cart', + initialState, + reducers: { + loadCart: state => { + const cart = localStorage.getItem('cart'); + if (cart) state.cart = cart; + return state; + }, + setCart: (state, action: PayloadAction) => { + localStorage.setItem('cart', action.payload); + state.cart = action.payload; + return state; + }, + }, +}); + +const { actions, reducer: cartReducer } = cartSlice; +export const { loadCart, setCart } = actions; +export { cartReducer }; diff --git a/client/src/store/index.ts b/client/src/store/index.ts index 9fb969d..42ade2d 100644 --- a/client/src/store/index.ts +++ b/client/src/store/index.ts @@ -8,6 +8,7 @@ import { orderReducer, orderSaga } from './order'; import { addressReducer, addressSaga } from './address'; import { reviewReducer, reviewSaga } from './review'; import { likeReducer, likeSaga } from './like'; +import { cartReducer } from './cart'; const rootReducer = combineReducers({ auth: authReducer, @@ -18,6 +19,7 @@ const rootReducer = combineReducers({ address: addressReducer, review: reviewReducer, like: likeReducer, + cart: cartReducer, }); export type RootState = ReturnType; From edfe9195ba2a5a9e9f71f6e0594511ea92052d90 Mon Sep 17 00:00:00 2001 From: yoonminsang Date: Mon, 30 Aug 2021 20:42:27 +0900 Subject: [PATCH 78/84] =?UTF-8?q?feat:=20=EC=B2=98=EC=9D=8C=20=EC=8B=A4?= =?UTF-8?q?=ED=96=89=EC=8B=9C=20cart=EB=A5=BC=20=EB=A6=AC=EB=8D=95?= =?UTF-8?q?=EC=8A=A4=EC=97=90=20=EB=84=A3=EC=96=B4=EC=A4=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/index.tsx | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/client/src/index.tsx b/client/src/index.tsx index 7f62701..fd4c32b 100644 --- a/client/src/index.tsx +++ b/client/src/index.tsx @@ -6,6 +6,7 @@ import { configureStore } from '@reduxjs/toolkit'; import { HelmetProvider } from 'react-helmet-async'; import { getUser } from 'store/auth'; import { getCategories } from 'store/category'; +import { loadCart } from 'store/cart'; import logger from 'redux-logger'; import rootReducer, { rootSaga } from './store'; import App from './App'; @@ -32,8 +33,13 @@ function loadCategories() { store.dispatch({ type: getCategories.type }); } +function loadCarts() { + store.dispatch({ type: loadCart.type }); +} + loadUser(); loadCategories(); +loadCarts(); ReactDOM.render( From 9d4efca7a3180fc57495f4a2f2872272d8be0a99 Mon Sep 17 00:00:00 2001 From: yoonminsang Date: Mon, 30 Aug 2021 20:42:58 +0900 Subject: [PATCH 79/84] =?UTF-8?q?feat:=20=EC=B9=B4=ED=8A=B8=EB=A5=BC=20?= =?UTF-8?q?=EC=A0=84=EC=97=AD=EC=9C=BC=EB=A1=9C=20=EA=B4=80=EB=A6=AC?= =?UTF-8?q?=ED=95=98=EB=A9=B4=EC=84=9C=20=EB=B0=94=EB=80=8C=EB=8A=94=20?= =?UTF-8?q?=EC=BB=A8=ED=85=8C=EC=9D=B4=EB=84=88=20=EB=B0=8F=20=EC=BB=B4?= =?UTF-8?q?=ED=8F=AC=EB=84=8C=ED=8A=B8=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/components/cart/index.tsx | 42 +++++++++---------- client/src/components/common/navbar.tsx | 14 +++---- .../src/containers/item-detail-container.tsx | 11 +++-- client/src/containers/navbar-container.tsx | 5 ++- client/src/containers/order-container.tsx | 10 +++-- client/src/utils/cart-generator.ts | 4 +- 6 files changed, 46 insertions(+), 40 deletions(-) diff --git a/client/src/components/cart/index.tsx b/client/src/components/cart/index.tsx index 3a20b70..a612a0f 100644 --- a/client/src/components/cart/index.tsx +++ b/client/src/components/cart/index.tsx @@ -1,5 +1,5 @@ import React, { useState, useCallback, Fragment, FC, useEffect } from 'react'; -import { useSelector } from 'react-redux'; +import { useDispatch, useSelector } from 'react-redux'; import styled from 'lib/woowahan-components'; import { useHistory } from 'lib/router'; @@ -9,6 +9,7 @@ import { cartGenerator } from 'utils/cart-generator'; import { RootState } from 'store'; import { TextButton, PriceCalculator } from 'components'; +import { setCart } from 'store/cart'; import LoginModal from 'components/auth/login-modal'; import { TableSection, CartItem } from './table-section'; @@ -55,47 +56,46 @@ const OrderButtonDiv = styled.div` margin-right: 10px; } `; - -const getCartItemIndexes = () => { - const cartItems = cartGenerator(); - const indexes: number[] = []; - cartItems.forEach((item, index) => indexes.push(index)); - return indexes; -}; - const Cart: FC = () => { + const { userId, cart } = useSelector(({ auth, cart }: RootState) => ({ + userId: auth.user.userId, + cart: cart.cart, + })); + const getCartItemIndexes = () => { + const cartItems = cartGenerator(cart); + const indexes: number[] = []; + cartItems.forEach((item, index) => indexes.push(index)); + return indexes; + }; const [prices, setPrices] = useState([0]); const [totalCount, setTotalCount] = useState(0); - const [cartItems, setCartItems] = useState(cartGenerator()); + const [cartItems, setCartItems] = useState(cartGenerator(cart)); const [checkAll, setCheckAll] = useState(true); const [checkedItems, setCheckedItems] = useState(new Set(getCartItemIndexes())); const [modalVisible, setModalVisible] = useState(false); + const dispatch = useDispatch(); const history = useHistory(); const onClick = useCallback(() => history.goBack(), [history]); - const { userId } = useSelector(({ auth }: RootState) => ({ - userId: auth.user.userId, - })); - - const deleteSelectCartItem = () => { + const deleteSelectCartItem = useCallback(() => { const data = localStorage.getItem('select') as string; const select = data.split(','); - let cartItems = cartGenerator(); + let cartItems = cartGenerator(cart); cartItems = cartItems.filter((item, index) => select.indexOf(index.toString()) < 0); let cartItemsString = ''; cartItems.forEach(item => { cartItemsString += `${item.id},${item.thumbnail},${item.title},${item.count},${item.price},`; }); cartItemsString = cartItemsString.slice(0, cartItemsString.length - 1); - localStorage.setItem('cart', cartItemsString); + dispatch({ type: setCart, cartItemsString }); localStorage.removeItem('select'); - setCartItems(cartGenerator()); + setCartItems(cartGenerator(cart)); setPrices([0]); setTotalCount(0); setCheckAll(false); setCheckedItems(new Set()); - }; + }, [cart, dispatch]); const orderCartItem = (isAll: boolean) => { let selectCartItems: CartItem[] = []; @@ -128,7 +128,7 @@ const Cart: FC = () => { const updatePrice = useCallback( (set: Set) => { - const cartItems = cartGenerator(); + const cartItems = cartGenerator(cart); const prices = [] as number[]; let totalCount = 0; Array.from(set).forEach(index => { @@ -142,7 +142,7 @@ const Cart: FC = () => { setPrices(prices); setTotalCount(totalCount); }, - [setPrices, setTotalCount], + [setPrices, setTotalCount, cart], ); useEffect(() => { diff --git a/client/src/components/common/navbar.tsx b/client/src/components/common/navbar.tsx index 45cc57b..45d7f55 100644 --- a/client/src/components/common/navbar.tsx +++ b/client/src/components/common/navbar.tsx @@ -1,4 +1,4 @@ -import React, { FC } from 'react'; +import React, { FC, useCallback } from 'react'; import { Link } from 'lib/router'; import styled from 'lib/woowahan-components'; @@ -17,6 +17,7 @@ interface NavbarProps { isMobile: boolean; userId: string | null | undefined; onLogout: () => void; + cart: string; } const Wrapper = styled.nav` @@ -76,12 +77,11 @@ const Wrapper = styled.nav` } `; -const cartCount = (): number => { - const cartItems = cartGenerator(); - return cartItems.length; -}; - -const Navbar: FC = React.memo(({ displayMain, isMobile, userId, onLogout }) => { +const Navbar: FC = React.memo(({ displayMain, isMobile, userId, onLogout, cart }) => { + const cartCount = useCallback((): number => { + const cartItems = cartGenerator(cart); + return cartItems.length; + }, [cart]); return ( {isMobile && ( diff --git a/client/src/containers/item-detail-container.tsx b/client/src/containers/item-detail-container.tsx index 17f1544..9268121 100644 --- a/client/src/containers/item-detail-container.tsx +++ b/client/src/containers/item-detail-container.tsx @@ -17,6 +17,7 @@ import ReviewPost from 'components/item-detail/review-post'; import LoginModal from 'components/auth/login-modal'; import { Helmet } from 'react-helmet-async'; import { TITLE } from 'constants/index'; +import { setCart } from 'store/cart'; const ItemDetailContainer: FC = () => { const [postTitle, setPostTitle] = useState(''); @@ -48,8 +49,9 @@ const ItemDetailContainer: FC = () => { reviewSubmitLoading, itemLoading, isPaid, + cart, } = useSelector( - ({ item, auth, review, loading }: RootState) => ({ + ({ item, auth, review, loading, cart }: RootState) => ({ thumbnail: item.item.thumbnail, title: item.item.title, price: item.item.price, @@ -67,6 +69,7 @@ const ItemDetailContainer: FC = () => { reviewSubmitLoading: loading['review/postReview'], itemLoading: loading['item/getItem'], isPaid: item.item.isPaid, + cart: cart.cart, }), shallowEqual, ); @@ -104,8 +107,8 @@ const ItemDetailContainer: FC = () => { const onSubmitCart = (count: number) => { let cartItemsString = ''; - if (localStorage.getItem('cart') !== null) { - const cartItems = cartGenerator(); + if (cart !== null) { + const cartItems = cartGenerator(cart); if (cartItems.some(item => item.id === id)) { cartItems.forEach((item, index) => { @@ -129,7 +132,7 @@ const ItemDetailContainer: FC = () => { } else { cartItemsString += `${id},${thumbnail},${title},${count},${price}`; } - localStorage.setItem('cart', cartItemsString); + dispatch({ type: setCart.type, payload: cartItemsString }); }; const onBuy = () => { diff --git a/client/src/containers/navbar-container.tsx b/client/src/containers/navbar-container.tsx index 88b96a4..0c7f73a 100644 --- a/client/src/containers/navbar-container.tsx +++ b/client/src/containers/navbar-container.tsx @@ -13,8 +13,9 @@ interface NavbarProps { } const NavbarContainer: FC = ({ displayMain = false, isMobile }) => { const [modalVisible, setModalVisible] = useState(false); - const { userId } = useSelector(({ auth }: RootState) => ({ + const { userId, cart } = useSelector(({ auth, cart }: RootState) => ({ userId: auth.user.userId, + cart: cart.cart, })); const dispatch = useDispatch(); @@ -26,7 +27,7 @@ const NavbarContainer: FC = ({ displayMain = false, isMobile }) => return ( <> - + {modalVisible && } ); diff --git a/client/src/containers/order-container.tsx b/client/src/containers/order-container.tsx index 51ea8c4..8c8742b 100644 --- a/client/src/containers/order-container.tsx +++ b/client/src/containers/order-container.tsx @@ -17,6 +17,7 @@ import { } from 'utils/validation/order-validation'; import { cartGenerator } from 'utils/cart-generator'; import { CartItem } from 'types/cart'; +import { setCart } from 'store/cart'; interface IOrderItems { id: string; @@ -61,14 +62,15 @@ const OrderContainer: FC = () => { const [address, setAddress] = useState(''); const [addressDetail, setAddressDetail] = useState(''); const [addressChecked, setaddressChecked] = useState('기타'); - const { userId, submitError, itemsData, getLoading, submitLoading, addresses } = useSelector( - ({ auth, order, loading, address }: RootState) => ({ + const { userId, submitError, itemsData, getLoading, submitLoading, addresses, cart } = useSelector( + ({ auth, order, loading, address, cart }: RootState) => ({ userId: auth.user.userId || '', submitError: order.postError || '', itemsData: order.orderItems, getLoading: loading['order/getOrderItems'], submitLoading: loading['order/postOrder'], addresses: address.list, + cart: cart.cart, }), shallowEqual, ); @@ -137,7 +139,7 @@ const OrderContainer: FC = () => { const selectedItems = data.split(','); const selectedItemIds: string[] = []; selectedItems.forEach(item => selectedItemIds.push(item.split('-')[0])); - const cartItems = cartGenerator(); + const cartItems = cartGenerator(cart); const updateItems: CartItem[] = []; cartItems.forEach(item => { if (!selectedItemIds.includes(item.id)) { @@ -149,7 +151,7 @@ const OrderContainer: FC = () => { cartItemsString += `${item.id},${item.thumbnail},${item.title},${item.count},${item.price},`; }); cartItemsString = cartItemsString.substring(0, cartItemsString.length - 1); - localStorage.setItem('cart', cartItemsString); + dispatch({ type: setCart.type, payload: cartItemsString }); }; const onFocusOutPhone = () => { diff --git a/client/src/utils/cart-generator.ts b/client/src/utils/cart-generator.ts index 93ba032..4c8c0d0 100644 --- a/client/src/utils/cart-generator.ts +++ b/client/src/utils/cart-generator.ts @@ -1,10 +1,10 @@ import { CartItem } from 'types/cart'; import { cartValidator } from './validation/cart-validator'; -const cartGenerator = (): CartItem[] => { +const cartGenerator = (data: string): CartItem[] => { if (cartValidator()) { const cartItems: CartItem[] = []; - const data = localStorage.getItem('cart') as string; + const cartData = data.split(','); cartData.forEach((value, idx) => { const num = Math.floor(idx / 5); From e5b17a155d9709f65eac47c52549e82e5198dd03 Mon Sep 17 00:00:00 2001 From: yoonminsang Date: Mon, 30 Aug 2021 22:14:17 +0900 Subject: [PATCH 80/84] =?UTF-8?q?fix:=20=EC=B9=B4=ED=8A=B8=EC=95=84?= =?UTF-8?q?=EC=9D=B4=ED=85=9C=20=EC=98=A4=EB=A5=98=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/components/cart/index.tsx | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/client/src/components/cart/index.tsx b/client/src/components/cart/index.tsx index a612a0f..9fa09d9 100644 --- a/client/src/components/cart/index.tsx +++ b/client/src/components/cart/index.tsx @@ -76,6 +76,10 @@ const Cart: FC = () => { const dispatch = useDispatch(); const history = useHistory(); + useEffect(() => { + setCartItems(cartGenerator(cart)); + }, [cart]); + const onClick = useCallback(() => history.goBack(), [history]); const deleteSelectCartItem = useCallback(() => { @@ -88,9 +92,8 @@ const Cart: FC = () => { cartItemsString += `${item.id},${item.thumbnail},${item.title},${item.count},${item.price},`; }); cartItemsString = cartItemsString.slice(0, cartItemsString.length - 1); - dispatch({ type: setCart, cartItemsString }); + dispatch({ type: setCart, payload: cartItemsString }); localStorage.removeItem('select'); - setCartItems(cartGenerator(cart)); setPrices([0]); setTotalCount(0); setCheckAll(false); From 2f6fc84ee159b3584f7eda17edc246f587c1b0da Mon Sep 17 00:00:00 2001 From: yoonminsang Date: Mon, 30 Aug 2021 22:45:39 +0900 Subject: [PATCH 81/84] =?UTF-8?q?fix:=20=EC=A3=BC=EB=AC=B8=ED=95=98?= =?UTF-8?q?=EA=B8=B0=20=EC=95=84=EC=9D=B4=ED=85=9C=20=ED=95=A0=EC=9D=B8=20?= =?UTF-8?q?=EC=A4=91=EB=B3=B5=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server/src/repositories/items.ts | 2 -- server/src/services/items.ts | 19 ++----------------- 2 files changed, 2 insertions(+), 19 deletions(-) diff --git a/server/src/repositories/items.ts b/server/src/repositories/items.ts index 9c9fdc7..ff378ea 100644 --- a/server/src/repositories/items.ts +++ b/server/src/repositories/items.ts @@ -343,8 +343,6 @@ const getOrderItems = async (itemIDs: string[]): Promise { +async function getOrderItems(id: string): Promise[]> { const itemIDs = id.split(','); const items = await itemRepository.getOrderItems(itemIDs); - - const itemData: IOrderItem[] = items.map(item => { - const salePercent = item.getDataValue('salePercent'); - const price = Number(item.getDataValue('price')); - - const saledPrice = Math.round(price - (price * salePercent) / 100); - - return { - id: item.getDataValue('id'), - title: item.getDataValue('title'), - thumbnail: item.getDataValue('thumbnail'), - price: saledPrice, - }; - }); - - return itemData; + return items; } export default { From 9136c4184b7f9a9bb6cd9f60f62a340954f79566 Mon Sep 17 00:00:00 2001 From: Seogeurim Date: Mon, 30 Aug 2021 22:55:00 +0900 Subject: [PATCH 82/84] =?UTF-8?q?style:=20=EC=97=90=EB=9F=AC=20=EB=A9=94?= =?UTF-8?q?=EC=8B=9C=EC=A7=80=20=EA=B0=84=EA=B2=A9=20=EC=A1=B0=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/components/auth/form.tsx | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/client/src/components/auth/form.tsx b/client/src/components/auth/form.tsx index e58c5f3..e65bf34 100644 --- a/client/src/components/auth/form.tsx +++ b/client/src/components/auth/form.tsx @@ -59,6 +59,10 @@ const Form = styled.form` .auth-input { margin-bottom: 20px; } + + .auth-check { + margin-bottom: 12px; + } `; const Image = styled.img` @@ -158,7 +162,11 @@ const AuthForm: FC = ({ onChange={onChange} maxLength={20} /> - {isSignup && } + {isSignup && ( +
+ +
+ )} {error} {!isSignup && ( From 3bb435f3138def84e0df4da516457dda3a05092b Mon Sep 17 00:00:00 2001 From: Seogeurim Date: Mon, 30 Aug 2021 23:06:15 +0900 Subject: [PATCH 83/84] =?UTF-8?q?style:=20item=20counter=20=EC=8A=A4?= =?UTF-8?q?=ED=83=80=EC=9D=BC=20=EA=B9=A8=EC=A7=80=EB=8A=94=20=EB=AC=B8?= =?UTF-8?q?=EC=A0=9C=20=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/components/item-detail/item-counter.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/components/item-detail/item-counter.tsx b/client/src/components/item-detail/item-counter.tsx index 7bb42c4..19448dd 100644 --- a/client/src/components/item-detail/item-counter.tsx +++ b/client/src/components/item-detail/item-counter.tsx @@ -45,6 +45,7 @@ const Counter = styled.div` align-items: center; .count { margin: 0 15px; + width: max-content; } ${({ theme }) => theme?.mobile} { @@ -97,7 +98,6 @@ const ItemCounter: FC = ({ title, price, onChange }: ItenCount - -
{formatPrice(count * price)}원
); From c665f37fa24ff0c1c99f051ed05122a7aaeaac8f Mon Sep 17 00:00:00 2001 From: Seogeurim Date: Mon, 30 Aug 2021 23:11:14 +0900 Subject: [PATCH 84/84] =?UTF-8?q?style:=20=EC=9E=98=EB=AA=BB=EB=90=9C=20?= =?UTF-8?q?=EB=AC=B8=EC=9E=90=EC=97=B4=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/components/auth/form.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/components/auth/form.tsx b/client/src/components/auth/form.tsx index e65bf34..601ca52 100644 --- a/client/src/components/auth/form.tsx +++ b/client/src/components/auth/form.tsx @@ -199,7 +199,7 @@ const AuthForm: FC = ({ ) : ( <> - 깃-헙으로 로그인 + 깃-헙으로 로그인 )}