From bcedac8290e509bdf52e5fe2da477c3cc15ba550 Mon Sep 17 00:00:00 2001 From: kyuhho Date: Sat, 8 Jun 2024 15:19:25 +0900 Subject: [PATCH 01/63] feat: add assests (#294) --- src/assets/buyer-open-consult/open-consult-fire.svg | 3 +++ src/assets/buyer-open-consult/open-consult-recent.svg | 3 +++ 2 files changed, 6 insertions(+) create mode 100644 src/assets/buyer-open-consult/open-consult-fire.svg create mode 100644 src/assets/buyer-open-consult/open-consult-recent.svg diff --git a/src/assets/buyer-open-consult/open-consult-fire.svg b/src/assets/buyer-open-consult/open-consult-fire.svg new file mode 100644 index 00000000..c9f7d3d1 --- /dev/null +++ b/src/assets/buyer-open-consult/open-consult-fire.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/buyer-open-consult/open-consult-recent.svg b/src/assets/buyer-open-consult/open-consult-recent.svg new file mode 100644 index 00000000..5d4e1594 --- /dev/null +++ b/src/assets/buyer-open-consult/open-consult-recent.svg @@ -0,0 +1,3 @@ + + + From 9f05ecad639c222ea3697974666a91d88894ddbb Mon Sep 17 00:00:00 2001 From: kyuhho Date: Sat, 8 Jun 2024 15:19:37 +0900 Subject: [PATCH 02/63] chore: fix layout --- src/api/get.ts | 6 +- .../BuyerOpenConsult/HotOpenConsultList.tsx | 66 ++++++++++++------- .../BuyerOpenConsult/OpenConsultList.tsx | 34 ++++++++-- src/pages/Buyer/BuyerOpenConsult.tsx | 17 ++--- 4 files changed, 80 insertions(+), 43 deletions(-) diff --git a/src/api/get.ts b/src/api/get.ts index 8e5f0829..2389a3c8 100644 --- a/src/api/get.ts +++ b/src/api/get.ts @@ -167,10 +167,10 @@ export const getCounselorsRandomConsult = async () => export const getCustomerOpenConsultList = async (params: any) => await getInstance('/posts/customers', params); -export const getCustomerPopularConsultList = async () => - await getPublicInstance('/posts/customers/public/likes'); +export const getCustomerPopularConsultList = async (params: any) => + await getPublicInstance('/posts/customers/public/likes', params); -export const getCustomerPublicConsultList = async (params: any) => +export const getPostsCustomersPublic = async (params: any) => await getPublicInstance('/posts/customers/public', params); export const getCustomerIsWriter = async (postId: any) => diff --git a/src/components/Buyer/BuyerOpenConsult/HotOpenConsultList.tsx b/src/components/Buyer/BuyerOpenConsult/HotOpenConsultList.tsx index 48f60029..7dde41cb 100644 --- a/src/components/Buyer/BuyerOpenConsult/HotOpenConsultList.tsx +++ b/src/components/Buyer/BuyerOpenConsult/HotOpenConsultList.tsx @@ -1,31 +1,60 @@ -import React, { useEffect, useState } from 'react'; +import { useEffect, useState } from 'react'; import styled from 'styled-components'; import { ReactComponent as FireIcon } from 'assets/icons/icon-fire.svg'; import { Body4 } from 'styles/font'; import { Grey6 } from 'styles/color'; import { getCustomerPopularConsultList } from 'api/get'; import { useNavigate } from 'react-router-dom'; + +// +// +// interface apiHotConsultObj { postId: number; title: string; } -function HotOpenConsultList() { - const [hotConsultList, setHotConsultList] = useState([]); + +// +// +// + +const HotOpenConsultList = () => { const navigate = useNavigate(); + + const [hotConsultList, setHotConsultList] = useState([]); + + // + // + // useEffect(() => { const fetchHotConsultList = async () => { - const res: any = await getCustomerPopularConsultList(); - if (res.status === 200) { - setHotConsultList(res.data); + try { + const params = { + postId: 0, + finishedAt: new Date().toISOString().slice(0, 19), + }; + + const res: any = await getCustomerPopularConsultList({ params }); + if (res.status === 200) { + console.log(res); + setHotConsultList(res.data); + } + } catch (e) { + console.error(e); } }; + fetchHotConsultList(); }, []); + + // + // + // + return ( - - - - + <> + + {hotConsultList?.map((item) => ( ))} - + ); -} +}; -const HotList = styled.div` - display: flex; - white-space: nowrap; - flex-wrap: nowrap; - overflow-x: scroll; - gap: 1.2rem; - align-items: center; -`; +// +// +// const HotTitleItem = styled.div` padding: 1.2rem 1.6rem; @@ -60,6 +84,4 @@ const HotTitleItem = styled.div` border-radius: 1.2rem; `; -const FireIconWrapper = styled.div``; - export default HotOpenConsultList; diff --git a/src/components/Buyer/BuyerOpenConsult/OpenConsultList.tsx b/src/components/Buyer/BuyerOpenConsult/OpenConsultList.tsx index 7ba8c48f..6bfff948 100644 --- a/src/components/Buyer/BuyerOpenConsult/OpenConsultList.tsx +++ b/src/components/Buyer/BuyerOpenConsult/OpenConsultList.tsx @@ -1,4 +1,4 @@ -import React, { useLayoutEffect, useRef, useState } from 'react'; +import { useLayoutEffect, useRef, useState } from 'react'; import styled from 'styled-components'; import { Grey1, Grey2, Grey6 } from 'styles/color'; import { Body1, Caption1 } from 'styles/font'; @@ -9,12 +9,16 @@ import { ReactComponent as SaveEmptyIcon } from 'assets/icons/icon-save5.svg'; import { ReactComponent as CommentIcon } from 'assets/icons/icon-comment.svg'; import { Space } from 'components/Common/Space'; import { openConsultApiObject } from 'pages/Buyer/BuyerConsult'; -import { getCustomerPublicConsultList } from 'api/get'; +import { getPostsCustomersPublic } from 'api/get'; import { useNavigate } from 'react-router-dom'; import useIntersectionObserver from 'hooks/useIntersectionObserver'; import { LoadingSpinner } from 'utils/LoadingSpinner'; -function OpenConsultList() { +// +// +// + +const OpenConsultList = () => { const [cardData, setCardData] = useState([]); const preventRef = useRef(true); const navigate = useNavigate(); @@ -30,19 +34,24 @@ function OpenConsultList() { preventRef.current = true; } }; + const { setTarget } = useIntersectionObserver({ root: null, rootMargin: '0px', threshold: 0.8, onIntersect, }); + + /** + * + */ const fetchOpenConsult = async (lastId: number, lastDate: string) => { try { const params = { postId: lastId, finishedAt: lastDate, }; - const res: any = await getCustomerPublicConsultList({ params }); + const res: any = await getPostsCustomersPublic({ params }); if (res.status === 200) { if (res.data.length !== 0) { @@ -67,9 +76,19 @@ function OpenConsultList() { } } }; + + // + // + // useLayoutEffect(() => { fetchOpenConsult(0, new Date().toISOString().slice(0, 19)); + // eslint-disable-next-line react-hooks/exhaustive-deps }, []); + + // + // + // + if (isLoading) { return (
); } -} +}; + +// +// +// + const BuyerOpenConsultCardList = styled.div` display: flex; margin: 0 2rem; diff --git a/src/pages/Buyer/BuyerOpenConsult.tsx b/src/pages/Buyer/BuyerOpenConsult.tsx index b18512c0..ee99fea2 100644 --- a/src/pages/Buyer/BuyerOpenConsult.tsx +++ b/src/pages/Buyer/BuyerOpenConsult.tsx @@ -19,7 +19,7 @@ const BuyerOpenConsult = () => { // return ( - + <>
{ @@ -27,10 +27,10 @@ const BuyerOpenConsult = () => { }} /> -
+
-
+
@@ -44,7 +44,7 @@ const BuyerOpenConsult = () => { }} /> - + ); }; @@ -52,15 +52,6 @@ const BuyerOpenConsult = () => { // // -const Wrapper = styled.div` - section.hot-consult-list { - height: 4.6rem; - margin: 1.2rem 0rem 1.2rem 2rem; - overflow: hidden; - width: calc(100% - 2rem); - } -`; - const CreateConsultButtonWrapper = styled.div` width: 100%; padding: 0 2rem; From ca3287469f764a171a0fbbb92befb3ed987793a6 Mon Sep 17 00:00:00 2001 From: kyuhho Date: Sat, 8 Jun 2024 15:24:10 +0900 Subject: [PATCH 03/63] chore: add flex component --- src/components/Common/Flex.tsx | 85 ++++++++++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 src/components/Common/Flex.tsx diff --git a/src/components/Common/Flex.tsx b/src/components/Common/Flex.tsx new file mode 100644 index 00000000..b08ae023 --- /dev/null +++ b/src/components/Common/Flex.tsx @@ -0,0 +1,85 @@ +import styled from 'styled-components'; + +// +// +// + +interface FlexProps { + children: React.ReactNode; + width?: string; + height?: string; + direction?: 'row' | 'row-reverse' | 'column' | 'column-reverse'; + justify?: + | 'flex-start' + | 'flex-end' + | 'center' + | 'space-between' + | 'space-around' + | 'space-evenly'; + align?: 'stretch' | 'flex-start' | 'flex-end' | 'center' | 'baseline'; + gap?: number | string; + wrap?: 'nowrap' | 'wrap' | 'wrap-reverse'; + className?: string; +} + +interface FlexBaseProps { + height?: string; + width?: string; + direction?: 'row' | 'row-reverse' | 'column' | 'column-reverse'; + justify?: + | 'flex-start' + | 'flex-end' + | 'center' + | 'space-between' + | 'space-around' + | 'space-evenly'; + align?: 'stretch' | 'flex-start' | 'flex-end' | 'center' | 'baseline'; + gap?: number | string; + wrap?: 'nowrap' | 'wrap' | 'wrap-reverse'; +} + +// +// +// + +export const Flex = ({ + children, + width = 'auto', + height = 'auto', + direction = 'row', + justify = 'center', + align = 'center', + gap = 0, + wrap = 'nowrap', + className, +}: FlexProps) => { + return ( + + {children} + + ); +}; + +// +// +// + +const FlexBase = styled.div` + display: flex; + height: ${({ height }) => height}; + width: ${({ width }) => width}; + flex-direction: ${({ direction }) => direction}; + justify-content: ${({ justify }) => justify}; + align-items: ${({ align }) => align}; + gap: ${({ gap }) => `${gap}`}; + flex-wrap: ${({ wrap }) => wrap}; +`; From be2bf29429a1780ce42ffdadbfcd999b01648b81 Mon Sep 17 00:00:00 2001 From: kyuhho Date: Sat, 8 Jun 2024 15:31:35 +0900 Subject: [PATCH 04/63] feat: update flex props (#294) --- src/components/Common/Flex.tsx | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/components/Common/Flex.tsx b/src/components/Common/Flex.tsx index b08ae023..3246b0a6 100644 --- a/src/components/Common/Flex.tsx +++ b/src/components/Common/Flex.tsx @@ -19,7 +19,10 @@ interface FlexProps { align?: 'stretch' | 'flex-start' | 'flex-end' | 'center' | 'baseline'; gap?: number | string; wrap?: 'nowrap' | 'wrap' | 'wrap-reverse'; + padding?: string; + margin?: string; className?: string; + onClick?: () => void; } interface FlexBaseProps { @@ -36,6 +39,8 @@ interface FlexBaseProps { align?: 'stretch' | 'flex-start' | 'flex-end' | 'center' | 'baseline'; gap?: number | string; wrap?: 'nowrap' | 'wrap' | 'wrap-reverse'; + padding?: string; + margin?: string; } // @@ -51,7 +56,10 @@ export const Flex = ({ align = 'center', gap = 0, wrap = 'nowrap', + padding = '0', + margin = '0', className, + onClick, }: FlexProps) => { return ( {children} @@ -82,4 +93,6 @@ const FlexBase = styled.div` align-items: ${({ align }) => align}; gap: ${({ gap }) => `${gap}`}; flex-wrap: ${({ wrap }) => wrap}; + padding: ${({ padding }) => padding}; + margin: ${({ margin }) => margin}; `; From 3a3e0cd6f734f8e1a2a9c0c1a4c5ea9451c033d6 Mon Sep 17 00:00:00 2001 From: kyuhho Date: Sat, 8 Jun 2024 15:31:49 +0900 Subject: [PATCH 05/63] chore: add arrow asset (#294) --- src/assets/buyer-open-consult/open-consult-arrow.svg | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 src/assets/buyer-open-consult/open-consult-arrow.svg diff --git a/src/assets/buyer-open-consult/open-consult-arrow.svg b/src/assets/buyer-open-consult/open-consult-arrow.svg new file mode 100644 index 00000000..f0ff88e8 --- /dev/null +++ b/src/assets/buyer-open-consult/open-consult-arrow.svg @@ -0,0 +1,3 @@ + + + From 3fd6bb5ee0cc5d194cc3472959e21e0fa9ee21bb Mon Sep 17 00:00:00 2001 From: kyuhho Date: Sat, 8 Jun 2024 15:58:29 +0900 Subject: [PATCH 06/63] chore: fix api naming (#294) --- src/api/get.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/get.ts b/src/api/get.ts index 2389a3c8..c1b6d2cc 100644 --- a/src/api/get.ts +++ b/src/api/get.ts @@ -167,7 +167,7 @@ export const getCounselorsRandomConsult = async () => export const getCustomerOpenConsultList = async (params: any) => await getInstance('/posts/customers', params); -export const getCustomerPopularConsultList = async (params: any) => +export const getPostsCustomersPublicLikes = async (params: any) => await getPublicInstance('/posts/customers/public/likes', params); export const getPostsCustomersPublic = async (params: any) => From a10c81b982a87085687da84bc6ed6e2c62280365 Mon Sep 17 00:00:00 2001 From: kyuhho Date: Sat, 8 Jun 2024 16:40:43 +0900 Subject: [PATCH 07/63] chore: add border box sizing (#294) --- src/components/Common/Flex.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/Common/Flex.tsx b/src/components/Common/Flex.tsx index 3246b0a6..22a8b738 100644 --- a/src/components/Common/Flex.tsx +++ b/src/components/Common/Flex.tsx @@ -95,4 +95,5 @@ const FlexBase = styled.div` flex-wrap: ${({ wrap }) => wrap}; padding: ${({ padding }) => padding}; margin: ${({ margin }) => margin}; + box-sizing: border-box; `; From c3535aa09be258c3c49514cd4e712e5cf2749395 Mon Sep 17 00:00:00 2001 From: kyuhho Date: Sat, 8 Jun 2024 17:09:34 +0900 Subject: [PATCH 08/63] feat: add css prop in font (#294) --- src/styles/font.tsx | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/styles/font.tsx b/src/styles/font.tsx index 1e0b5b36..6e263eaa 100644 --- a/src/styles/font.tsx +++ b/src/styles/font.tsx @@ -1,4 +1,4 @@ -import styled from 'styled-components'; +import styled, { CSSProp } from 'styled-components'; // 이런식으로 사용 //semi-bold : 600 regular : 400 interface FontProps { @@ -7,6 +7,7 @@ interface FontProps { margin?: string; underline?: boolean; textAlign?: string; + customStyles?: CSSProp; } export const Heading = styled.div` font-family: Pretendard; @@ -18,6 +19,7 @@ export const Heading = styled.div` padding: ${(props) => props.padding || ''}; margin: ${(props) => props.margin || ''}; text-decoration-line: ${(props) => props.underline && 'underline'}; + ${(props) => props.customStyles} `; export const Subtitle = styled.div` font-family: Pretendard; @@ -29,6 +31,7 @@ export const Subtitle = styled.div` padding: ${(props) => props.padding || ''}; margin: ${(props) => props.margin || ''}; text-decoration-line: ${(props) => props.underline && 'underline'}; + ${(props) => props.customStyles} `; export const Body1 = styled.div` font-family: Pretendard; @@ -40,6 +43,7 @@ export const Body1 = styled.div` padding: ${(props) => props.padding || ''}; margin: ${(props) => props.margin || ''}; text-decoration-line: ${(props) => props.underline && 'underline'}; + ${(props) => props.customStyles} `; export const Body2 = styled.div` font-family: Pretendard; @@ -51,6 +55,7 @@ export const Body2 = styled.div` padding: ${(props) => props.padding || ''}; margin: ${(props) => props.margin || ''}; text-decoration-line: ${(props) => props.underline && 'underline'}; + ${(props) => props.customStyles} `; //피그마 상에선 body4 export const Body3 = styled.div` @@ -63,6 +68,7 @@ export const Body3 = styled.div` padding: ${(props) => props.padding || ''}; margin: ${(props) => props.margin || ''}; text-decoration-line: ${(props) => props.underline && 'underline'}; + ${(props) => props.customStyles} text-align: ${(props) => props?.textAlign}; `; //피그마 상에선 body3 @@ -76,6 +82,7 @@ export const Body4 = styled.div` padding: ${(props) => props.padding || ''}; margin: ${(props) => props.margin || ''}; text-decoration-line: ${(props) => props.underline && 'underline'}; + ${(props) => props.customStyles} `; export const Button1 = styled.div` font-family: Pretendard; @@ -87,6 +94,7 @@ export const Button1 = styled.div` padding: ${(props) => props.padding || ''}; margin: ${(props) => props.margin || ''}; text-decoration-line: ${(props) => props.underline && 'underline'}; + ${(props) => props.customStyles} `; export const Button2 = styled.div` font-family: Pretendard; @@ -98,6 +106,7 @@ export const Button2 = styled.div` padding: ${(props) => props.padding || ''}; margin: ${(props) => props.margin || ''}; text-decoration-line: ${(props) => props.underline && 'underline'}; + ${(props) => props.customStyles} `; export const Caption1 = styled.div` font-family: Pretendard; @@ -109,6 +118,7 @@ export const Caption1 = styled.div` padding: ${(props) => props.padding || ''}; margin: ${(props) => props.margin || ''}; text-decoration-line: ${(props) => props.underline && 'underline'}; + ${(props) => props.customStyles} `; export const Caption2 = styled.div` font-family: Pretendard; @@ -120,4 +130,5 @@ export const Caption2 = styled.div` padding: ${(props) => props.padding || ''}; margin: ${(props) => props.margin || ''}; text-decoration-line: ${(props) => props.underline && 'underline'}; + ${(props) => props.customStyles} `; From b68e912d1e8b448afa4b390e608761b7aa0d5e71 Mon Sep 17 00:00:00 2001 From: kyuhho Date: Sat, 8 Jun 2024 17:09:58 +0900 Subject: [PATCH 09/63] chore: add consult info icons (#294) --- src/assets/buyer-open-consult/open-consult-comment.svg | 3 +++ src/assets/buyer-open-consult/open-consult-heart.svg | 3 +++ src/assets/buyer-open-consult/open-consult-scrap.svg | 3 +++ 3 files changed, 9 insertions(+) create mode 100644 src/assets/buyer-open-consult/open-consult-comment.svg create mode 100644 src/assets/buyer-open-consult/open-consult-heart.svg create mode 100644 src/assets/buyer-open-consult/open-consult-scrap.svg diff --git a/src/assets/buyer-open-consult/open-consult-comment.svg b/src/assets/buyer-open-consult/open-consult-comment.svg new file mode 100644 index 00000000..1292727d --- /dev/null +++ b/src/assets/buyer-open-consult/open-consult-comment.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/assets/buyer-open-consult/open-consult-heart.svg b/src/assets/buyer-open-consult/open-consult-heart.svg new file mode 100644 index 00000000..a0c9eef0 --- /dev/null +++ b/src/assets/buyer-open-consult/open-consult-heart.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/assets/buyer-open-consult/open-consult-scrap.svg b/src/assets/buyer-open-consult/open-consult-scrap.svg new file mode 100644 index 00000000..f0f4b3ae --- /dev/null +++ b/src/assets/buyer-open-consult/open-consult-scrap.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file From aabc8a63822e9b73abcf547b04b0eec03c42b318 Mon Sep 17 00:00:00 2001 From: kyuhho Date: Sat, 8 Jun 2024 18:33:58 +0900 Subject: [PATCH 10/63] feat: init open consult card (#294) --- .../BuyerOpenConsult/BuyerOpenConsultCard.tsx | 108 ++++++++++++++++++ .../BuyerOpenConsult/HotOpenConsultList.tsx | 83 +++++++++----- 2 files changed, 160 insertions(+), 31 deletions(-) create mode 100644 src/components/Buyer/BuyerOpenConsult/BuyerOpenConsultCard.tsx diff --git a/src/components/Buyer/BuyerOpenConsult/BuyerOpenConsultCard.tsx b/src/components/Buyer/BuyerOpenConsult/BuyerOpenConsultCard.tsx new file mode 100644 index 00000000..32dc36b1 --- /dev/null +++ b/src/components/Buyer/BuyerOpenConsult/BuyerOpenConsultCard.tsx @@ -0,0 +1,108 @@ +import styled, { css } from 'styled-components'; +import { Grey1, Grey2, White } from 'styles/color'; +import { Body3, Body4, Caption2 } from 'styles/font'; + +import { ReactComponent as HeartIcon } from 'assets/buyer-open-consult/open-consult-heart.svg'; +// import { ReactComponent as HeartEmptyIcon } from 'assets/icons/icon-heart4.svg'; +import { ReactComponent as SaveIcon } from 'assets/buyer-open-consult/open-consult-scrap.svg'; +// import { ReactComponent as SaveEmptyIcon } from 'assets/icons/icon-save5.svg'; +import { ReactComponent as CommentIcon } from 'assets/buyer-open-consult/open-consult-comment.svg'; + +import { Flex } from 'components/Common/Flex'; +import { getPostsCustomersPublicLikesResponse } from './HotOpenConsultList'; + +// +// +// + +export interface BuyerOpenConsultCardProps + extends Omit< + getPostsCustomersPublicLikesResponse, + 'content' | 'postId' | 'isLiked' | 'isScrapped' + > { + content?: string; + onClick?: () => void; +} + +// +// +// + +const ContentTwoLinesCSS = css` + display: -webkit-box; + -webkit-line-clamp: 2; + -webkit-box-orient: vertical; + overflow: hidden; +`; + +// +// +// + +const BuyerOpenConsultCard = ({ + title, + content, + totalLike, + totalScrap, + totalComment, + updatedAt, + onClick, +}: BuyerOpenConsultCardProps) => { + /** + * + */ + const renderConsultInfo = () => ( + + + + + {totalLike} + + + + {totalScrap} + + + + {totalComment} + + + {updatedAt} + + ); + + // + // + // + + return ( + + + + {title} + + {content ? ( + + {content} + + ) : null} + {renderConsultInfo()} + + + ); +}; + +export default BuyerOpenConsultCard; + +// +// +// + +const Wrapper = styled.div` + padding: 1.2rem 1.6rem; + box-sizing: border-box; + width: 100%; + background-color: ${White}; + border-radius: 1.2rem; + cursor: pointer; +`; diff --git a/src/components/Buyer/BuyerOpenConsult/HotOpenConsultList.tsx b/src/components/Buyer/BuyerOpenConsult/HotOpenConsultList.tsx index 7dde41cb..0630cfd9 100644 --- a/src/components/Buyer/BuyerOpenConsult/HotOpenConsultList.tsx +++ b/src/components/Buyer/BuyerOpenConsult/HotOpenConsultList.tsx @@ -1,17 +1,27 @@ import { useEffect, useState } from 'react'; import styled from 'styled-components'; -import { ReactComponent as FireIcon } from 'assets/icons/icon-fire.svg'; -import { Body4 } from 'styles/font'; -import { Grey6 } from 'styles/color'; -import { getCustomerPopularConsultList } from 'api/get'; +import { ReactComponent as FireIcon } from 'assets/buyer-open-consult/open-consult-fire.svg'; +import { ReactComponent as ArrowIcon } from 'assets/buyer-open-consult/open-consult-arrow.svg'; +import { Body1 } from 'styles/font'; +import { getPostsCustomersPublicLikes } from 'api/get'; import { useNavigate } from 'react-router-dom'; +import { Flex } from 'components/Common/Flex'; +import BuyerOpenConsultCard from './BuyerOpenConsultCard'; // // // -interface apiHotConsultObj { + +export interface getPostsCustomersPublicLikesResponse { postId: number; title: string; + content: string; + isLiked: boolean; + isScrapped: boolean; + totalLike: number; + totalScrap: number; + totalComment: number; + updatedAt: string; } // @@ -21,7 +31,9 @@ interface apiHotConsultObj { const HotOpenConsultList = () => { const navigate = useNavigate(); - const [hotConsultList, setHotConsultList] = useState([]); + const [hotConsultList, setHotConsultList] = useState< + getPostsCustomersPublicLikesResponse[] + >([]); // // @@ -34,9 +46,8 @@ const HotOpenConsultList = () => { finishedAt: new Date().toISOString().slice(0, 19), }; - const res: any = await getCustomerPopularConsultList({ params }); + const res: any = await getPostsCustomersPublicLikes({ params }); if (res.status === 200) { - console.log(res); setHotConsultList(res.data); } } catch (e) { @@ -52,24 +63,37 @@ const HotOpenConsultList = () => { // return ( - <> - - - {hotConsultList?.map((item) => ( - { - navigate(`/open-consult/${item.postId}`); - }} - > - - {item.title.length > 19 - ? item.title.slice(0, 19) + '...' - : item.title} - - - ))} - + + {/* TODO: add navigate url */} + { + navigate('/'); + }} + > + + + 인기글 + + + + + {hotConsultList?.map((item) => ( + { + navigate(`/open-consult/${item.postId}`); + }} + /> + ))} + + ); }; @@ -77,11 +101,8 @@ const HotOpenConsultList = () => { // // -const HotTitleItem = styled.div` - padding: 1.2rem 1.6rem; - cursor: pointer; - background-color: ${Grey6}; - border-radius: 1.2rem; +const Wrapper = styled.div` + padding: 1.2rem 2rem 2.3rem 2rem; `; export default HotOpenConsultList; From ea6d1535a54d5a5fcf41d06b988f3eb7670742c8 Mon Sep 17 00:00:00 2001 From: kyuhho Date: Sat, 8 Jun 2024 18:41:09 +0900 Subject: [PATCH 11/63] feat: add open consult hot section --- .../Buyer/BuyerOpenConsult/HotOpenConsultList.tsx | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/components/Buyer/BuyerOpenConsult/HotOpenConsultList.tsx b/src/components/Buyer/BuyerOpenConsult/HotOpenConsultList.tsx index 0630cfd9..baa9b487 100644 --- a/src/components/Buyer/BuyerOpenConsult/HotOpenConsultList.tsx +++ b/src/components/Buyer/BuyerOpenConsult/HotOpenConsultList.tsx @@ -2,11 +2,13 @@ import { useEffect, useState } from 'react'; import styled from 'styled-components'; import { ReactComponent as FireIcon } from 'assets/buyer-open-consult/open-consult-fire.svg'; import { ReactComponent as ArrowIcon } from 'assets/buyer-open-consult/open-consult-arrow.svg'; -import { Body1 } from 'styles/font'; +import { Body1, Caption2 } from 'styles/font'; import { getPostsCustomersPublicLikes } from 'api/get'; import { useNavigate } from 'react-router-dom'; import { Flex } from 'components/Common/Flex'; import BuyerOpenConsultCard from './BuyerOpenConsultCard'; +import { Grey2 } from 'styles/color'; +import { Space } from 'components/Common/Space'; // // @@ -77,12 +79,15 @@ const HotOpenConsultList = () => { + + 공감을 10개 이상 받았어요 + + {hotConsultList?.map((item) => ( Date: Sat, 8 Jun 2024 18:41:44 +0900 Subject: [PATCH 12/63] chore: change to semantic tag (#294) --- src/components/Buyer/BuyerOpenConsult/HotOpenConsultList.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/Buyer/BuyerOpenConsult/HotOpenConsultList.tsx b/src/components/Buyer/BuyerOpenConsult/HotOpenConsultList.tsx index baa9b487..599238cf 100644 --- a/src/components/Buyer/BuyerOpenConsult/HotOpenConsultList.tsx +++ b/src/components/Buyer/BuyerOpenConsult/HotOpenConsultList.tsx @@ -106,7 +106,7 @@ const HotOpenConsultList = () => { // // -const Wrapper = styled.div` +const Wrapper = styled.section` padding: 1.2rem 2rem 2.3rem 2rem; `; From 050550ea97d4e5f9f49c1bc800f2468592110c5c Mon Sep 17 00:00:00 2001 From: kyuhho Date: Sat, 8 Jun 2024 18:43:44 +0900 Subject: [PATCH 13/63] chore: fix component naming (#294) --- .../Buyer/BuyerOpenConsult/HotOpenConsultList.tsx | 4 ++-- .../{BuyerOpenConsultCard.tsx => OpenConsultCard.tsx} | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) rename src/components/Buyer/BuyerOpenConsult/{BuyerOpenConsultCard.tsx => OpenConsultCard.tsx} (94%) diff --git a/src/components/Buyer/BuyerOpenConsult/HotOpenConsultList.tsx b/src/components/Buyer/BuyerOpenConsult/HotOpenConsultList.tsx index 599238cf..d0ce0fb5 100644 --- a/src/components/Buyer/BuyerOpenConsult/HotOpenConsultList.tsx +++ b/src/components/Buyer/BuyerOpenConsult/HotOpenConsultList.tsx @@ -6,7 +6,7 @@ import { Body1, Caption2 } from 'styles/font'; import { getPostsCustomersPublicLikes } from 'api/get'; import { useNavigate } from 'react-router-dom'; import { Flex } from 'components/Common/Flex'; -import BuyerOpenConsultCard from './BuyerOpenConsultCard'; +import OpenConsultCard from './OpenConsultCard'; import { Grey2 } from 'styles/color'; import { Space } from 'components/Common/Space'; @@ -85,7 +85,7 @@ const HotOpenConsultList = () => { {hotConsultList?.map((item) => ( - { +}: OpenConsultCardProps) => { /** * */ @@ -92,7 +92,7 @@ const BuyerOpenConsultCard = ({ ); }; -export default BuyerOpenConsultCard; +export default OpenConsultCard; // // From 57a782f3c7a56101ec525eda54cd74f3fa16aff0 Mon Sep 17 00:00:00 2001 From: kyuhho Date: Sat, 8 Jun 2024 19:24:23 +0900 Subject: [PATCH 14/63] chore: fix flex gap (#294) --- src/components/Buyer/BuyerOpenConsult/HotOpenConsultList.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/Buyer/BuyerOpenConsult/HotOpenConsultList.tsx b/src/components/Buyer/BuyerOpenConsult/HotOpenConsultList.tsx index d0ce0fb5..2722c58d 100644 --- a/src/components/Buyer/BuyerOpenConsult/HotOpenConsultList.tsx +++ b/src/components/Buyer/BuyerOpenConsult/HotOpenConsultList.tsx @@ -83,7 +83,7 @@ const HotOpenConsultList = () => { 공감을 10개 이상 받았어요 - + {hotConsultList?.map((item) => ( Date: Sat, 8 Jun 2024 19:25:01 +0900 Subject: [PATCH 15/63] feat: apply changed component on recent open consult list (#294) --- .../BuyerOpenConsult/OpenConsultList.tsx | 279 ++++++------------ 1 file changed, 85 insertions(+), 194 deletions(-) diff --git a/src/components/Buyer/BuyerOpenConsult/OpenConsultList.tsx b/src/components/Buyer/BuyerOpenConsult/OpenConsultList.tsx index 6bfff948..5ba23670 100644 --- a/src/components/Buyer/BuyerOpenConsult/OpenConsultList.tsx +++ b/src/components/Buyer/BuyerOpenConsult/OpenConsultList.tsx @@ -1,225 +1,116 @@ -import { useLayoutEffect, useRef, useState } from 'react'; +import { useLayoutEffect, useState } from 'react'; import styled from 'styled-components'; -import { Grey1, Grey2, Grey6 } from 'styles/color'; -import { Body1, Caption1 } from 'styles/font'; -import { ReactComponent as HeartIcon } from 'assets/icons/icon-heart2.svg'; -import { ReactComponent as HeartEmptyIcon } from 'assets/icons/icon-heart4.svg'; -import { ReactComponent as SaveIcon } from 'assets/icons/icon-save4.svg'; -import { ReactComponent as SaveEmptyIcon } from 'assets/icons/icon-save5.svg'; -import { ReactComponent as CommentIcon } from 'assets/icons/icon-comment.svg'; -import { Space } from 'components/Common/Space'; -import { openConsultApiObject } from 'pages/Buyer/BuyerConsult'; + import { getPostsCustomersPublic } from 'api/get'; import { useNavigate } from 'react-router-dom'; -import useIntersectionObserver from 'hooks/useIntersectionObserver'; -import { LoadingSpinner } from 'utils/LoadingSpinner'; + +import OpenConsultCard from './OpenConsultCard'; +import { Body1 } from 'styles/font'; +import { Flex } from 'components/Common/Flex'; + +import { ReactComponent as RecentIcon } from 'assets/buyer-open-consult/open-consult-recent.svg'; +import { ReactComponent as ArrowIcon } from 'assets/buyer-open-consult/open-consult-arrow.svg'; +import { Space } from 'components/Common/Space'; + +// +// +// + +export interface getPostsCustomersPublicResponse { + postId: number; + title: string; + content: string; + isLiked: boolean; + isScrapped: boolean; + totalLike: number; + totalScrap: number; + totalComment: number; + updatedAt: string; +} // // // const OpenConsultList = () => { - const [cardData, setCardData] = useState([]); - const preventRef = useRef(true); + const [recentConsultList, setRecentConsultList] = useState< + getPostsCustomersPublicResponse[] + >([]); const navigate = useNavigate(); - const [isLastElem, setIsLastElem] = useState(false); - const [isLoading, setIsLoading] = useState(true); - const onIntersect: IntersectionObserverCallback = async (entry) => { - if (entry[0].isIntersecting && !isLastElem && preventRef.current) { - preventRef.current = false; - await fetchOpenConsult( - cardData[cardData.length - 1]?.postId, - cardData[cardData.length - 1]?.finishedAt, - ); - preventRef.current = true; - } - }; - - const { setTarget } = useIntersectionObserver({ - root: null, - rootMargin: '0px', - threshold: 0.8, - onIntersect, - }); - - /** - * - */ - const fetchOpenConsult = async (lastId: number, lastDate: string) => { - try { - const params = { - postId: lastId, - finishedAt: lastDate, - }; - const res: any = await getPostsCustomersPublic({ params }); - - if (res.status === 200) { - if (res.data.length !== 0) { - if (lastId === 0) { - setCardData(res.data); - } else { - const updatedReviews = [...cardData, ...res.data]; - setCardData(updatedReviews); - } - } else { - setIsLastElem(true); - } - } else if (res.response.status === 404) { - alert('존재하지 않는 회원입니다.'); - navigate('/login'); - } - } catch (err) { - alert(err); - } finally { - if (lastId === 0) { - setIsLoading(false); - } - } - }; // // // useLayoutEffect(() => { - fetchOpenConsult(0, new Date().toISOString().slice(0, 19)); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); + const fetchOpenConsult = async () => { + try { + const params = { + postId: 0, + finishedAt: new Date().toISOString().slice(0, 19), + }; + + const res: any = await getPostsCustomersPublic({ params }); + + if (res.status === 200) { + setRecentConsultList(res.data); + } else if (res.response.status === 404) { + alert('존재하지 않는 회원입니다.'); + navigate('/login'); + } + } catch (err) { + alert(err); + } + }; + + fetchOpenConsult(); + }, [navigate]); // // // - if (isLoading) { - return ( -
+ {/* TODO: add navigate url */} + { + navigate('/'); }} > - -
- ); - } else { - return ( -
- - {/* 상담카드 부분 */} - {cardData.map((item) => ( - { - navigate(`/open-consult/${item.postId}`); - }} - key={item.postId} - > -
- {item.title} -
- -
{item.content}
-
- - {item.isLiked ? : } - {item.totalLike} - - - - {item.isScrapped ? : } - {item.totalScrap} - - - - {item.totalComment} - -
- {item.updatedAt} -
- ))} - {!isLastElem ? ( -
- ) : ( -
- )} - {/* 상담카드 부분 */} - -
- ); - } + + + 최신글 + + + + + + {recentConsultList.map((consult) => ( + { + navigate(`/open-consult/${consult.postId}`); + }} + /> + ))} + + + ); }; // // // -const BuyerOpenConsultCardList = styled.div` - display: flex; - margin: 0 2rem; - flex-direction: column; - align-items: flex-start; - gap: 1.2rem; -`; - -const BuyerOpenConsultCard = styled.div` - width: 100%; - height: 14rem; - cursor: pointer; - position: relative; - background-color: ${Grey6}; - padding: 1.6rem; - box-sizing: border-box; - border-radius: 1.2rem; - .row1 { - width: calc(100% - 5rem); - display: -webkit-box; - -webkit-box-orient: vertical; - -webkit-line-clamp: 1; - max-height: 5rem; - overflow: hidden; - } - .row2 { - display: -webkit-box; - max-height: 4.7rem; - -webkit-box-orient: vertical; - overflow: hidden; - align-self: flex-end; - margin-bottom: 0.4rem; - -webkit-line-clamp: 2; - color: ${Grey1}; - height: 4.6rem; - text-overflow: ellipsis; - font-family: Pretendard; - font-size: 1.4rem; - font-style: normal; - font-weight: 400; - line-height: 155%; - } - .row3 { - position: absolute; - bottom: 1.6rem; - display: flex; - gap: 1.2rem; - } -`; -const IconItem = styled.div` - display: flex; - align-items: center; - gap: 0.5rem; -`; - -const SaveResizeIcon = styled(SaveIcon)` - width: 2rem; - height: 2rem; -`; - -const TimeLeft = styled.div` - font-size: 1.2rem; - font-weight: 400; - color: ${Grey2}; - position: absolute; - bottom: 1.8rem; - right: 1.6rem; +const Wrapper = styled.section` + padding: 0 2rem; `; export default OpenConsultList; From 8a4e353997aa8c572184524f4d8fe1e8fbf982a9 Mon Sep 17 00:00:00 2001 From: kyuhho Date: Sat, 8 Jun 2024 19:25:13 +0900 Subject: [PATCH 16/63] chore: remove section tag (#294) --- src/pages/Buyer/BuyerOpenConsult.tsx | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/pages/Buyer/BuyerOpenConsult.tsx b/src/pages/Buyer/BuyerOpenConsult.tsx index ee99fea2..fe746039 100644 --- a/src/pages/Buyer/BuyerOpenConsult.tsx +++ b/src/pages/Buyer/BuyerOpenConsult.tsx @@ -27,13 +27,11 @@ const BuyerOpenConsult = () => { }} /> -
- -
-
- - -
+ + + + +
)} @@ -134,13 +176,7 @@ export const BuyerConsult = () => { 종료/취소된 상담 제외
- {consultType === 'letter' ? ( - - ) : consultType === 'chat' ? ( - - ) : ( - - )} + {renderConsultSection()} {isModalOpen ? ( <> { ); }; + +// +// +// + const Wrapper = styled.div` .options { padding: 0.8rem 2rem 1.6rem; @@ -179,7 +220,7 @@ const Wrapper = styled.div` .select-wrapper { display: flex; gap: 0.4rem; - cursor: pointer; + cursor: pointer; } .select-button { display: flex; From a66eec2a94117205ddc20198afd1509175d7af76 Mon Sep 17 00:00:00 2001 From: kyuhho Date: Mon, 10 Jun 2024 21:47:07 +0900 Subject: [PATCH 53/63] chore: simplify component logic (#294) --- src/pages/Buyer/BuyerConsult.tsx | 79 +++++++++++++++++++++----------- 1 file changed, 51 insertions(+), 28 deletions(-) diff --git a/src/pages/Buyer/BuyerConsult.tsx b/src/pages/Buyer/BuyerConsult.tsx index e061b713..dc0923a1 100644 --- a/src/pages/Buyer/BuyerConsult.tsx +++ b/src/pages/Buyer/BuyerConsult.tsx @@ -85,6 +85,30 @@ export const BuyerConsult = () => { const setScrollLock = useSetRecoilState(scrollLockState); + /** + * + */ + const renderCheckBox = () => { + if (consultType === 'open-consult') { + return null; + } + + return ( +
{ + setIsChecked(!isChecked); + searchParams.set('check', String(!isChecked)); + setSearchParams(searchParams); + }} + > + {isChecked ? : } + 종료/취소된 상담 제외 +
+ ); + }; + /** * */ @@ -108,6 +132,31 @@ export const BuyerConsult = () => { } }; + /** + * + */ + const renderSortModal = () => { + if (!isModalOpen) { + return null; + } + + return ( + <> + { + setIsModalOpen(false); + }} + /> + + + ); + }; + // // // @@ -162,36 +211,10 @@ export const BuyerConsult = () => { )} - -
{ - setIsChecked(!isChecked); - searchParams.set('check', String(!isChecked)); - setSearchParams(searchParams); - }} - > - {isChecked ? : } - 종료/취소된 상담 제외 -
+ {renderCheckBox()} {renderConsultSection()} - {isModalOpen ? ( - <> - { - setIsModalOpen(false); - }} - /> - - - ) : null} + {renderSortModal()} ); }; From b5357630a8736d41aeb6dcabbddc8e0ec8bad259 Mon Sep 17 00:00:00 2001 From: kyuhho Date: Tue, 11 Jun 2024 21:22:40 +0900 Subject: [PATCH 54/63] chore: change consult page open consult view to white card (#294) --- .../BuyerConsult/BuyerOpenConsultSection.tsx | 35 ++++++++++++++++--- src/pages/Buyer/BuyerConsult.tsx | 4 --- 2 files changed, 30 insertions(+), 9 deletions(-) diff --git a/src/components/Buyer/BuyerConsult/BuyerOpenConsultSection.tsx b/src/components/Buyer/BuyerConsult/BuyerOpenConsultSection.tsx index 47741d3e..c39a5c8c 100644 --- a/src/components/Buyer/BuyerConsult/BuyerOpenConsultSection.tsx +++ b/src/components/Buyer/BuyerConsult/BuyerOpenConsultSection.tsx @@ -1,7 +1,7 @@ import { useLayoutEffect, useRef, useState } from 'react'; import { useRecoilValue } from 'recoil'; import styled from 'styled-components'; -import { Grey1, Grey2, Grey3, Grey6 } from 'styles/color'; +import { Grey1, Grey2, Grey3, White } from 'styles/color'; import { Body1, Body3, Caption1, Heading } from 'styles/font'; import { LoadingSpinner } from 'utils/LoadingSpinner'; import { isBuyPopupOpenState } from 'utils/atom'; @@ -20,13 +20,24 @@ import { ReactComponent as Empty } from 'assets/icons/graphic-noting.svg'; import { openConsultApiObject } from 'pages/Buyer/BuyerConsult'; import { getCustomerOpenConsultList } from 'api/get'; import useIntersectionObserver from 'hooks/useIntersectionObserver'; + +// +// +// + interface BuyerOpenConsultSectionProps { isChecked: boolean; } + +// +// +// + function BuyerOpenConsultSection({ isChecked }: BuyerOpenConsultSectionProps) { + const navigate = useNavigate(); + const [isLoading, setIsLoading] = useState(true); const [isLastElem, setIsLastElem] = useState(false); - const navigate = useNavigate(); const isBuyPopupOpen = useRecoilValue(isBuyPopupOpenState); const preventRef = useRef(true); @@ -38,13 +49,16 @@ function BuyerOpenConsultSection({ isChecked }: BuyerOpenConsultSectionProps) { preventRef.current = true; } }; + const { setTarget } = useIntersectionObserver({ root: null, rootMargin: '0px', threshold: 0.8, onIntersect, }); + const [cardData, setCardData] = useState([]); + const fetchOpenConsult = async (lastId: number) => { try { const params = { @@ -76,9 +90,16 @@ function BuyerOpenConsultSection({ isChecked }: BuyerOpenConsultSectionProps) { } } }; + useLayoutEffect(() => { fetchOpenConsult(0); + // eslint-disable-next-line react-hooks/exhaustive-deps }, [isChecked]); + + // + // + // + return ( <> {isLoading ? ( @@ -203,9 +224,13 @@ function BuyerOpenConsultSection({ isChecked }: BuyerOpenConsultSectionProps) { ); } +// +// +// + const BuyerOpenConsultCardList = styled.div` display: flex; - margin: 0 2rem; + padding: 1.2rem 2rem; flex-direction: column; align-items: flex-start; gap: 1.2rem; @@ -219,7 +244,7 @@ const BuyerPendingOpenConsultCard = styled.div` padding: 1.6rem; gap: 0.8rem; position: relative; - background-color: ${Grey6}; + background-color: ${White}; border-radius: 1.2rem; `; @@ -228,7 +253,7 @@ const BuyerOpenConsultCard = styled.div` cursor: pointer; height: 14rem; position: relative; - background-color: ${Grey6}; + background-color: ${White}; padding: 1.6rem; box-sizing: border-box; border-radius: 1.2rem; diff --git a/src/pages/Buyer/BuyerConsult.tsx b/src/pages/Buyer/BuyerConsult.tsx index dc0923a1..09eb6a04 100644 --- a/src/pages/Buyer/BuyerConsult.tsx +++ b/src/pages/Buyer/BuyerConsult.tsx @@ -89,10 +89,6 @@ export const BuyerConsult = () => { * */ const renderCheckBox = () => { - if (consultType === 'open-consult') { - return null; - } - return (
Date: Thu, 13 Jun 2024 22:09:25 +0900 Subject: [PATCH 55/63] refactor: change to use one instance (#294) --- src/api/axios.deprecated.ts | 113 +----------------------------------- src/api/axios.ts | 7 ++- src/api/get.ts | 7 ++- 3 files changed, 11 insertions(+), 116 deletions(-) diff --git a/src/api/axios.deprecated.ts b/src/api/axios.deprecated.ts index 7a77fceb..387cd09b 100644 --- a/src/api/axios.deprecated.ts +++ b/src/api/axios.deprecated.ts @@ -1,115 +1,4 @@ -import axios from 'axios'; -import { postPublicReissue, postReissue } from './post'; -import { getCookie, setCookie } from 'utils/cookie'; - -// -//axios instance that the token is required -// - -const instance = axios.create({ - baseURL: process.env.REACT_APP_API_URL, - headers: { - Authorization: `${getCookie('accessToken')}`, - }, -}); - -instance.interceptors.request.use((config) => { - const token = getCookie('accessToken'); - config.headers.Authorization = token; - - return config; -}); - -//리프레시 토큰 구현 -instance.interceptors.response.use( - (response) => { - return response; - }, - async (error) => { - const { - config, - response: { status }, - } = error; - - if (status === 401) { - const originRequest = config; - try { - const tokenResponse: any = await postReissue({ - refreshToken: getCookie('refreshToken'), - }); - if (tokenResponse.status === 200) { - const { accessToken, refreshToken } = tokenResponse.data; - setCookie('accessToken', accessToken); - setCookie('refreshToken', refreshToken); - axios.defaults.headers.common.Authorization = `${accessToken}`; - originRequest.headers.Authorization = `${accessToken}`; - return instance(originRequest); - } else if (tokenResponse.response.status === 400) { - alert('로그인 후 이용해 주세요.'); - window.location.href = '/mypage'; - } - } catch (error) { - if (axios.isAxiosError(error)) { - alert('로그인 후 이용해 주세요'); - } - } - } - return Promise.reject(error); - }, -); - -// -// axios instance that the token is not required -// - -const publicInstance = axios.create({ - baseURL: process.env.REACT_APP_API_URL, - headers: { - Authorization: `${getCookie('accessToken')}`, - }, -}); -publicInstance.interceptors.request.use((config) => { - const token = getCookie('accessToken'); - config.headers.Authorization = token; - - return config; -}); - -//리프레시 토큰 구현 -publicInstance.interceptors.response.use( - (response) => { - return response; - }, - async (error) => { - const { - config, - response: { status }, - } = error; - - if (status === 401) { - const originRequest = config; - try { - const tokenResponse: any = await postPublicReissue({ - refreshToken: getCookie('refreshToken'), - }); - if (tokenResponse.status === 200) { - const { accessToken, refreshToken } = tokenResponse.data; - setCookie('accessToken', accessToken); - setCookie('refreshToken', refreshToken); - axios.defaults.headers.common.Authorization = `${accessToken}`; - originRequest.headers.Authorization = `${accessToken}`; - return axios(originRequest); - } - } catch (error) { - if (axios.isAxiosError(error)) { - alert('로그인 후 이용해 주세요'); - } - } - } - - return Promise.reject(error); - }, -); +import { instance, publicInstance } from './axios'; // // diff --git a/src/api/axios.ts b/src/api/axios.ts index 52cf1978..229e78f8 100644 --- a/src/api/axios.ts +++ b/src/api/axios.ts @@ -6,7 +6,7 @@ import { getCookie, setCookie } from 'utils/cookie'; //axios instance that the token is required // -const instance = axios.create({ +export const instance = axios.create({ baseURL: process.env.REACT_APP_API_URL, headers: { Authorization: `${getCookie('accessToken')}`, @@ -37,8 +37,10 @@ instance.interceptors.response.use( const tokenResponse: any = await postReissue({ refreshToken: getCookie('refreshToken'), }); + if (tokenResponse.status === 200) { const { accessToken, refreshToken } = tokenResponse.data; + setCookie('accessToken', accessToken); setCookie('refreshToken', refreshToken); axios.defaults.headers.common.Authorization = `${accessToken}`; @@ -62,7 +64,7 @@ instance.interceptors.response.use( // axios instance that the token is not required // -const publicInstance = axios.create({ +export const publicInstance = axios.create({ baseURL: process.env.REACT_APP_API_URL, headers: { Authorization: `${getCookie('accessToken')}`, @@ -95,6 +97,7 @@ publicInstance.interceptors.response.use( }); if (tokenResponse.status === 200) { const { accessToken, refreshToken } = tokenResponse.data; + setCookie('accessToken', accessToken); setCookie('refreshToken', refreshToken); axios.defaults.headers.common.Authorization = `${accessToken}`; diff --git a/src/api/get.ts b/src/api/get.ts index f2238f4b..ab1601b8 100644 --- a/src/api/get.ts +++ b/src/api/get.ts @@ -1,4 +1,4 @@ -import { axiosPublicGet } from './axios'; +import { axiosGet, axiosPublicGet } from './axios'; import { getInstance, getPublicInstance } from './axios.deprecated'; /** @@ -166,7 +166,10 @@ export const getCounselorsRandomConsult = async () => await getInstance(`/posts/counselors/random`); export const getCustomerOpenConsultList = async (params: any) => - await getInstance('/posts/customers', params); + await getInstance('/posts/customers', { params }); + +export const getPostsCutsomers = async (params: any) => + axiosGet('/posts/customers', params); export const getPostsCustomersPublicLikes = (params: any) => axiosPublicGet('/posts/customers/public/likes', params); From 0e3c86211da68406d12f77001c4549844a6b46c0 Mon Sep 17 00:00:00 2001 From: kyuhho Date: Thu, 13 Jun 2024 22:11:15 +0900 Subject: [PATCH 56/63] feat: apply infinite query on buyer open consult page (#294) --- .../BuyerConsult/BuyerOpenConsultSection.tsx | 130 +++++++++--------- 1 file changed, 67 insertions(+), 63 deletions(-) diff --git a/src/components/Buyer/BuyerConsult/BuyerOpenConsultSection.tsx b/src/components/Buyer/BuyerConsult/BuyerOpenConsultSection.tsx index c39a5c8c..551ea4c1 100644 --- a/src/components/Buyer/BuyerConsult/BuyerOpenConsultSection.tsx +++ b/src/components/Buyer/BuyerConsult/BuyerOpenConsultSection.tsx @@ -1,4 +1,4 @@ -import { useLayoutEffect, useRef, useState } from 'react'; +import { useMemo } from 'react'; import { useRecoilValue } from 'recoil'; import styled from 'styled-components'; import { Grey1, Grey2, Grey3, White } from 'styles/color'; @@ -17,14 +17,35 @@ import IsBuyPopup from './IsBuyPopup'; import { Button } from 'components/Common/Button'; import { useNavigate } from 'react-router-dom'; import { ReactComponent as Empty } from 'assets/icons/graphic-noting.svg'; -import { openConsultApiObject } from 'pages/Buyer/BuyerConsult'; -import { getCustomerOpenConsultList } from 'api/get'; -import useIntersectionObserver from 'hooks/useIntersectionObserver'; +import { getPostsCutsomers } from 'api/get'; +import { useInfiniteQuery } from '@tanstack/react-query'; +import useInfiniteObserver from 'hooks/useInfiniteObserver'; // // // +const LIKE_LIST_PER_PAGE = 4; + +// +// +// + +interface GetPostsCutsomersResponse { + postId: number; + isCompleted: boolean; + title: string; + content: string; + isPublic: boolean; + isLiked: boolean; + totalLike: number; + isScrapped: boolean; + totalScrap: number; + totalComment: number; + updatedAt: string; + finishedAt: string; +} + interface BuyerOpenConsultSectionProps { isChecked: boolean; } @@ -36,65 +57,50 @@ interface BuyerOpenConsultSectionProps { function BuyerOpenConsultSection({ isChecked }: BuyerOpenConsultSectionProps) { const navigate = useNavigate(); - const [isLoading, setIsLoading] = useState(true); - const [isLastElem, setIsLastElem] = useState(false); const isBuyPopupOpen = useRecoilValue(isBuyPopupOpenState); - const preventRef = useRef(true); + const { + data: openConsults, + isLoading, + fetchNextPage, + hasNextPage, + isFetching, + isFetchingNextPage, + isLoadingError, + } = useInfiniteQuery({ + queryKey: ['infiniteGetPostsCutsomersResponse', isChecked], + queryFn: async ({ pageParam }) => + await getPostsCutsomers(pageParam).then((res) => { + console.log(res.data); + return res.data; + }), + initialPageParam: { + filter: isChecked, + postId: 0, + }, + getNextPageParam: (lastPage) => { + if (lastPage.length < LIKE_LIST_PER_PAGE) { + return undefined; + } - const onIntersect: IntersectionObserverCallback = async (entry) => { - if (entry[0].isIntersecting && !isLastElem && preventRef.current) { - preventRef.current = false; - await fetchOpenConsult(cardData[cardData.length - 1]?.postId); - preventRef.current = true; - } - }; + const lastItem = lastPage[lastPage.length - 1]; - const { setTarget } = useIntersectionObserver({ - root: null, - rootMargin: '0px', - threshold: 0.8, - onIntersect, + return { filter: isChecked, postId: lastItem.postId }; + }, }); - const [cardData, setCardData] = useState([]); - - const fetchOpenConsult = async (lastId: number) => { - try { - const params = { - filter: isChecked, - postId: lastId, - }; - const res: any = await getCustomerOpenConsultList({ params }); - - if (res.status === 200) { - if (res.data.length !== 0) { - if (lastId === 0) { - setCardData(res.data); - } else { - const updatedReviews = [...cardData, ...res.data]; - setCardData(updatedReviews); - } - } else { - setIsLastElem(true); - } - } else if (res.response.status === 404) { - alert('존재하지 않는 회원입니다.'); - navigate('/login'); - } - } catch (err) { - alert(err); - } finally { - if (lastId === 0) { - setIsLoading(false); - } - } - }; + const openConsultList = useMemo( + () => openConsults?.pages.flatMap((consult) => consult) ?? [], + [openConsults], + ); - useLayoutEffect(() => { - fetchOpenConsult(0); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [isChecked]); + const { observerElem } = useInfiniteObserver({ + fetchNextPage, + hasNextPage, + isFetching, + isFetchingNextPage, + isLoadingError, + }); // // @@ -115,13 +121,13 @@ function BuyerOpenConsultSection({ isChecked }: BuyerOpenConsultSectionProps) { ) : ( {/* 상담카드 부분 */} - {cardData.length === 0 ? ( + {openConsultList.length === 0 ? ( 아직 진행한 상담이 없어요 ) : ( - cardData?.map((item) => { + openConsultList?.map((item) => { if (item.title === null) { return ( @@ -199,11 +205,9 @@ function BuyerOpenConsultSection({ isChecked }: BuyerOpenConsultSectionProps) { )} - {!isLastElem ? ( -
- ) : ( -
- )} + +
+ {isBuyPopupOpen && ( <> From 5457378b4dea4990bb0f0d0605d8d4eb929bfafb Mon Sep 17 00:00:00 2001 From: kyuhho Date: Thu, 13 Jun 2024 22:13:37 +0900 Subject: [PATCH 57/63] chore: fix space (#294) --- src/pages/Buyer/BuyerOpenConsult.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/Buyer/BuyerOpenConsult.tsx b/src/pages/Buyer/BuyerOpenConsult.tsx index 812bc062..908d2260 100644 --- a/src/pages/Buyer/BuyerOpenConsult.tsx +++ b/src/pages/Buyer/BuyerOpenConsult.tsx @@ -30,7 +30,7 @@ const BuyerOpenConsult = () => { - +