From 5c72b968301452eef028aa1df38f8ea2d4ff7d72 Mon Sep 17 00:00:00 2001 From: Mungjin01 Date: Sun, 19 May 2024 16:35:11 +0900 Subject: [PATCH 01/25] =?UTF-8?q?feat:=20=EB=A7=88=EC=9D=B4=ED=8E=98?= =?UTF-8?q?=EC=9D=B4=EC=A7=80=20=EC=82=AC=EC=9D=B4=EB=93=9C=EB=B0=94=20(#5?= =?UTF-8?q?2)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/MyPage/MyPageSidebar.tsx | 72 +++++++++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 src/components/MyPage/MyPageSidebar.tsx diff --git a/src/components/MyPage/MyPageSidebar.tsx b/src/components/MyPage/MyPageSidebar.tsx new file mode 100644 index 0000000..3820597 --- /dev/null +++ b/src/components/MyPage/MyPageSidebar.tsx @@ -0,0 +1,72 @@ +import React from 'react'; + +import styled from 'styled-components'; + +import { theme } from '@/styles'; + +const SidebarContainer = styled.div` + width: 196px; + height: 100%; + padding-top: 76px; + background-color: ${({ theme }) => `${theme.color.white}`}; + border-right: 2px ${({ theme }) => `${theme.color.gray150}`} solid; + display: flex; + flex-direction: column; + justify-content: flex-start; + align-items: flex-start; +`; + +const MenuItem = styled.div<{ $active: boolean }>` + align-self: stretch; + height: 56px; + padding-left: 24px; + padding-right: 24px; + background-color: ${({ $active }) => + $active ? `${theme.color.primary50}` : `${theme.color.white}`}; + border-left: ${({ $active }) => ($active ? '4px #915AFB solid' : 'none')}; + display: flex; + justify-content: flex-start; + align-items: center; + gap: 20px; + cursor: pointer; + + & > div { + text-align: center; + color: ${({ $active }) => ($active ? `${theme.color.primary500}` : `${theme.color.gray600}`)}; + ${({ theme }) => theme.font.desktop.body1m}; + word-wrap: break-word; + } + &:hover { + background-color: ${(props) => props.theme.color.gray150}; + } +`; + +interface SidebarProps { + activeMenu: string; + setActiveMenu: (menu: string) => void; +} + +const Sidebar: React.FC = ({ activeMenu, setActiveMenu }) => { + const menuItems = [ + { label: '브랜드 관리', key: '브랜드 관리' }, + { label: '내 페르소나', key: '내 페르소나' }, + { label: '신청한 경험', key: '신청한 경험' }, + { label: '환경설정', key: '환경설정' }, + ]; + + return ( + + {menuItems.map((item) => ( + setActiveMenu(item.key)} + > +
{item.label}
+
+ ))} +
+ ); +}; + +export default Sidebar; From 45257ca038d3ab18dc76f7526b32424b7759c42d Mon Sep 17 00:00:00 2001 From: Mungjin01 Date: Sun, 19 May 2024 19:10:43 +0900 Subject: [PATCH 02/25] =?UTF-8?q?feat:=20=EB=B8=8C=EB=9E=9C=EB=93=9C=20?= =?UTF-8?q?=EB=B7=B0=20=EC=9E=84=EC=8B=9C=20=EB=A0=88=EC=9D=B4=EC=95=84?= =?UTF-8?q?=EC=9B=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/assets/logos/brandLogo.svg | 25 +++++++ src/components/MyPage/BrandView.tsx | 84 ++++++++++++++++++++++++ src/components/MyPage/ExperienceView.tsx | 17 +++++ src/components/MyPage/PersonaView.tsx | 3 + src/components/MyPage/SettingView.tsx | 12 ++++ src/pages/Mypage.tsx | 33 ++++++++++ src/routers/router.tsx | 33 +++++----- 7 files changed, 192 insertions(+), 15 deletions(-) create mode 100644 src/assets/logos/brandLogo.svg create mode 100644 src/components/MyPage/BrandView.tsx create mode 100644 src/components/MyPage/ExperienceView.tsx create mode 100644 src/components/MyPage/PersonaView.tsx create mode 100644 src/components/MyPage/SettingView.tsx create mode 100644 src/pages/Mypage.tsx diff --git a/src/assets/logos/brandLogo.svg b/src/assets/logos/brandLogo.svg new file mode 100644 index 0000000..6297bc7 --- /dev/null +++ b/src/assets/logos/brandLogo.svg @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/components/MyPage/BrandView.tsx b/src/components/MyPage/BrandView.tsx new file mode 100644 index 0000000..a6e2c62 --- /dev/null +++ b/src/components/MyPage/BrandView.tsx @@ -0,0 +1,84 @@ +import { styled } from 'styled-components'; + +import { ReactComponent as ArrowRight } from '@/assets/icons/arrowRight.svg'; +import { ReactComponent as BrandLogoImage } from '@/assets/logos/brandLogo.svg'; +export const BrandView = () => { + return ( + + + + + + + 브랜드 이름 + 상반기 100만 구독자 확보 + + + 더보기 + + + + + + + ); +}; + +const StyledContainer = styled.div` + width: 100%; + height: 100%; + padding: 100px 24px 52px 24px; +`; + +const BrandHeader = styled.div` + width: 100%; + height: 101px; + padding: 24px; + background-color: ${({ theme }) => `${theme.color.primary50}`}; + border-radius: 16px; + justify-content: space-between; + align-items: center; + display: inline-flex; +`; +const HeaderLeft = styled.div` + justify-content: flex-start; + align-items: center; + gap: 24px; + display: flex; +`; + +const BrandLogo = styled.div` + width: 52px; + flex-direction: column; + justify-content: center; + align-items: center; + display: inline-flex; +`; + +const BrandTitle = styled.div` + color: ${({ theme }) => `${theme.color.gray900}`}; + ${({ theme }) => theme.font.desktop.body1b}; +`; + +const BrandSubtitle = styled.div` + color: ${({ theme }) => `${theme.color.primary500}`}; + ${({ theme }) => theme.font.desktop.body1m}; +`; + +const HeaderRight = styled.div` + justify-content: flex-start; + align-items: center; + gap: 4px; + display: flex; +`; + +const RightText = styled.div` + color: ${({ theme }) => `${theme.color.gray700}`}; + ${({ theme }) => theme.font.desktop.body1m}; +`; + +const RightIcon = styled.div` + width: 24px; + height: 24px; + position: relative; +`; diff --git a/src/components/MyPage/ExperienceView.tsx b/src/components/MyPage/ExperienceView.tsx new file mode 100644 index 0000000..7e6228a --- /dev/null +++ b/src/components/MyPage/ExperienceView.tsx @@ -0,0 +1,17 @@ +import { styled } from 'styled-components'; + +export const ExperienceView = () => { + return 경험어쩌구; +}; + +const StyledContainer = styled.div` + /*padding: 100px 24px 54px 24px; +*/ + width: 100%; + height: 100%; + padding-top: 100px; + padding-left: 24px; + padding-right: 24px; + padding-bottom: 52px; + background-color: aliceblue; +`; diff --git a/src/components/MyPage/PersonaView.tsx b/src/components/MyPage/PersonaView.tsx new file mode 100644 index 0000000..1c2e3d9 --- /dev/null +++ b/src/components/MyPage/PersonaView.tsx @@ -0,0 +1,3 @@ +export const PersonaView = () => { + return
페르소나어쩌구
; +}; diff --git a/src/components/MyPage/SettingView.tsx b/src/components/MyPage/SettingView.tsx new file mode 100644 index 0000000..d5dbb1f --- /dev/null +++ b/src/components/MyPage/SettingView.tsx @@ -0,0 +1,12 @@ +import { styled } from 'styled-components'; + +export const SettingView = () => { + return 설정어쩌구; +}; + +const StyledContainer = styled.div` + width: 100%; + height: 100%; + padding: 100px 24px 52px 24px; + background-color: aliceblue; +`; diff --git a/src/pages/Mypage.tsx b/src/pages/Mypage.tsx new file mode 100644 index 0000000..7628786 --- /dev/null +++ b/src/pages/Mypage.tsx @@ -0,0 +1,33 @@ +import { useState } from 'react'; + +import { BrandView } from '@/components/MyPage/BrandView'; +import { ExperienceView } from '@/components/MyPage/ExperienceView'; +import MyPageSidebar from '@/components/MyPage/MyPageSidebar'; +import { PersonaView } from '@/components/MyPage/PersonaView'; +import { SettingView } from '@/components/MyPage/SettingView'; + +export const MyPage1 = () => { + const [activeMenu, setActiveMenu] = useState('브랜드 관리'); + + const renderContent = () => { + switch (activeMenu) { + case '브랜드 관리': + return ; + case '내 페르소나': + return ; + case '신청한 경험': + return ; + case '환경설정': + return ; + default: + return ; + } + }; + + return ( +
+ +
{renderContent()}
+
+ ); +}; diff --git a/src/routers/router.tsx b/src/routers/router.tsx index 82ace1d..d448fd7 100644 --- a/src/routers/router.tsx +++ b/src/routers/router.tsx @@ -1,8 +1,8 @@ import { Navigate, Route, Routes } from 'react-router-dom'; -/* import { MainLayout } from '@/components/common/Layout/MainLayout'; */ import { DefineLayout } from '@/components/common/Layout/DefineLayout'; import { DesignLayout } from '@/components/common/Layout/DesignLayout'; +import { MainLayout } from '@/components/common/Layout/MainLayout'; import { DefineResultPage } from '@/pages/DefineResultPage'; import { DefineStartPage } from '@/pages/DefineStartPage'; import { DefineTestPage1, DefineTestPage2, DefineTestPage3 } from '@/pages/DefineTestPage'; @@ -12,28 +12,31 @@ import { DesignTestPage3, DesignTestPage4, DesignTestPage5, -} from '@/pages/DesignTestPage'; /* +} from '@/pages/DesignTestPage'; import { HomePage } from '@/pages/HomePage'; import { LoginPage } from '@/pages/LoginPage'; -import { OnboardingPage } from '@/pages/OnboardingPage';*/ -import { RedirectPage } from '@/pages/RedirectPage'; /* +import { MyPage1 } from '@/pages/Mypage'; +import { OnboardingPage } from '@/pages/OnboardingPage'; +import { RedirectPage } from '@/pages/RedirectPage'; import { SelfUnderstandPage } from '@/pages/SelfUnderstandPage'; -import { ExceptPreMemberRoute } from '@/routers/ExceptPreMemberRoute'; */ +import { ExceptPreMemberRoute } from '@/routers/ExceptPreMemberRoute'; +import { MemberPrivateRoute } from '@/routers/MemberPrivateRoute'; export const Router = () => { return ( - {/* }> - } /> - }> - } /> - } /> - } /> - // }> - //} /> - // + { + }> + } /> + }> + } /> + } /> + } /> + //무조건 수정 } /> + }>// // + - */} + } }> }> From e8430fe8f40e6fd37cb18248022b5860bec8e7d9 Mon Sep 17 00:00:00 2001 From: Mungjin01 Date: Mon, 20 May 2024 13:27:27 +0900 Subject: [PATCH 03/25] =?UTF-8?q?feat:=20=EB=A7=88=EC=9D=B4=ED=8E=98?= =?UTF-8?q?=EC=9D=B4=EC=A7=80=20=EB=A0=88=EC=9D=B4=EC=95=84=EC=9B=83=20(#5?= =?UTF-8?q?2)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/MyPage/BrandView.tsx | 46 +++++ src/components/MyPage/Card.tsx | 71 +++++++ src/components/MyPage/Card2.tsx | 82 ++++++++ src/components/MyPage/ExperienceCard.tsx | 155 +++++++++++++++ src/components/MyPage/ExperienceView.tsx | 119 +++++++++++- src/components/MyPage/ExperienceWholeView.tsx | 181 ++++++++++++++++++ src/components/MyPage/MyPageSidebar.tsx | 4 +- src/components/MyPage/PersonaView.tsx | 106 +++++++++- src/components/common/Tab/Tab.tsx | 85 ++++++++ src/pages/Mypage.tsx | 2 +- 10 files changed, 839 insertions(+), 12 deletions(-) create mode 100644 src/components/MyPage/Card.tsx create mode 100644 src/components/MyPage/Card2.tsx create mode 100644 src/components/MyPage/ExperienceCard.tsx create mode 100644 src/components/MyPage/ExperienceWholeView.tsx create mode 100644 src/components/common/Tab/Tab.tsx diff --git a/src/components/MyPage/BrandView.tsx b/src/components/MyPage/BrandView.tsx index a6e2c62..7b5d93f 100644 --- a/src/components/MyPage/BrandView.tsx +++ b/src/components/MyPage/BrandView.tsx @@ -2,6 +2,7 @@ import { styled } from 'styled-components'; import { ReactComponent as ArrowRight } from '@/assets/icons/arrowRight.svg'; import { ReactComponent as BrandLogoImage } from '@/assets/logos/brandLogo.svg'; +import ExampleComponent2 from '@/components/MyPage/Card2'; export const BrandView = () => { return ( @@ -20,6 +21,12 @@ export const BrandView = () => { + + + + + + ); }; @@ -82,3 +89,42 @@ const RightIcon = styled.div` height: 24px; position: relative; `; + +const ContentContainer = styled.div` + align-self: stretch; + height: 996px; + flex-direction: column; + justify-content: center; + align-items: flex-start; + gap: 16px; + display: flex; +`; + +const LeftContent = styled.div` + align-self: stretch; + justify-content: space-between; + align-items: flex-end; + display: inline-flex; +`; + +const CenterContent = styled.div` + align-self: stretch; + height: 208px; + padding: 24px; + background: #f7f7f7; + border-radius: 16px; + border: 2px #efefef solid; + flex-direction: column; + justify-content: center; + align-items: flex-start; + gap: 16px; + display: flex; +`; + +const RightContent = styled.div` + align-self: stretch; + justify-content: flex-start; + align-items: flex-start; + gap: 20px; + display: inline-flex; +`; diff --git a/src/components/MyPage/Card.tsx b/src/components/MyPage/Card.tsx new file mode 100644 index 0000000..3808714 --- /dev/null +++ b/src/components/MyPage/Card.tsx @@ -0,0 +1,71 @@ +import React from 'react'; + +import styled from 'styled-components'; + +const Container = styled.div` + width: 300px; + height: auto; + padding: 20px; + background: white; + box-shadow: 0px 0px 5px rgba(0, 0, 0, 0.13); + border-radius: 8px; + flex-direction: column; + justify-content: flex-start; + align-items: flex-start; + gap: 12px; + display: inline-flex; +`; + +const InnerContainer = styled.div` + align-self: stretch; + height: 72px; + flex-direction: column; + justify-content: flex-start; + align-items: flex-start; + gap: 4px; + display: flex; +`; + +const Title = styled.div` + align-self: stretch; + color: #242424; + font-size: 18px; + font-family: 'Spoqa Han Sans Neo'; + font-weight: 500; + line-height: 28px; + word-wrap: break-word; +`; + +const Description = styled.div` + align-self: stretch; + color: #6f6f6f; + font-size: 12px; + font-family: 'Spoqa Han Sans Neo'; + font-weight: 500; + line-height: 20px; + word-wrap: break-word; + overflow: hidden; + text-overflow: ellipsis; + white-space: pre-wrap; + max-height: 100px; +`; + +const Card = () => { + return ( + + + ERD 설계 방법에 관하여 + + 모든 국민은 종교의 자유를 가진다. 사면·감형 및 복권에 관한 사항은 법률로 정한다. 국회는 + 국정을 감사하거나 특정한 국정사안에 대하여 조사할 수 있으며, 이에 필요한 서류의 제출 또는 + 증인의 출석과 증언이나 의견의 진술을 요구할 수 있다. +
+ 재의의 요구가 있을 때에는 국회는 재의에 붙이고, 재적의원과반수의 출석과 출석의원 3분의 2 + 이상의 찬성으로 전과 같은 의결을 하면 그 법률안은 법률로서 확정된다. +
+
+
+ ); +}; + +export default Card; diff --git a/src/components/MyPage/Card2.tsx b/src/components/MyPage/Card2.tsx new file mode 100644 index 0000000..b65bbbd --- /dev/null +++ b/src/components/MyPage/Card2.tsx @@ -0,0 +1,82 @@ +import React from 'react'; + +import styled from 'styled-components'; + +const Container = styled.div` + width: 300px; + height: auto; + padding: 20px; + background: white; + box-shadow: 0px 0px 5px rgba(0, 0, 0, 0.13); + border-radius: 8px; + flex-direction: column; + justify-content: flex-start; + align-items: flex-start; + gap: 12px; + display: inline-flex; +`; + +const InnerContainer = styled.div` + align-self: stretch; + height: 72px; + flex-direction: column; + justify-content: flex-start; + align-items: flex-start; + gap: 4px; + display: flex; +`; + +const Title = styled.div` + align-self: stretch; + color: #242424; + font-size: 18px; + font-family: 'Spoqa Han Sans Neo'; + font-weight: 500; + line-height: 28px; + word-wrap: break-word; +`; + +const Description = styled.div` + align-self: stretch; + color: #6f6f6f; + font-size: 12px; + font-family: 'Spoqa Han Sans Neo'; + font-weight: 500; + line-height: 20px; + word-wrap: break-word; + overflow: hidden; + text-overflow: ellipsis; + white-space: pre-wrap; + max-height: 100px; +`; + +const DateText = styled.div` + align-self: stretch; + color: #a5a5a5; + font-size: 14px; + font-family: 'Spoqa Han Sans Neo'; + font-weight: 500; + line-height: 20px; + word-wrap: break-word; +`; + +const ExampleComponent2 = () => { + return ( + + + ERD 설계 방법에 관하여 + + 모든 국민은 종교의 자유를 가진다. 사면·감형 및 복권에 관한 사항은 법률로 정한다. 국회는 + 국정을 감사하거나 특정한 국정사안에 대하여 조사할 수 있으며, 이에 필요한 서류의 제출 또는 + 증인의 출석과 증언이나 의견의 진술을 요구할 수 있다. +
+ 재의의 요구가 있을 때에는 국회는 재의에 붙이고, 재적의원과반수의 출석과 출석의원 3분의 2 + 이상의 찬성으로 전과 같은 의결을 하면 그 법률안은 법률로서 확정된다. +
+
+ 2024.06.24 +
+ ); +}; + +export default ExampleComponent2; diff --git a/src/components/MyPage/ExperienceCard.tsx b/src/components/MyPage/ExperienceCard.tsx new file mode 100644 index 0000000..aefae05 --- /dev/null +++ b/src/components/MyPage/ExperienceCard.tsx @@ -0,0 +1,155 @@ +import styled, { css } from 'styled-components'; + +interface StyledImageProps { + $variant: 'type1' | 'type2'; +} + +const Container = styled.div` + width: 247px; + height: 246px; + display: flex; + flex-direction: column; + justify-content: flex-start; + align-items: center; + gap: 12px; + overflow: hidden; + cursor: pointer; +`; + +const ImageContainer = styled.div` + width: 247px; + height: 154px; + overflow: hidden; + border-radius: 24px; + display: flex; + justify-content: center; + align-items: center; + position: relative; + + ${({ $variant }) => + $variant === 'type2' && + css` + &:hover { + &::before { + content: ''; + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: rgba(17, 17, 17, 0.36); + border-radius: 24px; + z-index: 1; + } + + ${Overlay} { + display: flex; + } + } + `} +`; + +const StyledImage = styled.img` + width: 100%; + height: 100%; + object-fit: cover; + transition: transform 0.3s ease-in-out; + + &:hover { + ${({ $variant }) => + $variant === 'type1' && + css` + transform: scale(1.1); + `} + } +`; + +const Overlay = styled.div` + flex: 1 1 0; + align-self: stretch; + padding: 24px; + display: none; + flex-direction: column; + justify-content: flex-end; + align-items: center; + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + z-index: 2; +`; + +const LinkButtonOverlay = styled.div` + align-self: stretch; + height: 48px; + padding: 8px 24px; + background: rgba(255, 255, 255, 0.3); + border-radius: 8px; + backdrop-filter: blur(10px); + display: flex; + justify-content: center; + align-items: center; + gap: 8px; + + & > div { + text-align: center; + color: ${({ theme }) => theme.color.white}; + ${({ theme }) => theme.font.desktop.label1m}; + word-wrap: break-word; + } +`; + +const TextContainer = styled.div` + align-self: stretch; + height: 80px; + display: flex; + flex-direction: column; + justify-content: flex-start; + align-items: flex-start; + gap: 4px; +`; + +const TopText = styled.div` + text-align: center; + color: ${({ theme, $variant }) => + $variant === 'type1' ? theme.color.primary600 : theme.color.secondary600}; + ${({ theme }) => theme.font.desktop.label1m}; + word-wrap: break-word; +`; + +const BottomText = styled.div` + align-self: stretch; + color: ${({ theme }) => theme.color.gray900}; + ${({ theme }) => theme.font.desktop.body1m}; + text-align: left; + word-wrap: break-word; +`; + +interface ExperienceCardProps extends StyledImageProps { + imageUrl: string; + title: string; + subtitle: string; + linkUrl?: string; +} + +export const ExperienceCard = ({ imageUrl, title, subtitle, $variant }: ExperienceCardProps) => { + return ( + + + + {$variant === 'type2' && ( + + +
외부 링크로 이동
+
+
+ )} +
+ + {title} + {subtitle} + +
+ ); +}; diff --git a/src/components/MyPage/ExperienceView.tsx b/src/components/MyPage/ExperienceView.tsx index 7e6228a..34aa1ea 100644 --- a/src/components/MyPage/ExperienceView.tsx +++ b/src/components/MyPage/ExperienceView.tsx @@ -1,17 +1,120 @@ -import { styled } from 'styled-components'; +import { useState } from 'react'; + +import styled from 'styled-components'; + +import { ExperienceWholeView } from '@/components/MyPage/ExperienceWholeView'; +import { Dropdown } from '@/components/common/Dropdown/Dropdown'; +import Tabs from '@/components/common/Tab/Tab'; + +interface Filter { + title: string; + contents: string[]; + selected: string | string[]; +} + +const wholeFilter: Filter[] = [ + { + title: '정렬 ', + contents: ['1', '2'], + selected: ' ', + }, +]; export const ExperienceView = () => { - return 경험어쩌구; -}; + const [filters, setFilters] = useState(wholeFilter); + const handleFilterChange = (index: number, selected: string | string[]) => { + const newFilters = [...filters]; + newFilters[index].selected = selected; + setFilters(newFilters); + }; + + const tabs = [ + { + id: 'tab1', + label: '전체', + content: ( +
+ + + {filters.map((filter, index) => ( + handleFilterChange(index, content)} + /> + ))} + + + + + + + +
+ ), + }, + { + id: 'tab2', + label: '자기이해', + content:
자기이해
, + }, + { + id: 'tab3', + label: '브랜딩', + content:
브랜딩
, + }, + ]; + + return ( + + + + ); +}; const StyledContainer = styled.div` - /*padding: 100px 24px 54px 24px; -*/ width: 100%; height: 100%; - padding-top: 100px; + padding-top: 81px; + + padding-bottom: 52px; +`; +const CardContainer = styled.div` + padding: 24px; + display: flex; +`; + +const StyledFilterContainer = styled.div` + display: flex; + justify-content: space-between; + align-items: center; padding-left: 24px; padding-right: 24px; - padding-bottom: 52px; - background-color: aliceblue; + padding-top: 24px; + + .refresh-button { + ${({ theme }) => theme.font.desktop.body1m}; + color: ${({ theme }) => theme.color.primary700}; + } +`; + +const StyledDropdownContainer = styled.div` + display: flex; + gap: 12px; `; diff --git a/src/components/MyPage/ExperienceWholeView.tsx b/src/components/MyPage/ExperienceWholeView.tsx new file mode 100644 index 0000000..0cb8481 --- /dev/null +++ b/src/components/MyPage/ExperienceWholeView.tsx @@ -0,0 +1,181 @@ +import styled from 'styled-components'; + +import TestImage from '@/assets/test1.png'; +import { ExperienceCard } from '@/components/MyPage/ExperienceCard'; + +export const ExperienceWholeView = () => { + return ( + + + {Dummy4.map((item) => ( + + ))} + + + ); +}; + +const StyledSectionContainer = styled.div` + width: 100%; + height: 100%; + + flex-direction: column; + justify-content: flex-start; + align-items: flex-start; + gap: 24px; + display: flex; +`; + +const Container = styled.div` + width: 100%; + display: flex; + flex-wrap: wrap; + justify-content: flex-start; + gap: 16px; +`; + +const Dummy4 = [ + { + id: 1, + img: TestImage, + title: '신청완료', + subtitle: '경험 타이틀 경험 타이틀경험 타이틀 경험 타이틀경험 타이틀', + keywords: ['keyword1', 'keyword2'], + hot: true, + }, + { + id: 2, + img: TestImage, + title: '신청완료', + subtitle: '경험 타이틀 경험 타이틀경험 타이틀 경험 타이틀경험 타이틀', + keywords: ['keyword1', 'keyword2'], + hot: true, + }, + { + id: 3, + img: TestImage, + title: '신청완료', + subtitle: '경험 타이틀 경험 타이틀경험 타이틀 경험 타이틀경험 타이틀', + keywords: ['keyword1', 'keyword2'], + hot: true, + }, + { + id: 4, + img: TestImage, + title: '신청완료', + subtitle: '경험 타이틀 경험 타이틀경험 타이틀 경험 타이틀경험 타이틀', + keywords: ['keyword1', 'keyword2'], + hot: true, + }, + { + id: 5, + img: TestImage, + title: '신청완료', + subtitle: '경험 타이틀 경험 타이틀경험 타이틀 경험 타이틀경험 타이틀', + keywords: ['keyword1', 'keyword2'], + hot: true, + }, + { + id: 6, + img: TestImage, + title: '신청완료', + subtitle: '경험 타이틀 경험 타이틀경험 타이틀 경험 타이틀경험 타이틀', + keywords: ['keyword1', 'keyword2'], + hot: true, + }, + { + id: 7, + img: TestImage, + title: '신청완료', + subtitle: '경험 타이틀 경험 타이틀경험 타이틀 경험 타이틀경험 타이틀', + keywords: ['keyword1', 'keyword2'], + hot: true, + }, + { + id: 8, + img: TestImage, + title: '신청완료', + subtitle: '경험 타이틀 경험 타이틀경험 타이틀 경험 타이틀경험 타이틀', + keywords: ['keyword1', 'keyword2'], + hot: true, + }, + { + id: 9, + img: TestImage, + title: '신청완료', + subtitle: '경험 타이틀 경험 타이틀경험 타이틀 경험 타이틀경험 타이틀', + keywords: ['keyword1', 'keyword2'], + hot: true, + }, + { + id: 10, + img: TestImage, + title: '신청완료', + subtitle: '경험 타이틀 경험 타이틀경험 타이틀 경험 타이틀경험 타이틀', + keywords: ['keyword1', 'keyword2'], + hot: true, + }, + { + id: 11, + img: TestImage, + title: '신청완료', + subtitle: '경험 타이틀 경험 타이틀경험 타이틀 경험 타이틀경험 타이틀', + keywords: ['keyword1', 'keyword2'], + hot: true, + }, + + { + id: 12, + img: TestImage, + title: '신청완료', + subtitle: '경험 타이틀 경험 타이틀경험 타이틀 경험 타이틀경험 타이틀', + keywords: ['keyword1', 'keyword2'], + hot: true, + }, + { + id: 13, + img: TestImage, + title: '신청완료', + subtitle: '경험 타이틀 경험 타이틀경험 타이틀 경험 타이틀경험 타이틀', + keywords: ['keyword1', 'keyword2'], + hot: true, + }, + { + id: 14, + img: TestImage, + title: '신청완료', + subtitle: '경험 타이틀 경험 타이틀경험 타이틀 경험 타이틀경험 타이틀', + keywords: ['keyword1', 'keyword2'], + hot: true, + }, + { + id: 15, + img: TestImage, + title: '신청완료', + subtitle: '경험 타이틀 경험 타이틀경험 타이틀 경험 타이틀경험 타이틀', + keywords: ['keyword1', 'keyword2'], + hot: true, + }, + { + id: 16, + img: TestImage, + title: '신청완료', + subtitle: '경험 타이틀 경험 타이틀경험 타이틀 경험 타이틀경험 타이틀', + keywords: ['keyword1', 'keyword2'], + hot: true, + }, + { + id: 17, + img: TestImage, + title: '신청완료', + subtitle: '경험 타이틀 경험 타이틀경험 타이틀 경험 타이틀경험 타이틀', + keywords: ['keyword1', 'keyword2'], + hot: true, + }, +]; diff --git a/src/components/MyPage/MyPageSidebar.tsx b/src/components/MyPage/MyPageSidebar.tsx index 3820597..b5a2f46 100644 --- a/src/components/MyPage/MyPageSidebar.tsx +++ b/src/components/MyPage/MyPageSidebar.tsx @@ -6,8 +6,8 @@ import { theme } from '@/styles'; const SidebarContainer = styled.div` width: 196px; - height: 100%; - padding-top: 76px; + height: auto; + padding-top: 81px; background-color: ${({ theme }) => `${theme.color.white}`}; border-right: 2px ${({ theme }) => `${theme.color.gray150}`} solid; display: flex; diff --git a/src/components/MyPage/PersonaView.tsx b/src/components/MyPage/PersonaView.tsx index 1c2e3d9..5cdee90 100644 --- a/src/components/MyPage/PersonaView.tsx +++ b/src/components/MyPage/PersonaView.tsx @@ -1,3 +1,107 @@ +import { styled } from 'styled-components'; + +import Card from '@/components/MyPage/Card'; + export const PersonaView = () => { - return
페르소나어쩌구
; + return ( + <> + + + + + + Discover 나를 깊게 이해해요 + + + + + + + + + + + + ); }; +const StyledContainer = styled.div` + padding-top: 81px; +`; +const StyledInnerContainer = styled.div` + width: 100%; + height: 100%; + padding: 24px; + flex-direction: column; + justify-content: flex-start; + align-items: flex-start; + gap: 24px; + display: inline-flex; +`; + +const StyledTopContainer = styled.div` + align-self: stretch; + height: 1381px; + flex-direction: column; + justify-content: flex-start; + align-items: center; + gap: 48px; + display: flex; +`; + +const TopContainer = styled.div` + align-self: stretch; + height: 706px; + padding: 24px; + background-color: ${({ theme }) => `${theme.color.primary50}`}; + border-radius: 16px; + overflow: hidden; + border: 2px #ddccfe solid; + flex-direction: column; + justify-content: flex-start; + align-items: center; + gap: 24px; + display: flex; +`; + +const BottomContainer = styled.div` + align-self: stretch; + height: 627px; + padding: 24px; + background-color: ${({ theme }) => `${theme.color.gray150}`}; + border-radius: 16px; + overflow: hidden; + border: 2px #dfdfdf solid; + flex-direction: column; + justify-content: flex-start; + align-items: flex-start; + gap: 24px; + display: flex; +`; + +const BottomTitleContainer = styled.div` + align-self: stretch; + height: 28px; + flex-direction: column; + justify-content: center; + align-items: flex-start; + gap: 16px; + display: flex; +`; + +const BottomCardContainer = styled.div` + align-self: stretch; + justify-content: flex-start; + align-items: center; + gap: 12px; + display: inline-flex; +`; + +const BottomImageContainer = styled.div` + width: 988px; + height: 391px; + position: relative; + background: white; + box-shadow: 0px 0px 5px rgba(0, 0, 0, 0.13); + border-radius: 16px; + overflow: hidden; +`; diff --git a/src/components/common/Tab/Tab.tsx b/src/components/common/Tab/Tab.tsx new file mode 100644 index 0000000..ebacb35 --- /dev/null +++ b/src/components/common/Tab/Tab.tsx @@ -0,0 +1,85 @@ +import { useState, ReactNode } from 'react'; + +import styled from 'styled-components'; + +const TabContainer = styled.div` + width: 100%; + height: 100%; + padding-left: 24px; + padding-right: 64px; + background-color: ${({ theme }) => theme.color.white}; + border-bottom: 4px #f7f7f7 solid; + display: inline-flex; + justify-content: flex-start; + align-items: center; + gap: 16px; +`; + +const Tab = styled.div<{ $isActive: boolean }>` + padding: 20px 32px; + background-color: ${({ theme }) => theme.color.white}; + justify-content: center; + align-items: center; + gap: 8px; + display: flex; + border-bottom: ${({ $isActive }) => ($isActive ? '4px #915AFB solid' : 'none')}; + cursor: pointer; + + & > div { + color: ${({ $isActive }) => ($isActive ? '#915AFB' : '#8B8B8B')}; + ${({ theme }) => theme.font.desktop.body1m}; + word-wrap: break-word; + } +`; + +const TabPanel = styled.div<{ $hidden: boolean }>` + padding-bottom: 0px; + display: ${({ $hidden }) => ($hidden ? 'none' : 'block')}; +`; + +interface TabItem { + id: string; + label: string; + content: ReactNode; +} + +interface TabsProps { + tabs: TabItem[]; +} + +const Tabs = ({ tabs }: TabsProps) => { + const [value, setValue] = useState(0); + + const handleChange = (index: number) => { + setValue(index); + }; + + return ( + <> + + + {tabs.map((tab, index) => ( + handleChange(index)}> +
{tab.label}
+
+ ))} +
+
+
+ {tabs.map((tab, index) => ( + + {tab.content} + + ))} +
+ + ); +}; + +export default Tabs; + +const Container = styled.div` + display: flex; + flex-direction: column; + align-items: center; +`; diff --git a/src/pages/Mypage.tsx b/src/pages/Mypage.tsx index 7628786..da0c127 100644 --- a/src/pages/Mypage.tsx +++ b/src/pages/Mypage.tsx @@ -27,7 +27,7 @@ export const MyPage1 = () => { return (
-
{renderContent()}
+
{renderContent()}
); }; From f5cca07eb331b50e4f4b22c9ed5075c9b45df5e5 Mon Sep 17 00:00:00 2001 From: Mungjin01 Date: Mon, 20 May 2024 20:58:22 +0900 Subject: [PATCH 04/25] =?UTF-8?q?feat:=20=EB=A7=88=EC=9D=B4=ED=8E=98?= =?UTF-8?q?=EC=9D=B4=EC=A7=80=20=EC=A0=84=EC=B2=B4=20=EB=A0=88=EC=9D=B4?= =?UTF-8?q?=EC=95=84=EC=9B=83=20(#52)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/assets/myPage/MypageDiscover.png | Bin 0 -> 37060 bytes src/components/MyPage/BrandView.tsx | 116 ++++++++++++++++-- src/components/MyPage/Card.tsx | 18 +-- .../MyPage/{Card2.tsx => DateCard.tsx} | 29 ++--- src/components/MyPage/ExperienceCard.tsx | 10 +- src/components/MyPage/ExperienceView.tsx | 4 +- src/components/MyPage/PersonaView.tsx | 42 +++++-- .../common/Tab/{Tab.tsx => MyPageTab.tsx} | 4 +- 8 files changed, 156 insertions(+), 67 deletions(-) create mode 100644 src/assets/myPage/MypageDiscover.png rename src/components/MyPage/{Card2.tsx => DateCard.tsx} (78%) rename src/components/common/Tab/{Tab.tsx => MyPageTab.tsx} (96%) diff --git a/src/assets/myPage/MypageDiscover.png b/src/assets/myPage/MypageDiscover.png new file mode 100644 index 0000000000000000000000000000000000000000..471813408cc78b14880f123119a5d9a6479eb1d3 GIT binary patch literal 37060 zcmX_n2Rz%``+rn%t3`X!UKDM$YSiAFF1L1#s@f$sL9E!LyGGUC)LyYSLA7QgYR3qz zCRT_YgyjFx`~ClTdEt}uIpaCcdB*#BpZ5lOnoNwGj35w*>B+wj4M8AUJP1S+{}(;* zWM#V4ANX~_^ItP42y~J4?1u)Fp7{^(kOpd~c^?EHzP<|lbKX%yR|5p9iMx1WO9ujd zGJEn+!#IFuV?OAU1ukv*NUl!HKk0m-(B&_;8Q&-0v;Cxg=^9soi>Tf6F~58FH^ZH0 z!v=Og!9uNyP!7j4aL_&#+detIFK zRZ`t;^0~tNf@PUEnurQEx~rd+0NZ&1I|{vJm^2s!#wozENigiPOi`p^sqxpu8v&h$ zyv0`nIx|WO-jRf^?D`d!OfM9T5+B{kxx04ionpFnx~HPI<%n38O)BWC{6_3Ku>NP3 zYUW0DquP?}$YN{T)0FZpWjAV}N~|EwY?xVG-+}e(<z0{hf;!z-%Z)?bo5q}53RxwQ%MzDMB5K7mi<9)9}dHYkGkw0VZ{~}l(zzE zJgx<+g@h$kcRm^qN{se0XAN*;JqVD%j#YO?y+0zS{nI44XZ8A2kAHam(i}fWv-0M; z4H+H6B778-`qHECKy91Yb-+tToK3eI{j{50bNZITt%F=Ze{0swBMA}wCB3X17iItN zbD8Y}NN`n>P(OH++HGXM6?!G5iD6j3`5r;$)tuVek+(-@ z=;?8FUw@FAe-0Ae*yWnOrSw|4?-l9ZFGM`?!IdhdHI)y6Vfhpu*6cninZe3vd?63@ zo7&c}d}R5n9Ue^7Fh?#s#T}(zw7hl{c#dd3PGmi5l6y@pI>I&uSIM}|_AAt!)}1n7 z-x4;aDN7wZjnwBkO(hHOHx{Z-`vNMDLP_#O%e*Oz6~#vC3i^H~8tCHN0c4tD*FG8C z8I(y9U1Pg$FZhI@qL)WE+w>HTLHLr$pvQ`Z8cUls%g1+hj& zMPV)m1_u7Uv9TdY1>Zz3S;e*d{;X{nbU=9Wu$`W|9&_BG6Fu}Xi5PN;qDICtEPRyY z_5TXSE@gb`YnpO|UkqhFnM(WA*G~}%PGL~vW932rzP2x?^YCQhJdfI1OI>iM>y{UE z`0WY2dqHXqy43?{kA_#kVRuy&)M8#Y{_E#vfZ<_z|zmY->T5hh6TG(9Zg)w z{>yz*YDS15!=k^wQzA|^0!GP?60lvEtgNi}Q4B0=OnT{G!}_b2KYS*^dOUJqIg!+y>Yo8A8Sh9^1et%R886Tm3T%v{N`~c>^EAK>_(KCve@PA z2tQG~{EqglmlyLv#14|ad6UO!r$_sCubi&p4PL1h@Me5BEU#-W2|gP>H}uIr^cQQ+ z;R!NLikeSz_8Lgxv8E=KTwzv6=`En$mEuoOXo4bG-;XRR3yJI7YfYb;?R*aj2~pb@ zZR`K@Lb!pIatCA=kK#S3U8d#Fl0nn2*fzyoLZUD_FtTe^hu`-P?82d+boj4v{CVNi z)ZyWw`RVDYzoj1rJgciHZc48rEwBG(POZkahn^1Srz-~@6zkX<)x0qHXHxGpCF=j4 z(^uIae|hS^zcwLC@q52jQ5_AFHKJ5PLR_(qs=H~{1_F#!E3HHkwZ!33`_r4sTeqo7M@D~H*NJt0W}BtfP$RV zUyzQt2+wzDt8Hp(viA7%zWR5aG)bIf0#}%Mw*vm)Lt|s(qciUY0vYS@PY%=L(*$vt zzvdkVJB-@=(?4q!#&Z7o)Zpp+hhKWgUNe~+$ZQd?{t?9S&vW(fzP`S??^;edpfaIG zz3o}i|H&mOWgxYDJEIoA)SDvVpQv!x?!PVYeJvZtC%|y_Zf-08xA}oj!bbm%KmJhM zPShUtXIo1mjD=)uxdA^5d>Qb)fB5xw$I6_D$DckxF1b}zXo|7U=D8hvd;xB>DA4q} z?4PE&U)nDnT~DwQ($y|ocxhw#ldVw#sG4-SB|7m5Q0hnIamzy@G2bqtC|EyCTcU?JPgcqv+yl>9( z-~V;IR;LkIo%sJ1$YgY40!M`?+GT4MMqc|Y@t?{tK7Rc8gsSU^WPN|ZOP=FDp}5?3 z{xeWlf%BA_kR!`LCN1cLcp#x3v%Tw2I7*sA%Sk!vU+9=0$>uv~+{L4}^rUnZ_T&SV z&01Zou(PV<{0{5}I(6N{@}Hx21}w+E-re>otVf_|nk#7BN@CWxa09FQD~oyhbj-I& zbP(D`d*Fz^1HDD^1%)5F*=$}MH0jlQ#SFS5|C3usZD(TR;3TTtTg3RS!L)JuRg=_0_9iL#*sb+RW@Q1=!CZ2Z6G(!>@HBI)Fh6S>%2zjvD&7-kLdB{ zavO5`%C)l=q&%M8fzFPvAc34l@CNTr+RqKKIaR)4Kkj9TT@_8Xjf{Gh=dIpW_BQa- z{;5rJp$c`8#p9MZLpY-o%SjHf-7gt={#m!#CmgXVG>P1ig7^8EmA+hUI8O}vH7!Vn zwxvvvIwxOS^?oGC8>mp!m9%Q2Y|DndXd}D?rxDb3-u@OHGA%U}30`Z68&S{7&kdc} z-(>>j{`y-`zl{czczYqDW{6*bq_!9FMcYs_gkk8rL$8kk_x?=wy!@x#F!1IDWW<`0 z0}RK2X6b+f?o>pE6nP{sZO|N~d3Yn|fWekFoB^v6U&r!e@m7Qa$oP>KJAu-r%zk(Q z)SsV9Ylp&!CJ$M>uYK|TJi4`VaAC=y_qzJN;JQVr;H~t}UyQB~25ZvcIa8Ik@>uD3 z?dWl9AOmO7&1VzGm}r=_we?HD3l-JXC3yRR-rWqasi;WMdiE%yMvb=UjTZc#kF>*q z`L1%7qa4E7qaEr+Xvu8NN^gHJ{DgZZ!&%XvqBEO04DMvx3tRsvhS~k@fT#IZyfI|W zvw3Yod?&sN@iI)*LUL-8RtVL}qRp_ymq!0-a1-4`mXKp#j%dr40EK_>@@irlsf%cd z^i~Mix&dgeKxCvBT_XiH`y~oP=4~COjMES&i{HFd!?P~TgLxs?qt)S!K|hrPQdJP9 zF~H1IQ-h=y>f6TD?>MYQ+>r^d-Y-4H7x{if9iy#W2qcY0hcXGox!BkO9+q-x_tb>K>gLBf=tF)!pIi-aR>oZIdU&hq+i6EH+It$XY9n zhUjB|`;_B{qfHs9MPAYSK)l!y_Vu1s7A0EXc@_Hx*CZ8Jm^bC@qVtchidahW6C~+6 zn&Q+&k5kdcPvboUvt}SpVYx0@niP+=j+5>%z0Ru}5Bjrd)y)V3UVxg&YG60pBLDUS z35-%yG)J{RRc5A0`5WW%;6Fd7e=Dt+qw8$FcTe0@oEq(anNa(TvB)y5G`%lm{bFY$ zX@X`Ol}^8xUr@lzN2e>Agqt2tsiWq|;lMh%gPhg?Z1pEfjPqfulCc zJ33+L5ASoXFs)o-;gqUHUtDa8$q-r4$J{tg_k9BWxwFPgkJ{3ecwe5#&K-H+cx>`e zB{?IEQiDdQnd?>M%s>Rh}&qB7Pbz_EPxusVaSygK0Z@(B+(r1n%VbJ965F z;e=#^kLh-*frLb+K@)Gv1u@~xbFd$ozTk?)Zo}Tw$70o@-?(3`%gh-1Ev#cYm!0r3 zdX+=>S}r!SB?{XdZ-p?{?=a}icU&MAEOwwOj+!MNoC*d}iJ_a(OvCKKc`X7DC}J#e zu2~#pIV*&$b20*gQgt-Gs&ex!x92?vF824NtFL+`CRr1QTvlsKhPPVv(t^QllxS=&I zI-@6<2n!n%S#rQtK7nqu${I0($003ED6aY^3@dSJ@(vz{bp>+GMp+NOJe@re30BL6 z&0iE-71+DnNU%tf`R>WC7#HmOHfAWG(-2i%5M0Tnj1VXuhk!63Eb?_*bXb z{4XT9_$5lBb93_1L9rI{bf^%QP&IC{`$HxtxXpj0G9kaBUF)a24N;{y2s<#GU5-3_ zUlo^jaUn(ARV`kP%rW($Vb!heoC2NI`Q;eh2{yIUnN*bDI;2$Vy>|=fH0f?1O20!R zPs{ZA^oNwU@FB`VC#tNLf79inb7{L}goU3)MCid$@N&;)`Gz&S%FIC&YV}#jRO#^SL-!nHwc*Im$$S^r zznnCXL!FiK$y~K`Dm(sFY!lxt5vNsQf5Wo0e$Ok9an#Ljgx`NIzIYA_?iXsndRq)8 zQWtmatmvhGg4N57{3wwr>>*J|*n^1un{MPw4J>YH)^$mx#N4S36=bg=^N&D8BGI}axi z1L)4KW0tT6O-LsHQ^rQiBWKmY>DAwpFTw~Joiz*#9-FXYk^C$>2G+fHsSksTN%|T` zy$t1Ci642${ho@@&?(cIl^Lv!@xB2n*J2b*aF>O`?;L7nX(+XoHliv zy_rgkg$4ZCGF{;WD8EEO47o z!3Rl2;p-a|uM9eohfJ+(-!uVvB7${&w*1H;Pt0Z2d>(+MzLYRGxnU<7T?4(ss;Jvj zb{H9?X+X~V3^mrOr*rI0cTio8#wPThZUz}?Roo7>cu%$6d>XFAa)#ICGuteZLJ9DY z*OM~-QSmG%J?XcW`)NUuf4~2RffLeLaRiV7*u#D2dDDKa%XfIt^@8wOCeFFtrgAp} zp5I#YCY+Ed5v*04Th=+aNfW>DXSxZ+iJ&G9qO^k*CQ*DHaoGwEUmk_7wM?{d@9T!$ z6?yOX-M!(|ymGr1uNGi~ya$P=$>dI>kDtP}3i#OQ(KH`ea~gX>F%v7^4*jZhfTF)L z^h=Sr>&grQ8_4;}-L3m{AC)FuTsPNc!BLfFMQ<_xtHF3I#$WG(NQ0?39K0~MI~iGv z!=1Nyu{8IzX)`{=vGc2s6~}=LFALgFNPGdY8f{6;tbm;wHU=*idU4&JN>@Y(3oIZ? zW#~PPpC({g+U-;qH~a(dmjx!um^#d_+5<6t;=Qq?`SU5-v>@ZICdA?T^Clxtg0;4M z^dM#_xn9#3W}57JYHgJ+Vl*XaIhajh+!7=54~|ZiMW4n12Jk3-loswAvEwh2xBuc|I9DbI&d(qXHJfHIr5w)`@eyTg)4-%9rj6kI2zN$(RBlm>T7Msoc!w z#GY;yaVRHrcvI=5yM_L`<$jF0cf2Ivq_ZNuZIeKxpk3ePD5qwTW2q^O*0(`&H6O%5r8kljmKShTRd~x|uD#dCwshZRT z(YWqc`t?@R`ioK3)$T9^#*KPJbPI=00cLknl6hum}|sqdcKZd6#WP8W4Zdg~7@T5eh(TsV*Y0xYk;- z)4lcc=Ny%RcK=4lo4onEI(@H;nbwB#Zqj`nyBjj{FelzxMeiaHNFBF#aKPW5Ac?HYHxh+g3StZQg{+H>rjD%M1KBohEMRLjl ziqHsIRZEl1hs0(K6rtbIhps#Vfl8!(?MYR3o8sNfAOoo}ha^%1>(%JlzWvC%DDBwU z0rKw>4Q@q63+tmuqrQoo*$?gjlNS&m6?n%!H(p`}spqe(XiXc5e}n;+6UpAB>(L{g zSe4&~h+HhK`wPH~*d049PBcXlYiL0(4r>*Ah7P#Hak&}7Y7YtLH-tq9QkI0wRhwpW z^|&jeCgnC|40@SCCFg=hez71~(*~9SoMisG*jR{9fu!BnwV95SH+2}~Mn><3;;L7P zZD#FeiJD7mQFq2bwoC3EQtP#C4jPd0TYTDEF!Bfw{F!B0N;JUGqB`7tXL#^@U0^79(T|llU(R=Rsr|Uex?vlgtGV5W~J#UVtp#J(YWA7Ayg1K6*gKT8sjt0SVk#)-F}?d{hP`b9`(d zb(FwJD22QvE2UW6RSRB2V2yGMo<~^Z-LR%fIoDxM$#jG98Q35~#yFJ1>&p7~S51>@ zvQNiY;^IXZK;sX$W`(@A7B#dmG`Za;6jG;Lv0j#B3{c?#OD_36t$G#1QbY^Kxn4kW zMbMkW5qw!Pac!5ZTCC>eJ&NytEB)=n))&Vs7k1dgdkK_FxjjK63e7$O93Gum`&J|j zpXPYKitC?$#H%_EUUZMu*!A7wwPu(FkXIQaU?9(VE=apAHiR@kLOwn0Q)`UlcA!#D zS*_}L9A_KdF}rc9$0Z?~TFp4ACtT;#xczasFg=W#K=8O3%h%RcmVXe7BX zECcBgMkAa{HM_#B(PGx{PE)D)jDEm{R06eun>f=TObn@KQSezY_`P4OpVLSiWjjY? z^Hl*YR`~gbOZnI{gx3m!!l>j0hyyyCo2<%+^xX=i94)`Ks=9YLGV-ZIb55eo?^{miga*txtfW|&9HH|XVeYO&$s!*^ zc-@!0Bpc1k#eTjcoy- zh=&Z#jFBHNARlSeQEf12x}KwzV^Rk(1emssvIo5f5!=C9>!`1G>T_@cPO)?-d*b>& z?2xMLo_(0!T92;oh7~4D7)_CKLW1U^3EB)eB!`E^dV9Eq(Ur0*nXb&_WMXmDj%&HJ ze1XmLS$m0ymUBn!CJgh6H>SFMpO?1fLk)7U^n2FrmsT=G9~fZIOD_ZuXj)4WDQj^^e>J&2S(bZEU+))g zyX?ufi-A>xt$ihNxRLN2y(6a=S_pSz^81fs2>Ct5rkIqkben;}CYu6Ll${|lE|9v_ zfz3BMoZp_$QLBbgR&)!4k+13I2P0S2ExOzAZ>;_2ed&1hXowAH9h`gERZ`3GS~-e+sxjl5Y-~o1HBa5{2h)ltY}~oRH%wPs zBP)}do{73(&)+sv6sb( z+#s#RbiP&f`hVmWg6jm|GJl9N6Yrpxf&J~@b^1F&e}>kcZu+R!t~EyzDtg(px`N!Q zu*L}*(P#=?&~p546?WkAZ)LF7IO^}?`jg5w!1a{Xk%Tsa=7m41x z7nw}FLulPo!QRj#Jz|{_F}Jn~L)+A4)WRtWN>ZM1vu6Os3~LA9o?CPfN>b!Xb&T|0 zBZG3!i;7P%%euuDGe=t%nSqyEPctA0=MTPPKrsc~*6V3%1p^Q73V=*Om9wq1zh^z# zP=01puFbo{N_;~zzMnQBI|XFnPyP(cgYfUpw@vS*(3#k57TcU82hAd7)(ss>)WAct zW6+VYsWy6#yP8I6R4y(jOQ>d`U_EPbQ5uEP;n4jB?$#C8TZnE_z1xk>jf7_HabQ}& zbM3#tUF_i>Rr!uBu5&1mIi7aG(eGQ~{z1!c-wfBNT*ad@9A{?BO?6g^vfl}xGJA(` zpCk!s2$@g$t%^a=asnkGy3^3_rJFzYlB;_mjDs@r#ocNh%uMnt4eK)3q{4VWFOvK( zEr0&Sice)tq*Z@EF0D&b%WT}k-0W+!e$I*8z|~&b4N-iKh5MnVOw>iJ>@@NTIzQ?q zw+=Z9GLO&aJuTtB?3qGdj#Fx_GQY3e1l=9qCmXvCj#oJFA76094JOgY429^4cAo6?&+b)h)#8L_2(XaHu_su22Cs)PzrJcs zu%BPAqa4gaGCqp7_8WhU3=84$9reTWIzic1T4x`6ad?K=z`NvKx^$aJ`d}|%@rU3a zJx&JQ9sJ-vlV9+VbXVn7iYVi>Ot`6&o-*i$aG}Ps&8{3sJ>Dv0--K+$Kw=CwVTNC7 zpx!WBJ~cxC#e^Wnnz;5Y80SBsZ_0Agv)pA_&18`(y*TwIxNH=OSU zWB1$GXT4OJPkC(3MuOSGNfqz>&6#AKx*puKfXLNA+j38tTA3o{1_JIIbmXo$yvLQcdD+C26lh@ zl>E2*@@7k4W+MsaukaqVa{a=h7niCdQS3sPW5D4U@r>8iX>L+vKcr*o(I9+Y~Akduy zq<)Wa>kIx-9}46OcdTyn{)G3Yuk&X_E>&p5yA*}WMV}U~cpzM+iNy=LyI%f8tb0_H zAuSX<^pb`bTrq}o=SL+St>Yj9kM?WH9dB~9I z+;GWY4|hAuszq~+cB^v9)bzJplggr^Q(L+;rXr< zBD|kNTW*+iJ(T(2!^p&Q4y2X;VINtG6LdKOIk>U4jAVJP070--kaO8l ze^~q6_>8@Ysc~&oi|b5k)zqumI5y6I?lD*b!L7JS4O!|p<7mU-vNZ7nfTJ0tBn~`# z+;$b}QLdq}{j=w-t7MaMG(Ej^Qy5T`_xT8yf)I7mI;_+YQ0+nZ1Gr2d@hC7O?UDZ}g<3{}imaz~4~I@x!%LUI`#yN{#$w zeY$3vz(WvVeNo;E?bpX_XQ2y`U5#E+zv=MH7N5kIJ0Rnk%FsDN5Mt8u+2iCRAv(F3dK0CM$3fEd)TTA!kSWg8q z!TY*Pi6IuPKBZ}HE-N_2A>n@=kLqXs8j7_JG#brpTXfS?*Qln~ZAGi~=@9>s>cLJw z(QHa%^Ei?Y(W{rfmBR{BzY`rDt6 zbG4=kKi;eGHU-bL!*-p{o7xV>LV$VzJ&s7&uU)#x@6Z>OC^9t~T<3^xq~>7b#rYt* z9yfU>*g@e!p83NVv6h3bq+ap9>mUOSA#2md8lJjQ#$I+e=f&`@c1gB(oiAy=B@Se|i}KGAFm5CYvs$ zHev3)b!qpaG-G2^5U5P>9*|wCKO#)mv$#8V^k+T{ z#xiiL2Fv>x*gw|%TCcAw7ru^g+F>y&fdk6N2RFaqea#u< zm!UzH!F>fU%#Hx}ZZrqhRP8PQv5xBv4Pg5~i9*eWG3TJ<%GS`+z*eCACUjrpBYpUK z!%uTIFiPgGmD$|0LK_Rrc3-D5p6<6J5?(1-M>sAxTAX)xSY;RzHe(qjS9E_WacdE< z%eES74_$$NK{p2q0Hlf!-Q61glYR;&HXfZDJV68rf4Vc^Xn?IkV7)zH`{kHZ;=Df- z;zdmD=wNIZscHxc!|KCdH5->jF%eu!RqhFjE}meWwib(6F%6S2Z%}n z&;0%UW${>mYf<@9-w9Q(V;S^SyI6nw7O4~qehW}B?o2nhrks{myyP>4HE;$ycdR`g zI=rTh*^WptbXZQV1JXt7qzb2J${!?$r5upr0Dk}m@ppSjOK*p-qLd==P*;#vPQs8_ zXQn6sjeH6CNxDw#b0+%qD#gHxjoT)5hAeXS3daDrART{kioE0Wx+HJv%cGBOvc|5@ zaU4iFd{L0`X!O&!V zT2SJ^0qi2cm@xDMsXxI6EHQD7%Lbb6W@qy#b&co@6$>gMc3ToTru}4(H+|&YPkwZOfS7J!)ap>-je+3qp63>~Rz zVtQTPGq?2YJjx`TzGP0Wom%je2IX$btewd#Vjd8$Tgtx6E7&&*;V_Y-*N4Q0$7)e=YPz9UEx`X2Sm^kc`{rEB z9aK;Dd{VX@T;rXyl&+f$8UKLgy$As%p)P=p9fI)hv+wCHCFYehpMU*S(erJ_renSzV`JDGuzbcpkY+pEAs%!NJ+!)Z8+iasqVT9}V-`#<88(^e<%p~>Zp#9kfuUP}7Ict|Z)B=w{uL#tR-@4rtQ4$=6I+@1>J6iF3OzOn}ij zbNJI{74T^Tcn=Q+ptf~GjINMTF}(vYh+$DxhOIwbv-i5RO9A8h6Z{0apY>!+qN)WE z*`S9y|mcP|VQz~XMsjRn0TQ(*A5na6u!+nbor8*XO{;q>W)kv_n8pJWeDIH5a+yQ zl@JHny>7p+rkL|=oFQ9DMHR3>k=@<^>R=_HyV7^3;^z+$BcE?J@txtR>KabMB7lOO z6QQ#hWF{AKwG<+kta+rkI>r`b6H&2Mr^an&!6r}!+!vDFOue&-bKs-|I+c&F$hLWn zF+@+=h6bcQ0`Rj55fMs?Bj`q?vkL$jyaa*z4USszLqh#d4SIy5l9rV8%+hYt=YGLI z!0(G#zMZlK3;h*i{>!?e$%;$P?yeF3fIO?ihpDl9TPgYDfEE;?Vc7$~0Z)2b0kma&fuJ>Snu+)G03fTk67--Qms#nbW!L`{R|JhC}(U(8X|5 zjAZHgpSTq3##xq_MSxj<@G(a3HYmLP1q^UCY~egXb}by-Djsm^Z#OCTz|ndk6K3Pq zpXMV3QM=_-*VeB3v?AM*3Tu<|oQnVj3iRp%kA`^XbM2|F?2kL4=MWT)b$d`-eg_% z_~b!O?k_}jWg*xKqCQHZDWZkTj~^gG+6x94T+Yh{FzRO0Y^}5-ZPtU+G)eFWfFYFY zEOVSGV2;ILoL%zr>m;P`qhn)s4C3QASU@AKl0$_Uu{yDkRqe(P^FZxX@{Bjh!N`*+ zQvB1r`DchAbo}CF%Y3<*&>VTMufqe7JHUBjT5uSyKovm1$hcVPO{7v&@Qd;gJ%HEy zcUnTScAd2gz{N~+WCn@oX++iHK3)@({i`X&XwYY$zjimxyB9-oe|tiIRub}dr@iX2F| zyOFv6%yY4eM(LlYC?Jf2;yIuN5mNXs6)jjL6E1+7Yy|Kpl``BZcufu^P`y0erM2t2 zJxxxuVui?6Rzav0WOK?vGOeEDDG+j&wx_k=ez^SDLg^P0UWjfuMGZ?`+rK?>P)H*V zQrFf3NVu)Leu@f1g)|^<0;aCdFRtjPd40#MAwHAtryXW6z5I%Wlq1Trr^!Vu?rKp; zx_^3^0;MR=*%GQtn|tLtsJ@`Rkbt?c0t%l5yq*!s>6H>}E;Y-%7ZnK}=$~z_fYph9 zG#LU;zkn;YBn!h0SlaO9-QMHaSzi7ny)-{(JU?qXyUeTHIJiz}_6) z4?9emY^sFao2;uNZfp--PzM0shSo`DRzlB7D>H?cUb$`t1vx3aR|z_>XI;|z(A<^j zrf?<`9N=1}xvU!7+vLo){9a6%$1JA1o84Jl3gU9GpB@ej5P%(|Vwzsu| zUo6ZotzJhl3&ah25gmC>Cb;cnXNc(wH;10Topk{0XO)%-w-W*;1qgMkauPU<&N=Bo z7LitzOY+9H!yKmImh_;J7stoPgmLjW5imNrru=7IUIEZu?4R?V#eKIOTZr0_|1=%oKQ2jqL z!A4!*fuN&f$9NEF%}HIaO-t5?GA-~cnTr|~6;bI?hQn|g318=hj-VzQP(A;o1ORUo zA5~twdhdq0Ro50G(NamtdaOx&%>s@a<5b{U<3vn6Fc5tqshfq-On2h&1Yngz8+SmU zx=)DOHv(R1cmj(4RVH|SV?(ANa)vXn#aQ=l7KcBJ*eEqB*5Mn?jjW|6G$_AFjUC1h zq<$=7C@HYyo-tEp0=>{5Rl1=K=Fhx1R79ix(V#~zsmAClPh2{}my|5)SLt%zS5nPq z<&(2C<{T?guc)8->>P*kA+7{***0kdrAE3bh&DL}@# z3mwV_AaG=E^?%xpV|rQ6HYbuZDG;+*uRJq7{d^uNLdy7Ii;U+VO8tm+Mai8J3o7s2 z6-VDop$9p61El+VaaYFx<{)8C(&|~`oO3;HY+To>ss&q%lbpYZY_OR5!JqE9Dd0K` z1fL^&bMHD&Z)wwu78G#JUA#k{*uLCz$5_0&Xj9+gZV>_fb^NzmaMM? zSi(|MM*1X?s=mMdI(=y6#}emuoYNtIl~H8u4|?{}UMcb&6?Y zu1?INahXL`%pwqh_A~{);1SX3Yu`KGK>@YB{cr;ttP>M04d^>S$b_^==VbzG_{6-) zo(gQ^LYMYZ&2rLN8imzyO=DPvbe#zy@r2OTxR8TE$yY%4;?oQz!dm_=C-GcI_lkHZV-K)?q zLamSclZP^4MWuk*Ts?m;haQ9i2Lwzn1gjJax3!4}0dW?ropQW>u$cV@vhBW*C~4V| zBxXk{FUA3^@deJC=AvU#VHpk})cVR2W z4Ho=Ab6sa+w%=E^ZhIu1B4XNf_;~CG<^)IhlEhY|o6&nFzw2L9w0C8~_~ZfMeHk^~ zSaLpmmieCsPoR^P2GarW^>Q@%JCJpwG8M+8(|u^0C*^~m^2whW+9DekNx&r4UOS)B z`6CV3!B<1cVwSDrHxLPZF+g#logYx5!a?Zra8@F247j|)<#3itE&n5>?DQhiT-E(Q zvo=C_w*!dv}}mtZiE0SMqSZB4w@Y9A#44ta-u4QY3_)wxq;wMOXlcrD4Cr}8N+ zeBg`Q(H^GAWqvxp$U>&WBf}?fkx8=Wx#INdXTfVpV-z`tiUE9r zlg-Jvt}R+YAziiM-2QC?K24cO*M|$o0P&n+LG~quZTPe2_T`0}k)}$=bIr&BA-rzr z_BY~;GyAPRN}!TA05)Jgm^~;Ryvq^?^wX^n{yh8iM>vM^(Vr2!NqMVkGx(Dk!DhUk z>xL%?!XQM+1zR6+`5u32VL3hxw#x;va=!`O8mqC)Jlj&fo>dP5Z*!3MRgtIR6{Fr@ zRJrBqqBW0h)VUa~Axy)6m`sTbvn`MY!CUn98)qUT=dWdJnclS|<-NwYnqR|PgxxZt zG0}N52YD-&`V4PQ-nt(dRmp%=unlt&?+Tl5Kay(iTbBeG2n&JHdqGm&tulicns1E@ zLjuNaNHjf0X%wAD+maLN-(*I`XzyY*s|1CHwtFCm>|H9r#up-X)wG<0HYumK%IC{7 z4mzUCH_x1z!Lx>_WRY?QSc_I3mpiOp;D6Xp(VZ1&4S_mX;|Iiv_auUve`OaW9c zF$3&QW`;=dU{fTA%u7}vl#?SrkmhV#YlFUQ*hnz>ZpsW{mldnN_Dn1Ye(EL;wYtPK zSax4KqIr0s*`tPZIEJ!YAjnx$_O6nH15ZlUiklZ0q!^9uXw(Y@1g2`zJC8D`B_f52 z{=g-fa7KX!oged4VV8^U^>$bzX58lYl2eYRZCNOO0UF20o$b=n)sx+6Ly_w?KV*+E zLEluLp+C3ai#vzd&3G!M840n>#mJV6{GAo%>+h)tO`Q$2 zA`_{xxiVuD^KEAIkVFZ{>jq@h_=8_ScG*CCFG0l}#{sbxnhGhotK?aBT0w8xfPNM( z>b3m2P4Ef1W43KH;OXT}-qh1l(sW>Oi1i9tec{?*F1eFyE;pQKiH=CNp<;U)Gv|}x zRfIt+>-RKZ&^uw)AV<2+_<>|vf%h53O*_X&e$34my?gLcaXd;18zt*#&yq`qW?oZ* z{`iW6%&2PMW{Ew7+P~o51m1H&=2OMm?PHlnqcDG8>nE?O6V1fdH+iOfgRA^CH4XhZ z#AKS&@u%tB^B2ft`Wl&%PNvo&4I0~x5Un&gc0k0=pH18q(Nc>~8g?oFnV~8SL_y-H z`w>U8RZZBN(M2jwm-U8ZotAf*n9nn~pRzv>HJ4+; zbWtM0o+os0gLK}w*&qO1a(CJ;&Y7qS+{gGacO5}q4(sB%+=5r!9nO*X*~l2}`n^0pJ@>#F3FrY|?Idw`vtDEPQ zrpcPbhBbAaxWdIbI!fHhys*_X$NurCCjTNNHpTFuShB^o2&FTv&@eQ08})jK)qzSR z%|!VC7|r9|p&-%9oGNuXJmVLcYwe$77RR@AY;h7)bAH| zzb?eVs4QVD<81omcXvz+!=6QP8SJA;la!z{?w@u9mgcsD|Av3hif$4VeD8d;EL|HaE=vX!trRc&8#k6$ zq@E+0%En~msANiJX`^MR6sr7GZa^Tf{&l@Hx}h1J4ufK!q_by_`-r0agotjZovs?T3vAXce|1c-NZ{xh8{sUPeBDTU(>>Bn`v9HTLfB>xNjdb87wdjF<~^m%MwKWwg6#&^YK>00U-ylmRQ|p}cUi zyHLhpPKB$5!8{U04=gq)TL>N-17!ZChBUUHo4x%Q?*@xOj&1aba5Vy zP}!uzEcuOW#xl$hRBwDZxTzxSBWnAsLYHAJC@f1-%$kV5Y%i zTIgLDkOpqYet>3NOI+aEwbZ-8;In&uYz44j(UpDlK;0d@en(Qv$t#t=6jv<6s1K%a zA<9XGDcZWh?bqL_RE=sT{U9y`eH(t_j|xeA|J30jgKauX6%xU`I7jqaoM$bXYy^s2 zZlqeQX%NGJ>0GkfjkquBrvMG3{e}t-jP64%vBajaETp)l`DP8}wUCvXqBDf41);UL zP@q&rw~Es-GVrY0*>`vjgu|M}1JdEH!{~Od_Kc+s{N_=hxt@cv=!W^TiV4A0y5+KZ zj$LeBLDPajC+CBxJX;N-Q{%$FC#9@q-h)%$=jqUEjc{bZ;rc*jyWw4bUE9%m;r-iQ zg#>s)d$vBi#U@$3Y8I7ow!c9GiFwi7>Q{_~ntPfkt_R-M$q%}#@Yh5w&E&_5kKW>T zQogU}u2ZVQx`H>Lo%QqKmYO!CR@H5QZOyT?L24HZf>qWn4~CxZx!TF5Hm`Tfj#)-T zS29mdh2)`le9p-H_+<3$jq5%SXWK-;ML{)dEf?3Ma*f2XKYrLQze(Xtm7CphvL(F0 zLu8h1qv>O%7mK>vT&GMNf+m;FXc=6c$`0h`PBxGi?OMAASy+mX4?6yW(MM(ndXLWi z?{X^tJrhy9F=?@*gfMt)(U2Y)z2DEXeoGNEeR1z{}=N|XR^cqBW(3eJJb2^1AZXPouCk}O)7MZyf?d$O0r6Y|T zNi{VRWApQK|BtP=j*F^m`$q>yKtaF&5fH(f8);BFqzq8HyA*~RdKi!{6;whch6X_z z2BbSw!l83$kQizR89L7zpXYtg`Tag;{iOrU-h1s;*L8hEmE5{ZExt;jO;xC0E~IjX z>8x;DzGj}Lr^4Kb@Mj=Z5n6#!Sc~bg>g_^@e>*EfSugptuVeUIg_m@G^onOKd7Fw& z*ZicuYRg|&`z=k}pWEj&+)&#Qp(X9f&RqjxRbt)i`4zwR9+#3#nr=TiUP5FrzDG)c z2PpO-ACLXD!FB6=L%+(V?nI%VB&n3IrOiDyTfq_&JhdA;5WM}#kIR@$z$jDPJX(x& ziOrdTFc><}D^_&!Ejl|R-FL74$e^wsM7oKIEp&s;MGPoKN})O)Y3V09)(6S(zGc9x zf%&NGL{s*NoIZ^eEl_$TL*;K@Y)2m>)O%Y_xB9J&tKizPP}b67>DrM0ANFJItT@RIx3Syb zsQl}fv<|bB?hRk+AY1lgq=|h@J|Q5p0n0k$HPq4Ah|`*Ae9)E|%Z}aV=2q5+R*45y8sAY3@+upgRXQF5F`0EPb-#^vfv`y( zzrR-vBZJJzQq8c!IQHk|@(PxI*1%M;2JY8fiAt??xZe9slfqVNx25LS6@A>|3V7o# z*kY55wC)@qV;y_1iI5M+@D_P(q}`Y~4w7&EB1mH1 z-?eme|Ll*t%H3n3?l8RN+uJ597G1HmaHr!9W^#Oehdoe0u<$t?KOmprw$a7mmt793 z^DbON>Vt!C_?3F33tDZxzzN16qDWP|lbTwW?n=g^(!7(SymB%8@(#I2nrEQ$sgcX{{iGe1M^kjM3V`_r=R~ zyiA4!VO0)AU z;b9WR=lStlmoTw^8m&$LsT-*QAD79L6uC67Q&-1cwnTd!ZT2JV=1E<+UkH@@j)Tlw zqCW`I*R^lphHNdD=yf7xwg##XxBOZ?pJ7j*94EBuv#-k~<9(eT?$x`lr)7H|qh4-k zJA%Un+G`eV^K$0wEEN6W#2UC)c7VRs+xSI9jGi}L+ITLyF5-jw=HT(f_}H?Xof&Rmg(n>P;HRM8$g97s({TG zKnpv=;CE_+_pO~lexQ!$#alCH{0{~{Q4tqCyr|^Xz}PB-ZoB&-Zj4^Lhu>(Xe)RY! zax>u2)5CEa>^+9p;NaGJN>zEt9EEQTl3`J0R z=Y}_E=3Pq;Mu40UvilU&vkjbM|EB1@NLK%}QFqZ@jI)uK!sS z<2q=T-~Zb`ySP7b!T56_BVjn@rDP*iE_O`IV_y~2CAvt`?M<|^UtXBIYtELVMLqN* z*LZj0w5Xv@Kd%ILBw#Qyidd(6RaH?jwm5hjAgSbi3SgZuZ^iFq(V7w0nOgd<*I}0M z0`;d|<%ai;#l6*IG^3P{xu%w$L7So=eRB97(L7D$BEPG7*4$S=kkN~&bpDD^pkK%I%dY09f^{=V48l9xKaA>!Wm}7%S(q&1 zdq52H)De*HMbbNd--YNHdMJ4f1jsu(3n02l(kb3kz0DaAY2YqDNmlZwH=BNFj->dh zp8C*^iC8Z8RnDylj`V5^uOA*IS={-jDjO z7CxhNPcOxM0&9HRoi+@%6n{fZM+@8yC9aE91ukYkhmvX^vCLDn!&?w+7jbY`PV!|NPhk z!m*fj0$so)sPqnRsZNazXPF|pLOOFQ5~CH{R5r6Bjv3MhrA5EAKan}S@Q0Oj!gZgG z@rsoa*k>aG6q7eFsY_&#Knl(K4ok0YemdOirHkd8VWCMOU_he*=j4#5nkK7TM(9-VpN^;62=jEGF=;p6f#%b^#G zOxir#jqgsB{!O~{CinT!=K>=i?B+B!2=(4rCjSoCrG0^@Y{*m-sPjo62I4KrwZ3&W zul2v-`8+LpXR~Z&Ce1dXJeTAhyM9W;!ye0~b=Yu41Q92ep9yLfKzU>=vrNbP0YYh% zB>jC{q1uAGdgT1x@p!!hcI+I^keep`(E84)?-9s0VKQ=9w1d1GVHqaTxs>`JN#Sn` zYl1iD+oP6Z917U#B+Kd~mWpu8K`Pl*px~!0sGOX)P=7UGZ$dVVe!-l6DzPtC zRQ>+KqcD6V*`J*;omuACQ+=W5es5EJgUa`$;b*)F>yJMa1`>VIVk=Tkiou6*1W@_M8?FBk_cYauo6?#^1L9NT+Ys>o# zLtzMF-PD()Do%L~k1vmyZEI(0`ekau5h=2F;?^X>;#{U}UMXvs)ReZTn2$4Dp}Hfw z4N0w}*)@X%D)eEoDCy$Na*IPrkXsH`OOtV=@!w8KW;s7-x3;zIhfd+%N79G|NmH4KL=@%z!vbZk*)#OR2w0ewCi8BL1y z#uZii8fAJ~?GLg}hi<~lI{&>nh{~WHr*ZUk>Ds9mXb8xE3*JYIo~!M7-sWqNx?gPY zo17q(2E?K-$ICfs{^N~rS^Ywny)NNMRNjJeWs*CKhvm4C-^_`RFD?Pf`79zQ)eD!< zu{IpDN@NL07eiA4tLy3XUIo^ytjZjK=w7c0Lq7Hr*%m!goAsAbYlmk3hcE;Y4+Ty- zYSsL&5;8-o#K~=srgjpQk)1Z<_@FHycrd0lY%gr3eIqA_JIk8l? z`LX(YBOJm?jSZbrRU=fv$peFXWY2vO`%|7a=f&ZV)zza68@wyH;;5TxZC{h(TsM5C zkXY4f6LJg5tM&NO&i66~1Agul^QGd8rBfp;&&ZdIk{(WJPU(bW%wz2a z5#3YUwynbM|BcqaiuqXh&)Lp+qIsmwPID_i2XSt{3cY&Nv4gkw;}-G_Ug) zXhFu%Bd-XV=lKwA%&X=8T1X$f`t@cq^G zlzAMk_uuaKA{Q53g&&QWglN3z%%lULh0@5(%uG?lbYY~ZCWFsMaCmxmP%kzrdZKqk zFxrqyCEGOfeF)<>OCc&J@bYk?Kq7aTtk5Z4N4_@u3RiBV^0B+0-V6W}5*qg#dZ|AG zlHCG)Ru8q9)b_=3A-@2PIh&DvRfx^BI2wl+Q#BNKCe~S)Kxf zkqf&_x7Omk|N1VRI{lesn3m|{#dWmFx0~(|db*gp0k2cuoQ3*vyr2S$dLsI1TYZUZ zmz0LuXvoG(sC#VYs+`aN%d=`r-u`C@)NBz5N)g`=8450|1L$-`L&RwlLtc#EpH5#R0@r+hpjfmh!i}jO^@O?}-3gfd+i z3&4YY@wX(aj7Yk>X<=M-zU8;lF8^m$1dc|pazE7vX#UE{e!mLU+Y)YH?NI9Q>`1(( z@TkY}sbltejcXa}4ClJUMJkC;-#Pi9OiV?4~xw@w#r zelhDeEX-hQ2^6KVe*QcCifo(3tR_{1toEZrY_M9>duH;!2D7)3HJ~5dy9zc7N;Y#I z`90pbb!1k(lAYuL)uf_*qUv=a@SiLpA_UG}k!j=$Gvv{VoJxdi47j~S^V_#Ogzn`x2AHD zp{d<&qKN+eqQHzvi6Wv738+NNsO6FPOA|ZkjV-HltI<5^q*=-7NwpVju-eo}mDZuo z`m>_KB+QKLIRACZ^g!8n9bVSncG6Ks_ipUc4?h&`yjas=gkvR+HM}OBea7<8Wq>3_>OR3dr%+Yeg?u`L z)r3Jn7S^vzwn<&Gzmej&w?3h0VV3RPnFwkvrHepEN@!7wq0U%FRo+|3t}PPp3UIOY z+DS!kHC&Dr>CJ4~)Kb?A(Sg1_Uc)p$e_U|ZH`TGds(ozUtx8kZ|r(AHOm2u;!Lz(aPLiMROf;zvu7}KU zP^2T7&OI_Fmj9fPRM^_boE2kH0@20C@PO4|@2L^0oAuyGQPrEZ?Wt?Na#*1Glr+7< zN(eVi;-EDpL;2Wt;Nzt?W z5D=)TO!c}o^`4OHzvyMxB-{xhIk(cZ+XfKt`mRH>BvZ#Wtwp0eRN*0zy42qR(4u8T ze|Tq(2tsl1(X`hRGaxFm%W||1oN0!{jPKWec1^*;-J~B)4t?Pq_axtMIl9v)SHN_F z%$jczbe|H4M`GdI`f^-bSa_ezl&k;J<~l62 z5YD$!ZpvQrL?MQ!gDomU+d^tCjg^9Q6wR#xfmu*VSXITILt{_%i?M6{K`FR9N1eZs zeOcI?c3lM-?vEpg(4rPJ^bvFYureeyDxb=IHZMF^aG6uJ!K$0)wzvhZC&l=W{7sNn z#Gwm}eS~cHi0jd-OfKGrhK6XFzKm1!-nZ4$FSGi`Ua>xPr{#Mshfmf+PER7_Ps?Wp zlL?$k5ABSiWsX5KyeHTogBljtsfTD#9#wiOf4vqD5M$sWHD(|7z=+XRVJ4IU#6eb{eBgOexoFOVGTe=XtCq{0n(A=eJRfS#M(fn zh)%LJwEs*Wusq@$GqCA$CL|@8+T!ZD_Zc!xjLi|NTyvZssn5{fG&>J9d$Zby;kCOX z#%1y~X=Lsq8oq!aj1w-TG!FU^i(RuZ(4|+Mh0wnEj*7cL(7{n)V*#Q~PE+TmLGH<< z?714b>>&n28B3}FQ#8>(xIcW!W%bhq{!?am)>^kkrH}y?>yb$jUmhC(B#q&6&Ib6V zPkyT^gIXq)CTqS}O8qZ76jg$Xja^k2n`~&imY6z_u(cQRHOt2ev3jdZvv(8=A~=s( z*zNC2nrG2NE~)_4%bA0D(CL7K7D5JjPiNz|sdT%978BV#>a=68@fE6CTaI!n1(jN( zJ4IJXxdE)-sFKac84gq*V|aWf9VT8`Gt4~Wj@@@=I#TNp>nm90hIP}a6eKF`56gWk zol8tBmRF(TJZMVWX(Z|dkU{K!ovS8q1-q3lLf+3Mp5=NO$w=PHe_~>X$-|PB6NR{ zb13I=$R&!fADjh6y_rg#l&-2{CXZ`;XD*|k=Ui~{Q$I|KMdUQqZf~_zBMj`4qPX+-5 z*9IVGA8wcm-%%m?*B*Hv0?D$VHh;*is(16*BATL6gE3&Feq4CTc&y$i?%oVUgg$=H`P}yF5_tqFBjN9?oLaVm}~uy-qqH}%5Ttg zv5N=_4j8RPK;)ve!6^;J#J8N!G2E57wwY15Yb8LE8$?2N^{3%ciCMXpqDN6_x_qUA z;{Z7%o;Al_+5nS!Kc)hJ%v?Kj)~6dL(%pwU5_yc#^3fX`PC{cl5}JT3VSmw62Zk?G z8PxtErYd6LBmof){m8xhq=ZKb0PcnFlHwA7sIXNJ=z_8Jwt(U-d}@pDJuWfrp;ze( z@9X7CiXM(te{q=r5BATXi!_IX%!?XfD8TDcoW$`OzGQ0o=4-UVodCjf+aqHY+~hWE z>`;O7G02xOW?V~_EbX=19uY_XX6no&0noI)SBMUfRr;VYM%$SaoAcQa5ql4A=G9=; z$xMpNN87$8PUD7xcS5*)lRgVZc08odU8|8qpD6^0i{6Ix5fN;{!91qyU`0CTfD`Aw z2$nSxAQKTI^7qFD=gQVes{sXc7HN zUl6fHHv)o${l%PKz+4HIaxJXs9QDMHwrtx%`X;rK#GFUek6}1-{s=%VvL#6zEG#^1 zZiYn6D(TpdO!7r#r&mp@rbrIEyStCpZ0#=7IEy(edVtU0I(P8_9O*})_GBQsTYi;! z3m#d9OUe|^vg+1NG*KtUC~iJr%2RLe;&$?Icrc)tR7Ltll|ZsIapd*aYFW#TxH;Bm z083i}7!FMFVwl9?-Rx12xtZ{GJh=HZVs^(nR;0K}!KHirlj+3Q(nVokXdrHQY%EXw zA%}Rc-Puk26>^BJ8AWwW!&IGTvAo@!bvNA*clEH(H0PLG&K;Dxw&I>pPGT`z9oerK zJ`fat1Km{&bhz!yC;Z+mc0EAp%yK}|e{sS60WLgFokw#LT;7PZYIhn8D`S}=Gw8_tm~FfY%K*=2z8@|1OBTxD5Vi=!GEcZX7 zn#ov32zqWz)`C56OtQ2NaLE7}83N(su!*cW`(cEG^ko2Pbq76Ep_iS>NPPgopl30$ zso0{jpGaI}6X#149RomaVg>e~jW{&4N?kp$b*!rg@o}OYv9J##HVYz9Y z2Lo*{tb1lsG}ZB7BR3iN~heS1IQ{Epnb-F6XZU^S72GND$ZE_sMk3Elv^O z?r~|4Qsb}2M}>z2MD*G~@^b43dhn7i$B;@3idt+ODkRmMpA>p6!E!u3#Rp6GW+5kYR`SEQ&3BTW#Ei)rPWIQl;lWa zNlY;iEuRdS#)%-^lwfba6NxukmrJ|G*hnG=SI*Mf>+E80XHR+{Mg)Oh(kNMpQ_s9+ zQms{%PSHoytDGe4w$b#_+2(V!e0dzIA|m3Z=pjNjWb>wG5dzWA+F)-lLya|?L>P}0 zo2wIb!-6g#{M5l6RG*!lm6oO>YLnRHid(nsA|^kX>e7MZ+?_EuNZ|bWBV{1Z`t09Q z$8kWPlffhk0Ps2)SZxtpl==H#uN(F$(DV&o0xPLrgn|p2?Re5@(1kXJxJ)-Ix_V-O zuD2;a-yeWH8v_97KuGspy*$B)SvRg(qY?}Gr)B9cNRB#X8H7Upjn6HYhD~I;kye|_ zPKA%@bg$ZKe7Fu?P1LDiXG|%_&J;tkr5d>Pt4a~G!l*g zVzxjgE+v4rx-|H)iaY>Cq{tmr_n$Gg5;=Hpgf_|`T3A( zAo^{Pk&G&oVbP6wET>zLNUjE~$r96F$_&Sun$~^&_fe3s$+_29guyLKk(t0-QPd?c) zMOUndK;^Y$%xG4s5bmrkknuJ6+gtB{MKewT=>Kgev{xD6ec%l>0s>`9o$K>SYC)>P zknl22y^PRFKfM3#z05Ih6d8n5;V<62@o_1l>lmQuQGkB+K0OfrU%pSaVY${#VP3h- zb1a5@`7c%KLCVSSr-szd(Orptolw9Io`gWIVrOU5rIPAQ#sP$W*Yf+n?hweFL8;X{ z$BS5AP+NO>bBHB9O(sFG>D7)(E7YB8jutG*4W3qDBG`eq&Z%gi?*UL9ff-!)HBo!u z43VUOT?Kc_mava)*g@-Gv;HIGmke6xGliPlQ~gT7Os3If7mWuImA;9k>D=ZVlt%Tr5L1TDN8o(?B4T#+8=Fr+fNTT_ zsD3TcbWMq|kVrxR5_1;`zRibC9L$nRhXnbR;J*uNS&lDwxXH*!>Is+L;yY5M1sRXh zVENn-NbJqH2R4nw?qP%-3YVtGF4FWZ2|OT$x`UFk@A&ev?Ov%jzC+DY4k9PAZ19fA z63^EhF)_3S>qMdmxGiZ-lA}$JMY3gZV&-2DrDn#61{YLC;?WN*K*a%wB7WXE{k)Tb z@LT)DP7cv|Q~JdSoD!K@K9LqRS_Dovd3Bx4^-n@f({8}70RH^T^MLY5%&5q)eA*2% za3G5v!eVU#xbLZZ_j{GRPGJR|q6w}fF}XW(DU#RL@esNLmbv)Tre9Qj73c!Smb~EK zqt8y=tw8^4GuvLd1j+phszGatj~>+Uz|<4U5M6d>WRTq4u`-(pu>QNOk{b5?%7mPb zBcFrdwua>Bi{D@=IG~B^u@E|=n5C@AV-J#ncEyVyZ>jcd1PLsXU>N2r1x0{O;G;H8 zN3dFB3B+%|DcN#*OxjG0dCVLLkxAwL)FB5wb`gpoUAR001R39Ju~k3)aC58%7d=J1 zaX(j*qnyTmrxAbOe1=ogoCe=gAskrW^Qb9+IA<=c>J+ArK1DT>BZU4|Dd=?Wev=I# zlB9aHZD%FF1~i?Y6aJiI<7JO#_EhYVZvyh6X+%|%i16_0GJbid&q0(#`App`1s94g zx&sxm()3;RVLDV%igeyE9V2bu((62GNTAUrw51xLZl>phVO8g`E?A*(v)on18u{ip znHO+#fbfJJ2<-Ewr_Fq(yC3Wed>X-}j5iF%=x`%{f*-O|_!3KGWiMMPm~yf21xv`O zZ{Pn5e?Qgs+ylZ=#NyeAJ8LTyBa!b${JM8fUPkWEmwRd%j>dZ`9SY(8YI{DCk5l?Z z$BBJU295D!ryLi*ms$G=Dkcn8be*LCao}jcSD$+WXAPj(a$nYK+p1eB7L=kYy81GG zF-GtNX;?4(1#wN^g=7O!mV7%Gmp*XPk~lv9%9wQUw@~f?SUqJv$0Uf^l>XqVVMq6g zFVdlG&Y5dS?u9XybrE%6PyOko2!e0y9C*FWChKJ8_6ML#9t@Y(eg`M1lf7TU-gtNX zy5z?C{D!9o5UM?X2k<@IE_FME6(DH1NI;cNq}Kzr%UMvDUp6*BsW=?>YYGQ?SWv5} zy#yAj*Ji~b4yMK0cY7Uf3lj|^>U!UGOgK!H%We{M6ECpFa`T86-;}%8guu2hN zDM!Vqn$0X5(C!opM8^J0~#)9L?amo!qLeVHMiLW!w!k-l$ zg1DEXI?46Q2=RnN@X7N2~;vV;w0=;o~k3qz*$@-`p4%tf*hNcx=9zl5MQSK+WR`*+%^CAZJBajKuglv!lGGCF;`)>Fuh){ zGt&;@u%><7JrGOiTHjZ33Xxc+Iccd7T+8r#ZI&Zsxkp>JdUOaRjAR6G9yVn`uYB%t zsx#nFP`Q5En09Wlh?>v}_OI%yT{@2Etx|gn|6`!>&$cV@q=;N%SRPgO8eUF$ulXd|fX0-_^rofH?8++afO6N4)~)gva}nJf(~Dr z>)V=tIh7xk!8g}&xb58qmLmTG&2`LkqUXxnJ1ZZ?9YzoCAcS-3;( zi-h1glSIn*!&VFhu~M8eNxyh#pRFAc`A0WG1#!`;hC~1snR%>3k6tG)XMVBKFkNC3 z5LnApL26`6qaRIFk>RL)mtS)|0oi4_r-vwh^$Kz{D<^rNAig&ysMf9TWl`2R!c@#)VE zW;PFsh`qZ!vf?v!{$?H}TmNyqSluGWI@?SqK}M*bFz_eItke zwYsqWaboDL|6Y~>D5xPq=`?tr?TZ~~eXIaVF20zUiO6o|v&?EzFfyIc#hzKq(oX?Va`^lg%a*le&1h>=klArEYfpx!sjz zmS&z1b~Y4yyevkWIjE>**yHzPG;RFa#`+Y#>;=75T;=oQ}`~gFMV9!?i1GeLO zi2p?OzF~rM?aeeeKmJ()B?`+g@LO>OpI@6qQkC$on_ zspWpvyl18>D)6esCz+c`42H8z^9vCDh*e(~qm8dy19EZm7Z8accz!nkKXOuKu}G8s zA?i06RC$2_h?zg`{M+80TnF9V5mZtxBgn?~>nW%N)hYF((5t)$1{)UUpt4kYbm|j1 zo+f0io-)Mibt{&;X?x9IXlIVpx?MeIJP_zmbM;})MTV!6w$v!5C%O`&d|K24Fl4(k zr;`i<;`ca^G{!zp~=3=iPa+;;Tw!ndTRC|&B0%_pQ-iPY|7uIPrD>7a+&%;$kJRkPy-3OGGMwJ{%g_5N8T8yXaGs%t zhb@G4zkuzjfU;w{s@}flDc}bJ?-i*3`s3#pIu?(UxfF-ts5{EX!8Y~np2fN+Q?tJ^ zfGJF=xv-gr%!^2`e_pXc>Am&l zx=aad$`(JCP|ce_oro+k;k;3d{d&02f&|$NwTPJ=Z(aLM%sPjZ4_a`Zqfy41-*-l( zZ12Xq`mx?>KrgbHsPYwHeswKbOmz3g!3ws`q0%@&Syw5hlXSWGp@ftFQJ=vuH*a}F zK}c;up)31RV)k_r5%&Bp(}^?cy5zYRQZo}%J*px7?x^ZPTX(63IQQ7zJs`T_1%<51 zCiM)}1u236U(QQXO6mqV&7H0q-qBcTn@?aX@!x+%J_y8f`6L#Wf~Wg$b$(nQ_wTbV z+SaUE01g_C8t691H_H~MM3MU*JEU^W%9(eA(3*qk%We+++2o!;JyA}rStI~O;NC<4 zV-PjiQck3g{2~4Ly{@|gSYXGnZYguR74OJcwOWbsqpqN;wRTL*p7Xb74Cgiw4%5ef z4jZqma`NtcNXQf`qgpI??$dgwdHj{r+i6O@6P?m=B_V6#@+H&*x<(uOT~TBXhWXT$rvPWy8QJQUBAM5vOY+@v=0sJLvKTwE zLV7|ekYI@w#kL%VGm@`UV8ryeIQIuFSs2vFmpuKl_-wpHhGcc6iDno7U)PP_OXeU- z6yc99nl+@lGZjM*D;iY3)t1w)wN(f)|Gsy_b;Z?vz+Zms73m2_WEv)+7u_P?ut8)% z?#Vy`OJB#8Mg!@J>zr~P?6Yr5&5S-j%PMTiR;7HbG-X<1{tlaSUAKzgTLu_t6f<{| zqz%II8Dpf*&!)e6?GP+QJL(pNgkQsHPmPH(X|7V~S`HfMtbw-!zwC{^$2Enz+K_W6j)|$6w?hN~dCe?-HJPNbi(E-4i2U3ix;q zQ8(t1Bp(_7-2KsX9+6U)iZXTm$NNkQ!YW(zNJvm{?kuS%K1YkI?rqNIBM_}?JPr7> z7+_=Hjf~K@*!quy2Mgq@@)XSkPTgKD%WYo^YatMK0bO<6?s!u;5{PMciMoB5*EV++ zV!kUsxxUZdO;bPXyZjbo^+eOuX{^3r^Vv9tz61F%s6>v7UoWK zzsKGS0UrO^lzj(X6@%IJxF_M-hS6rEbEr?)W1lCvsMmUCVQUF0LdsL>R4Y2t^Sxm? zEe#Ahxbg?VXeGz#McnBhaaldqa0)sLgIxkDobtt=TlI+~~$(o74}Q(bG=eH$@R9 zR2bWvOfIBI_t=~Fx&9AFk4dt=fSa;#=`Ag84o-cpqc@#{0rPBTpI`nPEw3NCkAB)8 z;Dhwl*J$+9KD{!_DUQ|?`M_;Ia2({>MPBbvGxC^5Ys4f0nG+2Ha*b=E_i2C_1qAc4 zxNE4_L#0<(BmW+ANAY>5av5w@GD~@E(6WqTGi`2bY%_%2 zfeYDoWdn;{R^4k8eLXQ$g{b0)bBUFJGca1GNn5O4jqKNLXrd-88v5MeN8z@>OXk4Z z`Q~z*h4#IZ|26tZY_3^ls#^F5_$F#F?B#aR$G|ToTw(?mHdyGnhPvkdJA~X?oHVys zNKsF>_iYiB*2rWJ-D%Yi>zxCJ30Mu`guxp4%?a2gWNC5T$WLFxJ$GoX1lrwk!c~v@ zhI55q0i-Sv8dnVMP1TPInial$8erO$N|v7;FDdk*Y^xJ1ynpwzaj@fYZ-5QdUDZ)y ztL{eSr{tt!G_qTFCDY9lcz5O|17jTst(_Qa$ zx0f&>xJ1>%j{n2QBWqwuB}8tq(72d?-FZ_7sp!bfBP^G#%}%GC0-_sA{AJ*u@h&D5 z2_(6qACaKqinvj6-zlV8v#|F|qZ)H|JCND}9(_+@uSVwIZ9J|Ks&qf?DB*f1!}eGT zWYmX0YLV8-TBcI`HGYVE)q?O$2&%zRoJTd?p={VFKI1YA&~A7u=6OeG2`z4=VLt6= znT=Z65N_47Y&zqcpN4dgb%KOg4me;+IoHRR?reOhhn$OtDuTp=n>p_avTG`fsGCN_ z#R5TT`$M1)>bd&LuWM}teoNYS{Dg>i&lL!zxu>dlnU7{@R2|VF=I_PJAx^Jre`TFW zpH00lc49aXmq+hgpRm#;)o=+^#}^s{2f(_nOc&D$0#1hOWRRhs<%WwbQEG`TasC(Na~BEJ57B(uv;wC_+oN0?=w9D+l&&BlE0_@k*2SzmMG!dVkFX8q7t z+w_3>K*<9#xaoIe%1jtn(U;Z!41s4+ z;QJDDPVk6h7rh2NNoPbMfr$x{Jj}eRqOlyke3_PF`8)>i&A6%NCILE}x#N!*^N@{8 zwH!fqpOMoN__h~{z`nSGwc zDW{JRZ;Eaw%qU_#1?Gemz!q#<+9!;wl0==CdKUu0aeo{`ude+c||7bSz4FRZzCd=fW~8)74rMT zQx^=`a}R#k%jK_Qaa4-n@chr_X9xRB*$xh#0_H)xN>K45saDfY6QU1QJAP@^hK5I6 zT_8%7L&)?6(0Q+P2DD&M}GH1lp;9}Q9I!v;Z7^P54cA-YU~55*=1+n?pmwDiGmB?)2?}T zWTSJY{EbSmUw<0&x4S8)YhWhPpr$FcisI%ODpXC2PNn-3C!&3|0bo=_<5@;U zH(>p$9$Si8Ytm+YjlPZg)8jFHv<_)p>RCvJ^?kpIh)MC3p#6K$l4xKC=* ziM<{#b^+F1Omrl{rYrH~=B3Bke=z>le<_kh*6D03R2I}gO~3u|bcw8?>;pO7oq3k? z(fYk{xCCm2RRZr0?1qyk8n(Vu0*{i^cfJl&HftkA*1)njdlE~F+CXiJ(5(SVwd2+D zMW6ZX@txb;FU$#-gSQpj-k`YjbzA4B)0HYh2n_;Rc-Cer7WENcWAyp~P&==XEqHoN zG}^X4mlYPas&t%)+m{h&Iw@s7;CbVp2IMHAkV`pe{G0%>q9R9PujAq~21AW$#{kT| z|MsMRMtirGyK9dEn4c1?FW(FF9xgM&vt&yi#~2z$j1awS47xtsZMB{ zjJM5O)mHc^NTc^IQ1NAhrga_k-^zcxSiKH%^*>Bv3oy#I{ zDnc+!O!7oEbgMe(@Ng;3*`ToY7RE?06RAHI=sdh52_5QhGo_XT3nBje_H7$2;9!^Gl0dxaG zXP)k}g;0XH`<9F$`4~mdu&U2IsvQV)$MCrdl;d^pVgk=Tph$GZoPxL8at?9C+Kk%s z0|0s+#RVNYrJ1$y2h(Jth zn~jP)LEXD~%)Z^zbPq%anq;j}RO(F|HC*Am7m69LyO~wD2HY26(49s2`{VH3&yNhZ z*ORn7>>B=K9>V?nue%Kdviqf~O6+$^%ma1X24Uh^HlxJCkUa-o^EuclB?I??=Mr!; zN%;6%kD<17g8xU+tdxQO>au7HZ#+L`&jW!9ujm`eRp^<5@emS0}6O14y_4&FtgThCtt?IClYUQhS!hw8MpNCFWD)YJk%uQwIZ~bop`}f5QmZ zW@E=_@4K`Me?IxG^u8Mr!`eKB%3waj?JA7KJ@5v)l9}-1@bP<7GXGYyxN4i3=$S-) z@iQnH=a{M7AfvC4<;_vL1TpFcH8|;nu2tKX=44=OeKoq4fxPnvGQA+gKtyRE$X@5i zzlv219Q1pIXKFAxnhC%M6($;X~T(3ry6Th%$4072e0EB z=1f&2an*sx3%1;Z083~QeB+tG8wI&(Mw38vZ$}T`JdREPiiVi%F!U|Wb##pNhF$RR zQyW4y9A}LCDNGLC=nkX5X|xqvbz9$j!0TinV~~m*FVg=KMgouuUaQ@=Fx&o zmwktP+F@AP5J5hks14SKwN#|=2o=qWj}EC$_;a!U&QF&BTpbRR4W;f7210Hlowqb2 z>rmcRDg|y%?B-W_1uD^tWhdUM(cdsoi15{?IEf&l?YM^gSr1M!kcxWc>dZkce0?gtllwt)w#w1>HF zS-qnux{D9s4Hzp3cDvm9@tyIVZV?9riPxwlX`WA+kMH@Z`~83k$0`QMpPF=&lZh!^ zeN$L~J@V~KoV(&>wIbJYzPcrfOx`Lb?9<{Fs`?tTD2me4kg#zMP6#%J=~TvvJA#a~ zoMvc##lQ6m;{~~b!H0yBaETi`!1?Czf-5ZgJ9RyBOi}hoGde1fgS1nL&RtOip)Dlt z>4OdLNugjqDY!B`<2Nz%?VNr&@*2Gc3+PWt#tZUD0g?@_Tt9$v#b~rIQLp4;D*vT zpr~$>uD=O}VO_`6felGQw7G!<+(eV%6(ozYr*4l&$8cV$jhS?ALvUS6*jXBX=$=x# zc&KNo5mpflEd(q9BlAFa$0_m?0_X4!Qcf|a<%4%5Q^&Vet-D!s5 zuFG-+F5u;;Zh(-G6>%CIqJy>4z2eE$LxvkOKk6*3nIM7Ww<*VSw1s5hH!ecLevx)) zX5~gUJ*mGXsj*jl*Nl_$CQ8s=6aE#N+u*j8a9krY7@|6T62qlGa|t#j(mUBiqrI!* z=~-3t`z@0azv_OkAvr|lbl}$b=m7<0at+U1@W_7 zNppgjh`%x($hA{Bp1WwszQT!%0D`*;w##WypEdX}7qLEyQHOVL6*n92f3x*e!m5}S@0 z>wSHYIv$n8{m&a^&I4NgsDG>ecz#cI+{o*U{-=Hh^?p*#Z~v0wjJz zZlOvcb9hVHTKw_ga^AOZ->R+Fx1nPqT zJ|Z(Efl?D7S(gz7q9M_0#Y{pLN+=3>k%Vl>ve_;=({q2{x%Zs!%=vNeIp62`1}EA{ z<}5ykxM}ujI(;^v>VR-xz~Jma{CQH z?>qG(=#nw;*ylap1GRz3!m*G9ZmE(>)0O3johAEYBi)=NL{^ZdDTaIc;_>;!h$cQX zcf`C>XZNt6JZUvg*gz)K(f-kuJ=AQCt5URpT6rd03+lQiDFD-Eo}=_9ELf6I=0ho& zwch_ZPwCSC)quQ|%qbpvK%3k%06+UMEaLG@f(We+8P3C}p?a&C12A7dID5kLN@ly-|A%jo z1owi_-AKJ*NX6coWHFoT8XFsr42Roy&dcw_%RlsKG@2bmaa?z6<~NXhQt{fg{5nh{ zn{Fqs8hmI}%FdD5V$-)xC4xxaCXFRs7IB8b+hNuJB+>8wgUbye9&-=Je{HeHfE<5y z9(6rS5y=y)3zwwx-bO3myPslOx_sdz22_VQKefCbO!?U6%azRt3j}e60cT!{Tb8@?ug%Ca0S0H-t?OD22W;3! z=+tLYb+dtR2FC%HsibJbJtIaJM0s_zfFgkap${81Vxcb8P)O=j-%MG>^V87RsK*0g zS_MW)hZM~h`j${E;%&9%7*_`x*`d&Avjg;2+|BS92c0l)(bZ6xnY(h+Ny-G+U&vyz z+FPN%W(OXU`utc_MiUSgh2$gR*+2DnA`I^1%taJ^oEtV1tF@bpSs*CY{l4^*aA%DXP_j5H46thCeb+IIOL{anKRF80oiCPMucXz#e{h` zNd?a=*`&0#!{vAwg`eKz=oy5br3bB9O^Sa+6EZ~-eEMxm{)yUMmp8T?0E;f^@r}Sk z9#4kjcPAYX5}j#yw>;+{nv2<{kFToSYYsG_J1!PnouOLtp2FZ}DXl}1SwfuxsKa2e zxnrmPc$#uBS)$*oq1j5HexzX;r<<1OEP{4IN$+589dy*dx69sCUx&u3i+O$qJkS+N zP{Y1fio1#7X+jR6q)+XkBj7J+ghx~x;YJ@*TUg@5#|va$=z6(bZeOBcsmE_=;Z$|% zh!$qSe2MtQ3+JjkQ-aX8++8#5Zv1c=Y3+zmS&wXARwh6W)+{a*we}6DLUQ5gM)ZiP zI=Vmi-2QrriSYtVG(`OfS6)EYzr-}gY08s4lnc}_=Mvn}?p z6>n$0U$!2;{}?*@6uzuwYXSI}6tVTFUKO*;I|Nrv^{v|hL?8B}R!PAxXPUM4fmT-}hBxSzDt_S!^g@Y-7 zjaH;qKev$`v)x81x+xcCh*1S?TVwY+jLJHfDp(hJ0smrh`>P&{&wK?-gU-QnC)ww$ m7FwN!|1Gz-SEfwR#Q4(WX*j`ekJIp6wTg?OMsv3vD*F$bakq2; literal 0 HcmV?d00001 diff --git a/src/components/MyPage/BrandView.tsx b/src/components/MyPage/BrandView.tsx index 7b5d93f..a877bf5 100644 --- a/src/components/MyPage/BrandView.tsx +++ b/src/components/MyPage/BrandView.tsx @@ -2,7 +2,9 @@ import { styled } from 'styled-components'; import { ReactComponent as ArrowRight } from '@/assets/icons/arrowRight.svg'; import { ReactComponent as BrandLogoImage } from '@/assets/logos/brandLogo.svg'; -import ExampleComponent2 from '@/components/MyPage/Card2'; +import Card from '@/components/MyPage/Card'; +import { PlainChip } from '@/components/common/Chip/PlainChip'; + export const BrandView = () => { return ( @@ -22,11 +24,47 @@ export const BrandView = () => { - - - + + + 브랜드 관리 + + + + + + Ai 추천 + + + + + + + + + + + + 준비 + + + + + + 진행 + + + + + + + + + 완료 + + + + - ); }; @@ -92,7 +130,7 @@ const RightIcon = styled.div` const ContentContainer = styled.div` align-self: stretch; - height: 996px; + //height: 996px; flex-direction: column; justify-content: center; align-items: flex-start; @@ -100,18 +138,37 @@ const ContentContainer = styled.div` display: flex; `; -const LeftContent = styled.div` +const TopContent = styled.div` align-self: stretch; justify-content: space-between; align-items: flex-end; display: inline-flex; `; - +const BrandTextContainer = styled.div` + justify-content: flex-start; + align-items: center; + gap: 12px; + display: flex; +`; +const BrandText = styled.div` + text-align: center; + color: ${({ theme }) => `${theme.color.gray800}`}; + ${({ theme }) => theme.font.desktop.title2}; + word-wrap: break-word; +`; +const BrandMenuContainer = styled.div` + border-radius: 8px; + overflow: hidden; + border: 2px #efefef solid; + justify-content: flex-start; + align-items: center; + display: flex; +`; const CenterContent = styled.div` align-self: stretch; height: 208px; padding: 24px; - background: #f7f7f7; + background: ${({ theme }) => `${theme.color.gray100}`}; border-radius: 16px; border: 2px #efefef solid; flex-direction: column; @@ -121,10 +178,49 @@ const CenterContent = styled.div` display: flex; `; -const RightContent = styled.div` +const RecommendContainer = styled.div` + align-self: stretch; + justify-content: flex-start; + align-items: flex-end; + gap: 16px; + display: inline-flex; +`; +const RecommendText = styled.div` + color: ${({ theme }) => `${theme.color.primary600}`}; + ${({ theme }) => theme.font.desktop.body1b}; + word-wrap: break-word; +`; +const RecommendCardContainer = styled.div` + align-self: stretch; + justify-content: flex-start; + align-items: center; + gap: 12px; + display: inline-flex; +`; +const BottomContent = styled.div` align-self: stretch; justify-content: flex-start; align-items: flex-start; gap: 20px; display: inline-flex; `; + +const BottomContainer = styled.div` + flex: 1 1 0; + padding: 16px; + background: ${({ theme }) => `${theme.color.gray100}`}; + border-radius: 16px; + border: 2px #efefef solid; + flex-direction: column; + justify-content: flex-start; + align-items: flex-start; + gap: 16px; + display: inline-flex; +`; + +const CardHeader = styled.div` + align-self: stretch; + justify-content: space-between; + align-items: center; + display: inline-flex; +`; diff --git a/src/components/MyPage/Card.tsx b/src/components/MyPage/Card.tsx index 3808714..92ac0f9 100644 --- a/src/components/MyPage/Card.tsx +++ b/src/components/MyPage/Card.tsx @@ -1,12 +1,10 @@ -import React from 'react'; - import styled from 'styled-components'; const Container = styled.div` width: 300px; height: auto; padding: 20px; - background: white; + background: ${({ theme }) => `${theme.color.white}`}; box-shadow: 0px 0px 5px rgba(0, 0, 0, 0.13); border-radius: 8px; flex-direction: column; @@ -28,21 +26,15 @@ const InnerContainer = styled.div` const Title = styled.div` align-self: stretch; - color: #242424; - font-size: 18px; - font-family: 'Spoqa Han Sans Neo'; - font-weight: 500; - line-height: 28px; + color: ${({ theme }) => `${theme.color.gray800}`}; + ${({ theme }) => theme.font.desktop.body1r}; word-wrap: break-word; `; const Description = styled.div` align-self: stretch; - color: #6f6f6f; - font-size: 12px; - font-family: 'Spoqa Han Sans Neo'; - font-weight: 500; - line-height: 20px; + color: ${({ theme }) => `${theme.color.gray500}`}; + ${({ theme }) => theme.font.desktop.label2}; word-wrap: break-word; overflow: hidden; text-overflow: ellipsis; diff --git a/src/components/MyPage/Card2.tsx b/src/components/MyPage/DateCard.tsx similarity index 78% rename from src/components/MyPage/Card2.tsx rename to src/components/MyPage/DateCard.tsx index b65bbbd..8618451 100644 --- a/src/components/MyPage/Card2.tsx +++ b/src/components/MyPage/DateCard.tsx @@ -1,12 +1,10 @@ -import React from 'react'; - import styled from 'styled-components'; const Container = styled.div` width: 300px; height: auto; padding: 20px; - background: white; + background: ${({ theme }) => `${theme.color.white}`}; box-shadow: 0px 0px 5px rgba(0, 0, 0, 0.13); border-radius: 8px; flex-direction: column; @@ -28,21 +26,15 @@ const InnerContainer = styled.div` const Title = styled.div` align-self: stretch; - color: #242424; - font-size: 18px; - font-family: 'Spoqa Han Sans Neo'; - font-weight: 500; - line-height: 28px; + color: ${({ theme }) => `${theme.color.gray800}`}; + ${({ theme }) => theme.font.desktop.body1r}; word-wrap: break-word; `; const Description = styled.div` align-self: stretch; - color: #6f6f6f; - font-size: 12px; - font-family: 'Spoqa Han Sans Neo'; - font-weight: 500; - line-height: 20px; + color: ${({ theme }) => `${theme.color.gray500}`}; + ${({ theme }) => theme.font.desktop.label2}; word-wrap: break-word; overflow: hidden; text-overflow: ellipsis; @@ -52,15 +44,12 @@ const Description = styled.div` const DateText = styled.div` align-self: stretch; - color: #a5a5a5; - font-size: 14px; - font-family: 'Spoqa Han Sans Neo'; - font-weight: 500; - line-height: 20px; + color: ${({ theme }) => `${theme.color.gray300}`}; + ${({ theme }) => theme.font.desktop.label1m}; word-wrap: break-word; `; -const ExampleComponent2 = () => { +const DateCard = () => { return ( @@ -79,4 +68,4 @@ const ExampleComponent2 = () => { ); }; -export default ExampleComponent2; +export default DateCard; diff --git a/src/components/MyPage/ExperienceCard.tsx b/src/components/MyPage/ExperienceCard.tsx index aefae05..3a3fdad 100644 --- a/src/components/MyPage/ExperienceCard.tsx +++ b/src/components/MyPage/ExperienceCard.tsx @@ -33,10 +33,7 @@ const ImageContainer = styled.div` &::before { content: ''; position: absolute; - top: 0; - left: 0; - right: 0; - bottom: 0; + inset: 0; background: rgba(17, 17, 17, 0.36); border-radius: 24px; z-index: 1; @@ -73,10 +70,7 @@ const Overlay = styled.div` justify-content: flex-end; align-items: center; position: absolute; - top: 0; - left: 0; - right: 0; - bottom: 0; + inset: 0; z-index: 2; `; diff --git a/src/components/MyPage/ExperienceView.tsx b/src/components/MyPage/ExperienceView.tsx index 34aa1ea..b4285c4 100644 --- a/src/components/MyPage/ExperienceView.tsx +++ b/src/components/MyPage/ExperienceView.tsx @@ -4,7 +4,7 @@ import styled from 'styled-components'; import { ExperienceWholeView } from '@/components/MyPage/ExperienceWholeView'; import { Dropdown } from '@/components/common/Dropdown/Dropdown'; -import Tabs from '@/components/common/Tab/Tab'; +import { MyPageTab } from '@/components/common/Tab/MyPageTab'; interface Filter { title: string; @@ -84,7 +84,7 @@ export const ExperienceView = () => { return ( - + ); }; diff --git a/src/components/MyPage/PersonaView.tsx b/src/components/MyPage/PersonaView.tsx index 5cdee90..1707042 100644 --- a/src/components/MyPage/PersonaView.tsx +++ b/src/components/MyPage/PersonaView.tsx @@ -1,5 +1,6 @@ import { styled } from 'styled-components'; +import DiscoverImage from '@/assets/myPage/MypageDiscover.png'; import Card from '@/components/MyPage/Card'; export const PersonaView = () => { @@ -10,13 +11,22 @@ export const PersonaView = () => { - Discover 나를 깊게 이해해요 + + + Discover 나를 깊게 이해해요 + + - + + + @@ -87,21 +97,31 @@ const BottomTitleContainer = styled.div` gap: 16px; display: flex; `; +const BottomTitle = styled.div` + color: ${({ theme }) => `${theme.color.gray700}`}; + ${({ theme }) => theme.font.desktop.body1b}; + word-wrap: break-word; +`; +const Highlight = styled.span` + color: ${({ theme }) => `${theme.color.primary600}`}; +`; const BottomCardContainer = styled.div` - align-self: stretch; - justify-content: flex-start; - align-items: center; + display: flex; + flex-wrap: nowrap; + overflow-x: auto; gap: 12px; - display: inline-flex; + padding: 8px; + padding-right: 16px; + + & > * { + flex: 0 0 240px; + } `; const BottomImageContainer = styled.div` width: 988px; - height: 391px; + height: 393px; position: relative; - background: white; - box-shadow: 0px 0px 5px rgba(0, 0, 0, 0.13); - border-radius: 16px; - overflow: hidden; + display: flex; `; diff --git a/src/components/common/Tab/Tab.tsx b/src/components/common/Tab/MyPageTab.tsx similarity index 96% rename from src/components/common/Tab/Tab.tsx rename to src/components/common/Tab/MyPageTab.tsx index ebacb35..c92178a 100644 --- a/src/components/common/Tab/Tab.tsx +++ b/src/components/common/Tab/MyPageTab.tsx @@ -47,7 +47,7 @@ interface TabsProps { tabs: TabItem[]; } -const Tabs = ({ tabs }: TabsProps) => { +export const MyPageTab = ({ tabs }: TabsProps) => { const [value, setValue] = useState(0); const handleChange = (index: number) => { @@ -76,8 +76,6 @@ const Tabs = ({ tabs }: TabsProps) => { ); }; -export default Tabs; - const Container = styled.div` display: flex; flex-direction: column; From 05885f41b9ffd0169305be81b43f0972bf3daa47 Mon Sep 17 00:00:00 2001 From: Mungjin01 Date: Tue, 21 May 2024 04:40:14 +0900 Subject: [PATCH 05/25] =?UTF-8?q?chore:=20=EB=A0=88=EC=9D=B4=EC=95=84?= =?UTF-8?q?=EC=9B=83=20=EC=88=98=EC=A0=95=20(#53)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/MyPage/Card.tsx | 2 +- src/components/MyPage/ExperienceView.tsx | 53 +++------ src/components/MyPage/ExperienceWholeView.tsx | 32 +++++- src/components/MyPage/PersonaView.tsx | 105 ++++++++++++------ 4 files changed, 115 insertions(+), 77 deletions(-) diff --git a/src/components/MyPage/Card.tsx b/src/components/MyPage/Card.tsx index 92ac0f9..baf30ae 100644 --- a/src/components/MyPage/Card.tsx +++ b/src/components/MyPage/Card.tsx @@ -1,7 +1,7 @@ import styled from 'styled-components'; const Container = styled.div` - width: 300px; + width: 100%; height: auto; padding: 20px; background: ${({ theme }) => `${theme.color.white}`}; diff --git a/src/components/MyPage/ExperienceView.tsx b/src/components/MyPage/ExperienceView.tsx index b4285c4..92affb2 100644 --- a/src/components/MyPage/ExperienceView.tsx +++ b/src/components/MyPage/ExperienceView.tsx @@ -1,4 +1,4 @@ -import { useState } from 'react'; +import React, { useState } from 'react'; import styled from 'styled-components'; @@ -6,27 +6,11 @@ import { ExperienceWholeView } from '@/components/MyPage/ExperienceWholeView'; import { Dropdown } from '@/components/common/Dropdown/Dropdown'; import { MyPageTab } from '@/components/common/Tab/MyPageTab'; -interface Filter { - title: string; - contents: string[]; - selected: string | string[]; -} - -const wholeFilter: Filter[] = [ - { - title: '정렬 ', - contents: ['1', '2'], - selected: ' ', - }, -]; - export const ExperienceView = () => { - const [filters, setFilters] = useState(wholeFilter); + const [selectedCategory, setSelectedCategory] = useState(''); - const handleFilterChange = (index: number, selected: string | string[]) => { - const newFilters = [...filters]; - newFilters[index].selected = selected; - setFilters(newFilters); + const handleCategoryChange = (category: string) => { + setSelectedCategory(category); }; const tabs = [ @@ -37,35 +21,27 @@ export const ExperienceView = () => {
- {filters.map((filter, index) => ( - handleFilterChange(index, content)} - /> - ))} + handleCategoryChange(content)} + /> - +
), @@ -88,13 +64,14 @@ export const ExperienceView = () => { ); }; + const StyledContainer = styled.div` width: 100%; height: 100%; padding-top: 81px; - padding-bottom: 52px; `; + const CardContainer = styled.div` padding: 24px; display: flex; diff --git a/src/components/MyPage/ExperienceWholeView.tsx b/src/components/MyPage/ExperienceWholeView.tsx index 0cb8481..876da6f 100644 --- a/src/components/MyPage/ExperienceWholeView.tsx +++ b/src/components/MyPage/ExperienceWholeView.tsx @@ -1,13 +1,23 @@ +import React from 'react'; + import styled from 'styled-components'; import TestImage from '@/assets/test1.png'; import { ExperienceCard } from '@/components/MyPage/ExperienceCard'; -export const ExperienceWholeView = () => { +interface ExperienceWholeViewProps { + selectedCategory: string; +} + +export const ExperienceWholeView = (props: ExperienceWholeViewProps) => { + const { selectedCategory } = props; + + const filteredData = Dummy4.filter((item) => item.filterCategory === selectedCategory); + return ( - {Dummy4.map((item) => ( + {filteredData.map((item) => ( { const StyledSectionContainer = styled.div` width: 100%; height: 100%; - flex-direction: column; justify-content: flex-start; align-items: flex-start; @@ -48,6 +57,7 @@ const Dummy4 = [ subtitle: '경험 타이틀 경험 타이틀경험 타이틀 경험 타이틀경험 타이틀', keywords: ['keyword1', 'keyword2'], hot: true, + filterCategory: '1', }, { id: 2, @@ -56,6 +66,7 @@ const Dummy4 = [ subtitle: '경험 타이틀 경험 타이틀경험 타이틀 경험 타이틀경험 타이틀', keywords: ['keyword1', 'keyword2'], hot: true, + filterCategory: '2', }, { id: 3, @@ -64,6 +75,7 @@ const Dummy4 = [ subtitle: '경험 타이틀 경험 타이틀경험 타이틀 경험 타이틀경험 타이틀', keywords: ['keyword1', 'keyword2'], hot: true, + filterCategory: '1', }, { id: 4, @@ -72,6 +84,7 @@ const Dummy4 = [ subtitle: '경험 타이틀 경험 타이틀경험 타이틀 경험 타이틀경험 타이틀', keywords: ['keyword1', 'keyword2'], hot: true, + filterCategory: '1', }, { id: 5, @@ -80,6 +93,7 @@ const Dummy4 = [ subtitle: '경험 타이틀 경험 타이틀경험 타이틀 경험 타이틀경험 타이틀', keywords: ['keyword1', 'keyword2'], hot: true, + filterCategory: '1', }, { id: 6, @@ -88,6 +102,7 @@ const Dummy4 = [ subtitle: '경험 타이틀 경험 타이틀경험 타이틀 경험 타이틀경험 타이틀', keywords: ['keyword1', 'keyword2'], hot: true, + filterCategory: '1', }, { id: 7, @@ -96,6 +111,7 @@ const Dummy4 = [ subtitle: '경험 타이틀 경험 타이틀경험 타이틀 경험 타이틀경험 타이틀', keywords: ['keyword1', 'keyword2'], hot: true, + filterCategory: '1', }, { id: 8, @@ -104,6 +120,7 @@ const Dummy4 = [ subtitle: '경험 타이틀 경험 타이틀경험 타이틀 경험 타이틀경험 타이틀', keywords: ['keyword1', 'keyword2'], hot: true, + filterCategory: '1', }, { id: 9, @@ -112,6 +129,7 @@ const Dummy4 = [ subtitle: '경험 타이틀 경험 타이틀경험 타이틀 경험 타이틀경험 타이틀', keywords: ['keyword1', 'keyword2'], hot: true, + filterCategory: '1', }, { id: 10, @@ -120,6 +138,7 @@ const Dummy4 = [ subtitle: '경험 타이틀 경험 타이틀경험 타이틀 경험 타이틀경험 타이틀', keywords: ['keyword1', 'keyword2'], hot: true, + filterCategory: '1', }, { id: 11, @@ -128,6 +147,7 @@ const Dummy4 = [ subtitle: '경험 타이틀 경험 타이틀경험 타이틀 경험 타이틀경험 타이틀', keywords: ['keyword1', 'keyword2'], hot: true, + filterCategory: '1', }, { @@ -137,6 +157,7 @@ const Dummy4 = [ subtitle: '경험 타이틀 경험 타이틀경험 타이틀 경험 타이틀경험 타이틀', keywords: ['keyword1', 'keyword2'], hot: true, + filterCategory: '1', }, { id: 13, @@ -145,6 +166,7 @@ const Dummy4 = [ subtitle: '경험 타이틀 경험 타이틀경험 타이틀 경험 타이틀경험 타이틀', keywords: ['keyword1', 'keyword2'], hot: true, + filterCategory: '2', }, { id: 14, @@ -153,6 +175,7 @@ const Dummy4 = [ subtitle: '경험 타이틀 경험 타이틀경험 타이틀 경험 타이틀경험 타이틀', keywords: ['keyword1', 'keyword2'], hot: true, + filterCategory: '1', }, { id: 15, @@ -161,6 +184,7 @@ const Dummy4 = [ subtitle: '경험 타이틀 경험 타이틀경험 타이틀 경험 타이틀경험 타이틀', keywords: ['keyword1', 'keyword2'], hot: true, + filterCategory: '1', }, { id: 16, @@ -169,6 +193,7 @@ const Dummy4 = [ subtitle: '경험 타이틀 경험 타이틀경험 타이틀 경험 타이틀경험 타이틀', keywords: ['keyword1', 'keyword2'], hot: true, + filterCategory: '2', }, { id: 17, @@ -177,5 +202,6 @@ const Dummy4 = [ subtitle: '경험 타이틀 경험 타이틀경험 타이틀 경험 타이틀경험 타이틀', keywords: ['keyword1', 'keyword2'], hot: true, + filterCategory: '1', }, ]; diff --git a/src/components/MyPage/PersonaView.tsx b/src/components/MyPage/PersonaView.tsx index 1707042..7ef8d48 100644 --- a/src/components/MyPage/PersonaView.tsx +++ b/src/components/MyPage/PersonaView.tsx @@ -1,42 +1,69 @@ +import Slider from 'react-slick'; import { styled } from 'styled-components'; import DiscoverImage from '@/assets/myPage/MypageDiscover.png'; import Card from '@/components/MyPage/Card'; export const PersonaView = () => { + const settings = { + dots: false, + infinite: true, + speed: 500, + slidesToShow: 3, + slidesToScroll: 1, + arrows: false, + }; + return ( - <> - - - - - - - - Discover 나를 깊게 이해해요 - - - - - - - - - - - - - - - + + + + + + + + Discover 나를 깊게 이해해요 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ); }; + const StyledContainer = styled.div` padding-top: 81px; `; + const StyledInnerContainer = styled.div` width: 100%; height: 100%; @@ -97,28 +124,36 @@ const BottomTitleContainer = styled.div` gap: 16px; display: flex; `; + const BottomTitle = styled.div` color: ${({ theme }) => `${theme.color.gray700}`}; ${({ theme }) => theme.font.desktop.body1b}; word-wrap: break-word; `; + const Highlight = styled.span` color: ${({ theme }) => `${theme.color.primary600}`}; `; const BottomCardContainer = styled.div` - display: flex; - flex-wrap: nowrap; - overflow-x: auto; - gap: 12px; - padding: 8px; - padding-right: 16px; + width: 100%; +`; - & > * { - flex: 0 0 240px; +const StyledSlider = styled(Slider)` + .slick-list { + padding: 0 20px; + } + .slick-track { + display: flex; + gap: 20px; } `; +const CardWrapper = styled.div` + flex: 0 0 300px; + box-sizing: border-box; +`; + const BottomImageContainer = styled.div` width: 988px; height: 393px; From 618d97704c4c0e8c7eaf702de51b467dfae280f3 Mon Sep 17 00:00:00 2001 From: Mungjin01 Date: Tue, 21 May 2024 23:43:02 +0900 Subject: [PATCH 06/25] =?UTF-8?q?chore:=20=EC=9E=84=EC=8B=9C=20=EB=AA=A8?= =?UTF-8?q?=EB=8B=AC=EC=B0=BD=20=EA=B5=AC=ED=98=84=20(#52)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/MyPage/BrandModal.tsx | 108 +++++++++++++++++++++++++++ src/components/MyPage/BrandView.tsx | 22 ++++++ 2 files changed, 130 insertions(+) create mode 100644 src/components/MyPage/BrandModal.tsx diff --git a/src/components/MyPage/BrandModal.tsx b/src/components/MyPage/BrandModal.tsx new file mode 100644 index 0000000..e25965e --- /dev/null +++ b/src/components/MyPage/BrandModal.tsx @@ -0,0 +1,108 @@ +import styled from 'styled-components'; + +interface ModalProps { + isOpen: boolean; + onClose: () => void; +} + +export const BrandModal = ({ isOpen, onClose }: ModalProps) => { + if (!isOpen) return null; + + return ( + + + 제목을 입력하세요. + + + 유형 + + + + + + + + + + ); +}; + +const ModalContainer = styled.div<{ isOpen: boolean }>` + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: ${({ isOpen }) => (isOpen ? 'rgba(0, 0, 0, 0.5)' : 'transparent')}; + display: flex; + justify-content: center; + align-items: center; +`; + +const ModalContent = styled.div` + width: 618px; + height: 338px; + padding: 32px 24px; + background: ${({ theme }) => theme.color.white}; + box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.25); + border-radius: 16px; + overflow: hidden; + backdrop-filter: blur(8px); + flex-direction: column; + justify-content: space-between; + align-items: center; + display: inline-flex; +`; + +const Title = styled.div` + width: 570px; + height: 32px; + color: #a5a5a5; + font-size: 25px; + font-family: 'Spoqa Han Sans Neo'; + font-weight: 500; + line-height: 32px; + word-wrap: break-word; +`; +const MiddleContent = styled.div` + align-self: stretch; + height: 372px; + flex-direction: column; + justify-content: flex-start; + align-items: flex-start; + gap: 16px; + display: flex; +`; +const ContentInput = styled.div` + align-self: stretch; + justify-content: flex-start; + align-items: center; + gap: 16px; + display: inline-flex; +`; +const InputButton = styled.div` + height: 28px; + justify-content: flex-start; + align-items: center; + gap: 8px; + display: flex; +`; +const ContentsInput = styled.div` + align-self: stretch; + height: 116px; + padding: 16px; + background: #fbfbfb; + border-radius: 8px; + border: 2px #efefef solid; + justify-content: flex-start; + align-items: flex-start; + gap: 12px; + display: inline-flex; +`; +const BottomContent = styled.div` + align-self: stretch; + justify-content: center; + align-items: flex-start; + gap: 16px; + display: inline-flex; +`; diff --git a/src/components/MyPage/BrandView.tsx b/src/components/MyPage/BrandView.tsx index a877bf5..18b12b0 100644 --- a/src/components/MyPage/BrandView.tsx +++ b/src/components/MyPage/BrandView.tsx @@ -1,14 +1,29 @@ +import { useState } from 'react'; + import { styled } from 'styled-components'; +import { ReactComponent as PlusIcon } from '@/assets/icons/add.svg'; import { ReactComponent as ArrowRight } from '@/assets/icons/arrowRight.svg'; import { ReactComponent as BrandLogoImage } from '@/assets/logos/brandLogo.svg'; +import { BrandModal } from '@/components/MyPage/BrandModal'; import Card from '@/components/MyPage/Card'; +import Test from '@/components/MyPage/test'; import { PlainChip } from '@/components/common/Chip/PlainChip'; export const BrandView = () => { + const [isModalOpen, setIsModalOpen] = useState(false); + + const openModal = () => { + setIsModalOpen(true); + }; + + const closeModal = () => { + setIsModalOpen(false); + }; return ( + @@ -45,6 +60,7 @@ export const BrandView = () => { 준비 + @@ -65,6 +81,7 @@ export const BrandView = () => { + ); }; @@ -127,6 +144,11 @@ const RightIcon = styled.div` height: 24px; position: relative; `; +const PlusIcons = styled(PlusIcon)` + path { + fill: ${({ theme }) => theme.color.primary500}; + } +`; const ContentContainer = styled.div` align-self: stretch; From 145df792db050d68db64bc07f6c5c5f54ec06e76 Mon Sep 17 00:00:00 2001 From: Mungjin01 Date: Thu, 23 May 2024 12:43:46 +0900 Subject: [PATCH 07/25] =?UTF-8?q?feat:=20=EB=A7=88=EC=9D=B4=ED=8E=98?= =?UTF-8?q?=EC=9D=B4=EC=A7=80=20=EB=AA=A8=EB=8B=AC=EC=B0=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/MyPage/BrandView.tsx | 35 ++-- src/components/common/Chip/BrandChip.tsx | 28 +++ .../common/Modal/BrandCardModal.tsx | 179 ++++++++++++++++++ 3 files changed, 229 insertions(+), 13 deletions(-) create mode 100644 src/components/common/Chip/BrandChip.tsx create mode 100644 src/components/common/Modal/BrandCardModal.tsx diff --git a/src/components/MyPage/BrandView.tsx b/src/components/MyPage/BrandView.tsx index 18b12b0..81ec5f9 100644 --- a/src/components/MyPage/BrandView.tsx +++ b/src/components/MyPage/BrandView.tsx @@ -2,16 +2,15 @@ import { useState } from 'react'; import { styled } from 'styled-components'; -import { ReactComponent as PlusIcon } from '@/assets/icons/add.svg'; +import { ReactComponent as AddIcon } from '@/assets/icons/add.svg'; import { ReactComponent as ArrowRight } from '@/assets/icons/arrowRight.svg'; import { ReactComponent as BrandLogoImage } from '@/assets/logos/brandLogo.svg'; -import { BrandModal } from '@/components/MyPage/BrandModal'; import Card from '@/components/MyPage/Card'; -import Test from '@/components/MyPage/test'; -import { PlainChip } from '@/components/common/Chip/PlainChip'; +import { BrandChip } from '@/components/common/Chip/BrandChip'; +import { BrandCardModal } from '@/components/common/Modal/BrandCardModal'; export const BrandView = () => { - const [isModalOpen, setIsModalOpen] = useState(false); + const [isModalOpen, setIsModalOpen] = useState(false); const openModal = () => { setIsModalOpen(true); @@ -23,7 +22,6 @@ export const BrandView = () => { return ( - @@ -59,14 +57,19 @@ export const BrandView = () => { - 준비 - + 준비 + + + - 진행 + 진행 + + + @@ -75,13 +78,16 @@ export const BrandView = () => { - 완료 + 완료 + + + - + ); }; @@ -144,12 +150,15 @@ const RightIcon = styled.div` height: 24px; position: relative; `; -const PlusIcons = styled(PlusIcon)` +const StyledAdd = styled.div` + width: 24px; + height: 24px; + position: relative; + path { fill: ${({ theme }) => theme.color.primary500}; } `; - const ContentContainer = styled.div` align-self: stretch; //height: 996px; diff --git a/src/components/common/Chip/BrandChip.tsx b/src/components/common/Chip/BrandChip.tsx new file mode 100644 index 0000000..52df8fb --- /dev/null +++ b/src/components/common/Chip/BrandChip.tsx @@ -0,0 +1,28 @@ +import styled from 'styled-components'; + +interface BrandChipProps { + width?: string; + children: React.ReactNode; +} + +export const BrandChip = ({ width, children }: BrandChipProps) => { + return {children}; +}; + +const StyledContainer = styled.div<{ $width?: string }>` + ${({ theme }) => theme.font.desktop.body1m}; + + width: ${(props) => props.$width || 'auto'}; + height: 42px; + padding: 0 16px; + border-radius: 8px; + + display: flex; + align-items: center; + white-space: nowrap; + + cursor: default; + + color: ${({ theme }) => theme.color.white}; + background: ${({ theme }) => theme.color.gray800}; +`; diff --git a/src/components/common/Modal/BrandCardModal.tsx b/src/components/common/Modal/BrandCardModal.tsx new file mode 100644 index 0000000..e497cea --- /dev/null +++ b/src/components/common/Modal/BrandCardModal.tsx @@ -0,0 +1,179 @@ +import { useState } from 'react'; + +import styled from 'styled-components'; + +import { PlainButton } from '@/components/common/Button/PlainButton'; + +interface ModalProps { + isOpen: boolean; + onClose: () => void; +} + +export const BrandCardModal = ({ isOpen, onClose }: ModalProps) => { + const [title, setTitle] = useState(''); + const [type, setType] = useState(''); + const [startDate, setStartDate] = useState('2024.05.15'); + const [endDate, setEndDate] = useState(''); + const [description, setDescription] = useState(''); + if (!isOpen) return null; + + return ( + + + setTitle(e.target.value)} + placeholder="제목을 입력하세요." + /> + <Frame> + <FrameRow> + <Label>유형</Label> + <Input + type="text" + value={type} + onChange={(e) => setType(e.target.value)} + placeholder="유형을 입력해주세요." + /> + </FrameRow> + <FrameRow> + <Label>진행상태</Label> + <PlainButton variant="disabled" height="48px" width="87px"> + 진행전 + </PlainButton> + <PlainButton variant="gray" height="48px" width="87px"> + 진행중 + </PlainButton> + <PlainButton variant="gray" height="48px" width="74px"> + 완료 + </PlainButton> + </FrameRow> + <FrameRow> + <Label>게시일</Label> + <Input type="text" value={startDate} onChange={(e) => setStartDate(e.target.value)} /> + </FrameRow> + <FrameRow> + <Label>마감일</Label> + <Input + type="text" + value={endDate} + onChange={(e) => setEndDate(e.target.value)} + placeholder="20XX.XX.XX" + /> + </FrameRow> + <FrameRow> + <DescriptionInput + value={description} + onChange={(e) => setDescription(e.target.value)} + placeholder="설명을 입력해주세요." + /> + </FrameRow> + </Frame> + <FrameRow> + <PlainButton variant="disabled" height="48px" onClick={onClose}> + 취소하기 + </PlainButton> + <PlainButton variant="gray" height="48px"> + 추가하기 + </PlainButton> + </FrameRow> + </Container> + </StyledContainer> + ); +}; + +const StyledContainer = styled.div<{ isOpen: boolean }>` + position: fixed; + top: 0; + left: 0; + z-index: 100; + + width: 100vw; + height: 100vh; + //padding: 24px; + background: ${({ theme }) => theme.color.bgModal}; + box-shadow: 0px 0px 10px 0px rgba(0, 0, 0, 0.25); + backdrop-filter: blur(4px); + display: flex; + justify-content: center; + align-items: center; +`; +const Container = styled.div` + width: 618px; + height: 556px; + padding: 32px 24px; + background: ${({ theme }) => `${theme.color.white}`}; + box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.3); + border-radius: 16px; + overflow: hidden; + flex-direction: column; + justify-content: flex-start; + align-items: center; + gap: 24px; + display: inline-flex; +`; + +const Title = styled.input` + width: 570px; + height: 32px; + color: ${({ theme }) => `${theme.color.gray300}`}; + ${({ theme }) => theme.font.desktop.title2}; + word-wrap: break-word; +`; + +const Frame = styled.div` + align-self: stretch; + height: 372px; + flex-direction: column; + justify-content: flex-start; + align-items: flex-start; + gap: 16px; + display: flex; +`; + +const FrameRow = styled.div` + align-self: stretch; + justify-content: flex-start; + align-items: center; + gap: 16px; + display: inline-flex; +`; + +const Input = styled.input` + flex: 1; + height: 48px; + padding: 8px 12px; + background: ${({ theme }) => `${theme.color.white}`}; + box-shadow: 0px 0px 5px rgba(0, 0, 0, 0.13); + border-radius: 8px; + justify-content: flex-start; + align-items: center; + gap: 12px; + display: flex; +`; + +const DescriptionInput = styled.input` + align-self: stretch; + width: 100%; + height: 116px; + padding: 16px; + background: ${({ theme }) => `${theme.color.gray50}`}; + border-radius: 8px; + border: 2px solid #efefef; + justify-content: flex-start; + align-items: flex-start; + gap: 12px; + display: inline-flex; +`; + +const Label = styled.div` + width: 90px; + height: 28px; + justify-content: flex-start; + align-items: center; + gap: 8px; + display: flex; + color: ${({ theme }) => `${theme.color.gray700}`}; + ${({ theme }) => theme.font.desktop.body1m}; + word-wrap: break-word; +`; From 1e1dc6e7953b2fd212aba2bdbad52b6fd4fac6b7 Mon Sep 17 00:00:00 2001 From: Mungjin01 <beckaljm@naver.com> Date: Thu, 23 May 2024 14:13:14 +0900 Subject: [PATCH 08/25] =?UTF-8?q?feat:=20=EB=A7=88=EC=9D=B4=ED=8E=98?= =?UTF-8?q?=EC=9D=B4=EC=A7=80=20=EA=B2=BD=ED=97=98=20=EC=8B=A0=EC=B2=AD=20?= =?UTF-8?q?=EC=B2=B4=EC=9D=B4=EC=A7=80=20api=20=EC=97=B0=EB=8F=99=20?= =?UTF-8?q?=EC=9D=BC=EB=B6=80=20(#52)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/MyPage/BrandModal.tsx | 108 --------- src/components/MyPage/ExperienceView.tsx | 97 -------- src/components/MyPage/ExperienceWholeView.tsx | 207 ------------------ src/components/MyPage/MyExperienceView.tsx | 161 ++++++++++++++ .../MyPage/MyExperienceWholeView.tsx | 81 +++++++ src/pages/Mypage.tsx | 4 +- src/types/myPage.type.ts | 13 ++ 7 files changed, 257 insertions(+), 414 deletions(-) delete mode 100644 src/components/MyPage/BrandModal.tsx delete mode 100644 src/components/MyPage/ExperienceView.tsx delete mode 100644 src/components/MyPage/ExperienceWholeView.tsx create mode 100644 src/components/MyPage/MyExperienceView.tsx create mode 100644 src/components/MyPage/MyExperienceWholeView.tsx create mode 100644 src/types/myPage.type.ts diff --git a/src/components/MyPage/BrandModal.tsx b/src/components/MyPage/BrandModal.tsx deleted file mode 100644 index e25965e..0000000 --- a/src/components/MyPage/BrandModal.tsx +++ /dev/null @@ -1,108 +0,0 @@ -import styled from 'styled-components'; - -interface ModalProps { - isOpen: boolean; - onClose: () => void; -} - -export const BrandModal = ({ isOpen, onClose }: ModalProps) => { - if (!isOpen) return null; - - return ( - <ModalContainer isOpen={isOpen}> - <ModalContent> - <Title>제목을 입력하세요. - - - 유형 - - - - - - - - - - ); -}; - -const ModalContainer = styled.div<{ isOpen: boolean }>` - position: fixed; - top: 0; - left: 0; - width: 100%; - height: 100%; - background: ${({ isOpen }) => (isOpen ? 'rgba(0, 0, 0, 0.5)' : 'transparent')}; - display: flex; - justify-content: center; - align-items: center; -`; - -const ModalContent = styled.div` - width: 618px; - height: 338px; - padding: 32px 24px; - background: ${({ theme }) => theme.color.white}; - box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.25); - border-radius: 16px; - overflow: hidden; - backdrop-filter: blur(8px); - flex-direction: column; - justify-content: space-between; - align-items: center; - display: inline-flex; -`; - -const Title = styled.div` - width: 570px; - height: 32px; - color: #a5a5a5; - font-size: 25px; - font-family: 'Spoqa Han Sans Neo'; - font-weight: 500; - line-height: 32px; - word-wrap: break-word; -`; -const MiddleContent = styled.div` - align-self: stretch; - height: 372px; - flex-direction: column; - justify-content: flex-start; - align-items: flex-start; - gap: 16px; - display: flex; -`; -const ContentInput = styled.div` - align-self: stretch; - justify-content: flex-start; - align-items: center; - gap: 16px; - display: inline-flex; -`; -const InputButton = styled.div` - height: 28px; - justify-content: flex-start; - align-items: center; - gap: 8px; - display: flex; -`; -const ContentsInput = styled.div` - align-self: stretch; - height: 116px; - padding: 16px; - background: #fbfbfb; - border-radius: 8px; - border: 2px #efefef solid; - justify-content: flex-start; - align-items: flex-start; - gap: 12px; - display: inline-flex; -`; -const BottomContent = styled.div` - align-self: stretch; - justify-content: center; - align-items: flex-start; - gap: 16px; - display: inline-flex; -`; diff --git a/src/components/MyPage/ExperienceView.tsx b/src/components/MyPage/ExperienceView.tsx deleted file mode 100644 index 92affb2..0000000 --- a/src/components/MyPage/ExperienceView.tsx +++ /dev/null @@ -1,97 +0,0 @@ -import React, { useState } from 'react'; - -import styled from 'styled-components'; - -import { ExperienceWholeView } from '@/components/MyPage/ExperienceWholeView'; -import { Dropdown } from '@/components/common/Dropdown/Dropdown'; -import { MyPageTab } from '@/components/common/Tab/MyPageTab'; - -export const ExperienceView = () => { - const [selectedCategory, setSelectedCategory] = useState(''); - - const handleCategoryChange = (category: string) => { - setSelectedCategory(category); - }; - - const tabs = [ - { - id: 'tab1', - label: '전체', - content: ( -
- - - handleCategoryChange(content)} - /> - - - - - - - -
- ), - }, - { - id: 'tab2', - label: '자기이해', - content:
자기이해
, - }, - { - id: 'tab3', - label: '브랜딩', - content:
브랜딩
, - }, - ]; - - return ( - - - - ); -}; - -const StyledContainer = styled.div` - width: 100%; - height: 100%; - padding-top: 81px; - padding-bottom: 52px; -`; - -const CardContainer = styled.div` - padding: 24px; - display: flex; -`; - -const StyledFilterContainer = styled.div` - display: flex; - justify-content: space-between; - align-items: center; - padding-left: 24px; - padding-right: 24px; - padding-top: 24px; - - .refresh-button { - ${({ theme }) => theme.font.desktop.body1m}; - color: ${({ theme }) => theme.color.primary700}; - } -`; - -const StyledDropdownContainer = styled.div` - display: flex; - gap: 12px; -`; diff --git a/src/components/MyPage/ExperienceWholeView.tsx b/src/components/MyPage/ExperienceWholeView.tsx deleted file mode 100644 index 876da6f..0000000 --- a/src/components/MyPage/ExperienceWholeView.tsx +++ /dev/null @@ -1,207 +0,0 @@ -import React from 'react'; - -import styled from 'styled-components'; - -import TestImage from '@/assets/test1.png'; -import { ExperienceCard } from '@/components/MyPage/ExperienceCard'; - -interface ExperienceWholeViewProps { - selectedCategory: string; -} - -export const ExperienceWholeView = (props: ExperienceWholeViewProps) => { - const { selectedCategory } = props; - - const filteredData = Dummy4.filter((item) => item.filterCategory === selectedCategory); - - return ( - - - {filteredData.map((item) => ( - - ))} - - - ); -}; - -const StyledSectionContainer = styled.div` - width: 100%; - height: 100%; - flex-direction: column; - justify-content: flex-start; - align-items: flex-start; - gap: 24px; - display: flex; -`; - -const Container = styled.div` - width: 100%; - display: flex; - flex-wrap: wrap; - justify-content: flex-start; - gap: 16px; -`; - -const Dummy4 = [ - { - id: 1, - img: TestImage, - title: '신청완료', - subtitle: '경험 타이틀 경험 타이틀경험 타이틀 경험 타이틀경험 타이틀', - keywords: ['keyword1', 'keyword2'], - hot: true, - filterCategory: '1', - }, - { - id: 2, - img: TestImage, - title: '신청완료', - subtitle: '경험 타이틀 경험 타이틀경험 타이틀 경험 타이틀경험 타이틀', - keywords: ['keyword1', 'keyword2'], - hot: true, - filterCategory: '2', - }, - { - id: 3, - img: TestImage, - title: '신청완료', - subtitle: '경험 타이틀 경험 타이틀경험 타이틀 경험 타이틀경험 타이틀', - keywords: ['keyword1', 'keyword2'], - hot: true, - filterCategory: '1', - }, - { - id: 4, - img: TestImage, - title: '신청완료', - subtitle: '경험 타이틀 경험 타이틀경험 타이틀 경험 타이틀경험 타이틀', - keywords: ['keyword1', 'keyword2'], - hot: true, - filterCategory: '1', - }, - { - id: 5, - img: TestImage, - title: '신청완료', - subtitle: '경험 타이틀 경험 타이틀경험 타이틀 경험 타이틀경험 타이틀', - keywords: ['keyword1', 'keyword2'], - hot: true, - filterCategory: '1', - }, - { - id: 6, - img: TestImage, - title: '신청완료', - subtitle: '경험 타이틀 경험 타이틀경험 타이틀 경험 타이틀경험 타이틀', - keywords: ['keyword1', 'keyword2'], - hot: true, - filterCategory: '1', - }, - { - id: 7, - img: TestImage, - title: '신청완료', - subtitle: '경험 타이틀 경험 타이틀경험 타이틀 경험 타이틀경험 타이틀', - keywords: ['keyword1', 'keyword2'], - hot: true, - filterCategory: '1', - }, - { - id: 8, - img: TestImage, - title: '신청완료', - subtitle: '경험 타이틀 경험 타이틀경험 타이틀 경험 타이틀경험 타이틀', - keywords: ['keyword1', 'keyword2'], - hot: true, - filterCategory: '1', - }, - { - id: 9, - img: TestImage, - title: '신청완료', - subtitle: '경험 타이틀 경험 타이틀경험 타이틀 경험 타이틀경험 타이틀', - keywords: ['keyword1', 'keyword2'], - hot: true, - filterCategory: '1', - }, - { - id: 10, - img: TestImage, - title: '신청완료', - subtitle: '경험 타이틀 경험 타이틀경험 타이틀 경험 타이틀경험 타이틀', - keywords: ['keyword1', 'keyword2'], - hot: true, - filterCategory: '1', - }, - { - id: 11, - img: TestImage, - title: '신청완료', - subtitle: '경험 타이틀 경험 타이틀경험 타이틀 경험 타이틀경험 타이틀', - keywords: ['keyword1', 'keyword2'], - hot: true, - filterCategory: '1', - }, - - { - id: 12, - img: TestImage, - title: '신청완료', - subtitle: '경험 타이틀 경험 타이틀경험 타이틀 경험 타이틀경험 타이틀', - keywords: ['keyword1', 'keyword2'], - hot: true, - filterCategory: '1', - }, - { - id: 13, - img: TestImage, - title: '신청완료', - subtitle: '경험 타이틀 경험 타이틀경험 타이틀 경험 타이틀경험 타이틀', - keywords: ['keyword1', 'keyword2'], - hot: true, - filterCategory: '2', - }, - { - id: 14, - img: TestImage, - title: '신청완료', - subtitle: '경험 타이틀 경험 타이틀경험 타이틀 경험 타이틀경험 타이틀', - keywords: ['keyword1', 'keyword2'], - hot: true, - filterCategory: '1', - }, - { - id: 15, - img: TestImage, - title: '신청완료', - subtitle: '경험 타이틀 경험 타이틀경험 타이틀 경험 타이틀경험 타이틀', - keywords: ['keyword1', 'keyword2'], - hot: true, - filterCategory: '1', - }, - { - id: 16, - img: TestImage, - title: '신청완료', - subtitle: '경험 타이틀 경험 타이틀경험 타이틀 경험 타이틀경험 타이틀', - keywords: ['keyword1', 'keyword2'], - hot: true, - filterCategory: '2', - }, - { - id: 17, - img: TestImage, - title: '신청완료', - subtitle: '경험 타이틀 경험 타이틀경험 타이틀 경험 타이틀경험 타이틀', - keywords: ['keyword1', 'keyword2'], - hot: true, - filterCategory: '1', - }, -]; diff --git a/src/components/MyPage/MyExperienceView.tsx b/src/components/MyPage/MyExperienceView.tsx new file mode 100644 index 0000000..9aa0c64 --- /dev/null +++ b/src/components/MyPage/MyExperienceView.tsx @@ -0,0 +1,161 @@ +import { useState } from 'react'; + +import styled from 'styled-components'; + +import { MyExperienceWholeView } from '@/components/MyPage/MyExperienceWholeView'; +import { Dropdown } from '@/components/common/Dropdown/Dropdown'; +import { MyPageTab } from '@/components/common/Tab/MyPageTab'; +import { MyPageFilter } from '@/types/myPage.type'; + +interface MyExperienceViewTemplateProps { + title: string | React.ReactNode; + subTitle: string; + backgroundColor: string; + filters: MyPageFilter[]; +} + +export const MyExperienceView = ({ + filters, +}: Omit) => { + const [programDate, setProgramDate] = useState([]); + const [sortOrder, setSortOrder] = useState('desc'); + + const resetFilters = () => { + setProgramDate([]); + setSortOrder('desc'); + filters.forEach((filter: MyPageFilter) => filter.setSelected([])); + }; + + const tabs = [ + { + id: 'tab1', + label: '전체', + content: ( +
+ + + { + setSortOrder(newSelected === '최신순' ? 'desc' : 'asc'); + }} + width="312px" + contentMaxHeight="172px" + multiple={false} + /> + + + + + + {' '} + +
+ ), + }, + { + id: 'tab2', + label: '자기이해', + content: ( +
+ + + { + setSortOrder(newSelected === '최신순' ? 'desc' : 'asc'); + }} + width="312px" + contentMaxHeight="172px" + multiple={false} + /> + + + + + + {' '} + +
+ ), + }, + { + id: 'tab3', + label: '브랜딩', + content: ( +
+ + + { + setSortOrder(newSelected === '최신순' ? 'desc' : 'asc'); + }} + width="312px" + contentMaxHeight="172px" + multiple={false} + /> + + + + + + {' '} + +
+ ), + }, + ]; + + return ( + + + + ); +}; + +const StyledContainer = styled.div` + width: 100%; + height: 100%; + padding-top: 81px; + padding-bottom: 52px; +`; + +const CardContainer = styled.div` + padding: 24px; + display: flex; +`; + +const StyledFilterContainer = styled.div` + display: flex; + justify-content: space-between; + align-items: center; + padding-left: 24px; + padding-right: 24px; + padding-top: 24px; + + .refresh-button { + ${({ theme }) => theme.font.desktop.body1m}; + color: ${({ theme }) => theme.color.primary700}; + } +`; + +const StyledDropdownContainer = styled.div` + display: flex; + gap: 12px; +`; diff --git a/src/components/MyPage/MyExperienceWholeView.tsx b/src/components/MyPage/MyExperienceWholeView.tsx new file mode 100644 index 0000000..8cf5a15 --- /dev/null +++ b/src/components/MyPage/MyExperienceWholeView.tsx @@ -0,0 +1,81 @@ +import { useEffect, useState } from 'react'; + +import styled from 'styled-components'; + +import { authClient } from '@/apis/client'; +import { ExperienceCard } from '@/components/MyPage/ExperienceCard'; + +interface ApiResponseItem { + selfUnderstandingUrl: string; + name: string; + link: string; + programsId: number; +} + +interface MyExperienceProps { + programData: string[]; + sortOrder: string; +} + +export const MyExperienceWholeView = ({ programData, sortOrder }: MyExperienceProps) => { + const [data, setData] = useState([]); + const [error, setError] = useState(null); + + useEffect(() => { + const fetchData = async () => { + try { + const response = await authClient.get('/api/users/experiences/all/desc', {}); + + if (response.data.is_success) { + setData(response.data.payload); + } else { + console.error('error1', response.data.message); + setError(response.data.message); + } + } catch (error) { + console.error('error2', error); + setError('error3'); + } + }; + + fetchData(); + }, [programData, sortOrder]); + + if (error) { + return
Error: {error}
; + } + + return ( + + + {data.map((item) => ( + + ))} + + + ); +}; + +const StyledSectionContainer = styled.div` + width: 100%; + height: 100%; + flex-direction: column; + justify-content: flex-start; + align-items: flex-start; + gap: 24px; + display: flex; +`; + +const Container = styled.div` + width: 100%; + display: flex; + flex-wrap: wrap; + justify-content: flex-start; + gap: 16px; +`; diff --git a/src/pages/Mypage.tsx b/src/pages/Mypage.tsx index da0c127..0a854af 100644 --- a/src/pages/Mypage.tsx +++ b/src/pages/Mypage.tsx @@ -1,7 +1,7 @@ import { useState } from 'react'; import { BrandView } from '@/components/MyPage/BrandView'; -import { ExperienceView } from '@/components/MyPage/ExperienceView'; +import { MyExperienceView } from '@/components/MyPage/MyExperienceView'; import MyPageSidebar from '@/components/MyPage/MyPageSidebar'; import { PersonaView } from '@/components/MyPage/PersonaView'; import { SettingView } from '@/components/MyPage/SettingView'; @@ -16,7 +16,7 @@ export const MyPage1 = () => { case '내 페르소나': return ; case '신청한 경험': - return ; + return ; case '환경설정': return ; default: diff --git a/src/types/myPage.type.ts b/src/types/myPage.type.ts new file mode 100644 index 0000000..7981d2b --- /dev/null +++ b/src/types/myPage.type.ts @@ -0,0 +1,13 @@ +export interface MyPageFilter { + title: string; + contents: string[]; + selected: string[]; + setSelected: (newSelected: string[]) => void; +} + +export interface MyPageFilterCards { + title: string; + contents: string[]; + selected: string[]; + setSelected: (newSelected: string[]) => void; +} From 9584228c1cb011915d3b9d92a651307a7d8007ff Mon Sep 17 00:00:00 2001 From: Mungjin01 Date: Thu, 23 May 2024 16:38:36 +0900 Subject: [PATCH 09/25] =?UTF-8?q?chore:=20=EC=B9=B4=EB=93=9C=20=EB=8D=94?= =?UTF-8?q?=EB=AF=B8=EB=8D=B0=EC=9D=B4=ED=84=B0=20=EC=B6=94=EA=B0=80=20(#5?= =?UTF-8?q?2)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/MyPage/BrandView.tsx | 102 +++++++++++++++++++++++++--- src/components/MyPage/Card.tsx | 13 +--- 2 files changed, 95 insertions(+), 20 deletions(-) diff --git a/src/components/MyPage/BrandView.tsx b/src/components/MyPage/BrandView.tsx index 81ec5f9..5eb37fc 100644 --- a/src/components/MyPage/BrandView.tsx +++ b/src/components/MyPage/BrandView.tsx @@ -48,10 +48,9 @@ export const BrandView = () => { Ai 추천 - - - - + {Dummy1.map((item) => ( + + ))} @@ -62,7 +61,9 @@ export const BrandView = () => { - + {Dummy1.map((item) => ( + + ))} @@ -71,10 +72,9 @@ export const BrandView = () => { - - - - + {Dummy1.map((item) => ( + + ))} @@ -83,7 +83,9 @@ export const BrandView = () => { - + {Dummy1.map((item) => ( + + ))} @@ -255,3 +257,83 @@ const CardHeader = styled.div` align-items: center; display: inline-flex; `; + +const Dummy1 = [ + { + id: 1, + title: '생성형 AI란 무엇인가?', + description: '생성형 AI의 기본 개념, 역사, 및 발전 과정을 설명하는 콘텐츠', + }, + { + id: 2, + title: '생성형 AI의 실제 응용 사례', + description: + '예술, 음악, 글쓰기, 게임 개발 등 다양한 분야에서의 생성형 AI 활용 사례를 소개하는 콘텐츠', + }, + { + id: 3, + title: '생성형 AI 툴 및 플랫폼 리뷰', + description: '생성형 AI 툴 및 플랫폼 리뷰', + }, + { + id: 4, + title: '생성형 AI와 윤리적 문제', + description: + '생성형 AI 사용 시 발생할 수 있는 윤리적 문제와 해결 방안에 대한 논의를 다룬 콘텐츠', + }, + { + id: 5, + title: '생성형 AI를 활용한 프로젝트 튜토리얼', + description: + '텍스트 생성, 이미지 생성, 음악 생성 등 구체적인 프로젝트를 통해 생성형 AI 사용법을 단계별로 설명하는 콘텐츠', + }, + { + id: 6, + title: '생성형 AI를 이용한 생산성 향상', + description: + '생성형 AI를 활용하여 개인 및 조직의 생산성을 향상시키는 방법에 대한 팁과 전략을 담은 콘텐츠', + }, + { + id: 7, + title: '생성형 AI 관련 인터뷰 및 전문가 의견', + description: '생성형 AI 분야의 전문가와의 인터뷰를 통해 얻은 인사이트 공유', + }, + { + id: 8, + title: '생성형 AI 트렌드 및 최신 뉴스', + description: '생성형 AI 분야의 최신 트렌드와 뉴스 업데이트', + }, + { + id: 9, + title: '온라인 프로필 최적화', + description: + 'LinkedIn, Twitter, Instagram 등 주요 소셜 미디어에서 프로필을 최적화하는 팁을 담은 콘텐츠', + }, + { + id: 10, + title: '브랜딩을 위한 비디오 콘텐츠 제작', + description: '유튜브 등 비디오 플랫폼에서 자신을 브랜딩한 방법과 소감을 담은 콘텐츠', + }, + { + id: 11, + title: '퍼스널 브랜딩과 SEO 전략', + description: '검색 엔진 최적화를 통해 자신의 온라인 가시성을 높이는 방법을 설명하는 콘텐츠', + }, + { + id: 12, + title: '디자인 씽킹 툴킷 소개', + description: '디자인 씽킹을 실천할 때 유용한 도구와 리소스를 소개하는 콘텐츠', + }, + { + id: 13, + title: '디자인 씽킹과 데이터 분석', + description: + '데이터 분석과 디자인 씽킹을 결합하여 인사이트를 도출하는 방법에 대한 학습 내용을 공유하는 콘텐츠', + }, + { + id: 14, + title: 'AI와 머신러닝: 미래를 이끌 기술 소개', + description: + 'AI와 머신러닝 관련하여 미래에서 어떤 방향으로 활용될 것인가에 대한 내용을 다룬 콘텐츠', + }, +]; diff --git a/src/components/MyPage/Card.tsx b/src/components/MyPage/Card.tsx index baf30ae..d8aab70 100644 --- a/src/components/MyPage/Card.tsx +++ b/src/components/MyPage/Card.tsx @@ -42,19 +42,12 @@ const Description = styled.div` max-height: 100px; `; -const Card = () => { +const Card = ({ title, description }: { title: string; description: string }) => { return ( - ERD 설계 방법에 관하여 - - 모든 국민은 종교의 자유를 가진다. 사면·감형 및 복권에 관한 사항은 법률로 정한다. 국회는 - 국정을 감사하거나 특정한 국정사안에 대하여 조사할 수 있으며, 이에 필요한 서류의 제출 또는 - 증인의 출석과 증언이나 의견의 진술을 요구할 수 있다. -
- 재의의 요구가 있을 때에는 국회는 재의에 붙이고, 재적의원과반수의 출석과 출석의원 3분의 2 - 이상의 찬성으로 전과 같은 의결을 하면 그 법률안은 법률로서 확정된다. -
+ {title} + {description}
); From 82b3826c0d8aeadad3b81505f1b9bf14ef26bb77 Mon Sep 17 00:00:00 2001 From: Mungjin01 Date: Thu, 23 May 2024 17:49:42 +0900 Subject: [PATCH 10/25] =?UTF-8?q?chore:=20=EB=A0=88=EC=9D=B4=EC=95=84?= =?UTF-8?q?=EC=9B=83=20=EC=9D=BC=EB=B6=80=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/MyPage/BrandView.tsx | 115 ++++++++++++++++++++++-- src/components/MyPage/MyPageSidebar.tsx | 4 +- src/components/MyPage/PersonaView.tsx | 99 ++++++++++++++++---- 3 files changed, 193 insertions(+), 25 deletions(-) diff --git a/src/components/MyPage/BrandView.tsx b/src/components/MyPage/BrandView.tsx index 5eb37fc..a7b7b2a 100644 --- a/src/components/MyPage/BrandView.tsx +++ b/src/components/MyPage/BrandView.tsx @@ -48,7 +48,7 @@ export const BrandView = () => { Ai 추천 - {Dummy1.map((item) => ( + {Dummy2.map((item) => ( ))} @@ -61,7 +61,7 @@ export const BrandView = () => { - {Dummy1.map((item) => ( + {Dummy3.map((item) => ( ))} @@ -72,7 +72,7 @@ export const BrandView = () => { - {Dummy1.map((item) => ( + {Dummy4.map((item) => ( ))} @@ -83,7 +83,7 @@ export const BrandView = () => { - {Dummy1.map((item) => ( + {Dummy5.map((item) => ( ))} @@ -146,7 +146,16 @@ const RightText = styled.div` color: ${({ theme }) => `${theme.color.gray700}`}; ${({ theme }) => theme.font.desktop.body1m}; `; - +/* +const StyledSlider = styled(Slider)` + .slick-list { + padding: 0 20px; + } + .slick-track { + display: flex; + gap: 20px; + } +`;*/ const RightIcon = styled.div` width: 24px; height: 24px; @@ -257,7 +266,7 @@ const CardHeader = styled.div` align-items: center; display: inline-flex; `; - +/* const Dummy1 = [ { id: 1, @@ -336,4 +345,98 @@ const Dummy1 = [ description: 'AI와 머신러닝 관련하여 미래에서 어떤 방향으로 활용될 것인가에 대한 내용을 다룬 콘텐츠', }, +];*/ + +const Dummy2 = [ + { + id: 1, + title: '생성형 AI란 무엇인가?', + description: '생성형 AI의 기본 개념, 역사, 및 발전 과정을 설명하는 콘텐츠', + }, + { + id: 2, + title: '생성형 AI의 실제 응용 사례', + description: + '예술, 음악, 글쓰기, 게임 개발 등 다양한 분야에서의 생성형 AI 활용 사례를 소개하는 콘텐츠', + }, + { + id: 3, + title: '생성형 AI 툴 및 플랫폼 리뷰', + description: '생성형 AI 툴 및 플랫폼 리뷰', + }, + { + id: 4, + title: '생성형 AI와 윤리적 문제', + description: + '생성형 AI 사용 시 발생할 수 있는 윤리적 문제와 해결 방안에 대한 논의를 다룬 콘텐츠', + }, +]; + +const Dummy3 = [ + { + id: 1, + title: '생성형 AI란 무엇인가?', + description: '생성형 AI의 기본 개념, 역사, 및 발전 과정을 설명하는 콘텐츠', + }, + { + id: 2, + title: '생성형 AI의 실제 응용 사례', + description: + '예술, 음악, 글쓰기, 게임 개발 등 다양한 분야에서의 생성형 AI 활용 사례를 소개하는 콘텐츠', + }, +]; + +const Dummy4 = [ + { + id: 3, + title: '생성형 AI 툴 및 플랫폼 리뷰', + description: '생성형 AI 툴 및 플랫폼 리뷰', + }, + { + id: 4, + title: '생성형 AI와 윤리적 문제', + description: + '생성형 AI 사용 시 발생할 수 있는 윤리적 문제와 해결 방안에 대한 논의를 다룬 콘텐츠', + }, + { + id: 5, + title: '생성형 AI를 활용한 프로젝트 튜토리얼', + description: + '텍스트 생성, 이미지 생성, 음악 생성 등 구체적인 프로젝트를 통해 생성형 AI 사용법을 단계별로 설명하는 콘텐츠', + }, + { + id: 6, + title: '생성형 AI를 이용한 생산성 향상', + description: + '생성형 AI를 활용하여 개인 및 조직의 생산성을 향상시키는 방법에 대한 팁과 전략을 담은 콘텐츠', + }, +]; + +const Dummy5 = [ + { + id: 7, + title: '생성형 AI 관련 인터뷰 및 전문가 의견', + description: '생성형 AI 분야의 전문가와의 인터뷰를 통해 얻은 인사이트 공유', + }, + { + id: 8, + title: '생성형 AI 트렌드 및 최신 뉴스', + description: '생성형 AI 분야의 최신 트렌드와 뉴스 업데이트', + }, + { + id: 9, + title: '온라인 프로필 최적화', + description: + 'LinkedIn, Twitter, Instagram 등 주요 소셜 미디어에서 프로필을 최적화하는 팁을 담은 콘텐츠', + }, + { + id: 10, + title: '브랜딩을 위한 비디오 콘텐츠 제작', + description: '유튜브 등 비디오 플랫폼에서 자신을 브랜딩한 방법과 소감을 담은 콘텐츠', + }, + { + id: 11, + title: '퍼스널 브랜딩과 SEO 전략', + description: '검색 엔진 최적화를 통해 자신의 온라인 가시성을 높이는 방법을 설명하는 콘텐츠', + }, ]; diff --git a/src/components/MyPage/MyPageSidebar.tsx b/src/components/MyPage/MyPageSidebar.tsx index b5a2f46..967fbe5 100644 --- a/src/components/MyPage/MyPageSidebar.tsx +++ b/src/components/MyPage/MyPageSidebar.tsx @@ -1,5 +1,3 @@ -import React from 'react'; - import styled from 'styled-components'; import { theme } from '@/styles'; @@ -46,7 +44,7 @@ interface SidebarProps { setActiveMenu: (menu: string) => void; } -const Sidebar: React.FC = ({ activeMenu, setActiveMenu }) => { +const Sidebar = ({ activeMenu, setActiveMenu }: SidebarProps) => { const menuItems = [ { label: '브랜드 관리', key: '브랜드 관리' }, { label: '내 페르소나', key: '내 페르소나' }, diff --git a/src/components/MyPage/PersonaView.tsx b/src/components/MyPage/PersonaView.tsx index 7ef8d48..c2cbac7 100644 --- a/src/components/MyPage/PersonaView.tsx +++ b/src/components/MyPage/PersonaView.tsx @@ -28,22 +28,9 @@ export const PersonaView = () => { - - - - - - - - - - - - - - - - + {Dummy1.map((item) => ( + + ))} @@ -160,3 +147,83 @@ const BottomImageContainer = styled.div` position: relative; display: flex; `; + +const Dummy1 = [ + { + id: 1, + title: '생성형 AI란 무엇인가?', + description: '생성형 AI의 기본 개념, 역사, 및 발전 과정을 설명하는 콘텐츠', + }, + { + id: 2, + title: '생성형 AI의 실제 응용 사례', + description: + '예술, 음악, 글쓰기, 게임 개발 등 다양한 분야에서의 생성형 AI 활용 사례를 소개하는 콘텐츠', + }, + { + id: 3, + title: '생성형 AI 툴 및 플랫폼 리뷰', + description: '생성형 AI 툴 및 플랫폼 리뷰', + }, + { + id: 4, + title: '생성형 AI와 윤리적 문제', + description: + '생성형 AI 사용 시 발생할 수 있는 윤리적 문제와 해결 방안에 대한 논의를 다룬 콘텐츠', + }, + { + id: 5, + title: '생성형 AI를 활용한 프로젝트 튜토리얼', + description: + '텍스트 생성, 이미지 생성, 음악 생성 등 구체적인 프로젝트를 통해 생성형 AI 사용법을 단계별로 설명하는 콘텐츠', + }, + { + id: 6, + title: '생성형 AI를 이용한 생산성 향상', + description: + '생성형 AI를 활용하여 개인 및 조직의 생산성을 향상시키는 방법에 대한 팁과 전략을 담은 콘텐츠', + }, + { + id: 7, + title: '생성형 AI 관련 인터뷰 및 전문가 의견', + description: '생성형 AI 분야의 전문가와의 인터뷰를 통해 얻은 인사이트 공유', + }, + { + id: 8, + title: '생성형 AI 트렌드 및 최신 뉴스', + description: '생성형 AI 분야의 최신 트렌드와 뉴스 업데이트', + }, + { + id: 9, + title: '온라인 프로필 최적화', + description: + 'LinkedIn, Twitter, Instagram 등 주요 소셜 미디어에서 프로필을 최적화하는 팁을 담은 콘텐츠', + }, + { + id: 10, + title: '브랜딩을 위한 비디오 콘텐츠 제작', + description: '유튜브 등 비디오 플랫폼에서 자신을 브랜딩한 방법과 소감을 담은 콘텐츠', + }, + { + id: 11, + title: '퍼스널 브랜딩과 SEO 전략', + description: '검색 엔진 최적화를 통해 자신의 온라인 가시성을 높이는 방법을 설명하는 콘텐츠', + }, + { + id: 12, + title: '디자인 씽킹 툴킷 소개', + description: '디자인 씽킹을 실천할 때 유용한 도구와 리소스를 소개하는 콘텐츠', + }, + { + id: 13, + title: '디자인 씽킹과 데이터 분석', + description: + '데이터 분석과 디자인 씽킹을 결합하여 인사이트를 도출하는 방법에 대한 학습 내용을 공유하는 콘텐츠', + }, + { + id: 14, + title: 'AI와 머신러닝: 미래를 이끌 기술 소개', + description: + 'AI와 머신러닝 관련하여 미래에서 어떤 방향으로 활용될 것인가에 대한 내용을 다룬 콘텐츠', + }, +]; From 942247224ec8e7b6e6f61d9894e8f4a75c5f12e0 Mon Sep 17 00:00:00 2001 From: Mungjin01 Date: Thu, 23 May 2024 17:55:12 +0900 Subject: [PATCH 11/25] =?UTF-8?q?chore:=20api=20=EC=88=98=EC=A0=95=20(#52)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/MyPage/MyBrandingView.tsx | 81 +++++++++++++++++++ src/components/MyPage/MyExperienceView.tsx | 6 +- src/components/MyPage/MyUnderstandingView.tsx | 81 +++++++++++++++++++ 3 files changed, 166 insertions(+), 2 deletions(-) create mode 100644 src/components/MyPage/MyBrandingView.tsx create mode 100644 src/components/MyPage/MyUnderstandingView.tsx diff --git a/src/components/MyPage/MyBrandingView.tsx b/src/components/MyPage/MyBrandingView.tsx new file mode 100644 index 0000000..387d30e --- /dev/null +++ b/src/components/MyPage/MyBrandingView.tsx @@ -0,0 +1,81 @@ +import { useEffect, useState } from 'react'; + +import styled from 'styled-components'; + +import { authClient } from '@/apis/client'; +import { ExperienceCard } from '@/components/MyPage/ExperienceCard'; + +interface ApiResponseItem { + selfUnderstandingUrl: string; + name: string; + link: string; + programsId: number; +} + +interface MyExperienceProps { + programData: string[]; + sortOrder: string; +} + +export const MyBrandingView = ({ programData, sortOrder }: MyExperienceProps) => { + const [data, setData] = useState([]); + const [error, setError] = useState(null); + + useEffect(() => { + const fetchData = async () => { + try { + const response = await authClient.get('/api/users/experiences/branding/desc', {}); + + if (response.data.is_success) { + setData(response.data.payload); + } else { + console.error('error1', response.data.message); + setError(response.data.message); + } + } catch (error) { + console.error('error2', error); + setError('error3'); + } + }; + + fetchData(); + }, [programData, sortOrder]); + + if (error) { + return
Error: {error}
; + } + + return ( + + + {data.map((item) => ( + + ))} + + + ); +}; + +const StyledSectionContainer = styled.div` + width: 100%; + height: 100%; + flex-direction: column; + justify-content: flex-start; + align-items: flex-start; + gap: 24px; + display: flex; +`; + +const Container = styled.div` + width: 100%; + display: flex; + flex-wrap: wrap; + justify-content: flex-start; + gap: 16px; +`; diff --git a/src/components/MyPage/MyExperienceView.tsx b/src/components/MyPage/MyExperienceView.tsx index 9aa0c64..cf697dc 100644 --- a/src/components/MyPage/MyExperienceView.tsx +++ b/src/components/MyPage/MyExperienceView.tsx @@ -2,7 +2,9 @@ import { useState } from 'react'; import styled from 'styled-components'; +import { MyBrandingView } from '@/components/MyPage/MyBrandingView'; import { MyExperienceWholeView } from '@/components/MyPage/MyExperienceWholeView'; +import { MyUnderstandingView } from '@/components/MyPage/MyUnderstandingView'; import { Dropdown } from '@/components/common/Dropdown/Dropdown'; import { MyPageTab } from '@/components/common/Tab/MyPageTab'; import { MyPageFilter } from '@/types/myPage.type'; @@ -84,7 +86,7 @@ export const MyExperienceView = ({ - {' '} + {' '} ), @@ -115,7 +117,7 @@ export const MyExperienceView = ({ - {' '} + {' '} ), diff --git a/src/components/MyPage/MyUnderstandingView.tsx b/src/components/MyPage/MyUnderstandingView.tsx new file mode 100644 index 0000000..ccb4f05 --- /dev/null +++ b/src/components/MyPage/MyUnderstandingView.tsx @@ -0,0 +1,81 @@ +import { useEffect, useState } from 'react'; + +import styled from 'styled-components'; + +import { authClient } from '@/apis/client'; +import { ExperienceCard } from '@/components/MyPage/ExperienceCard'; + +interface ApiResponseItem { + selfUnderstandingUrl: string; + name: string; + link: string; + programsId: number; +} + +interface MyExperienceProps { + programData: string[]; + sortOrder: string; +} + +export const MyUnderstandingView = ({ programData, sortOrder }: MyExperienceProps) => { + const [data, setData] = useState([]); + const [error, setError] = useState(null); + + useEffect(() => { + const fetchData = async () => { + try { + const response = await authClient.get('/api/users/experiences/self-understanding/desc', {}); + + if (response.data.is_success) { + setData(response.data.payload); + } else { + console.error('error1', response.data.message); + setError(response.data.message); + } + } catch (error) { + console.error('error2', error); + setError('error3'); + } + }; + + fetchData(); + }, [programData, sortOrder]); + + if (error) { + return
Error: {error}
; + } + + return ( + + + {data.map((item) => ( + + ))} + + + ); +}; + +const StyledSectionContainer = styled.div` + width: 100%; + height: 100%; + flex-direction: column; + justify-content: flex-start; + align-items: flex-start; + gap: 24px; + display: flex; +`; + +const Container = styled.div` + width: 100%; + display: flex; + flex-wrap: wrap; + justify-content: flex-start; + gap: 16px; +`; From 3cf0b431f22ff09d9fcef6635c8fa0a323576b09 Mon Sep 17 00:00:00 2001 From: Mungjin01 Date: Thu, 23 May 2024 18:45:29 +0900 Subject: [PATCH 12/25] =?UTF-8?q?chore:=20=EB=B8=8C=EB=9E=9C=EB=93=9C=20?= =?UTF-8?q?=EA=B4=80=EB=A6=AC=20=EC=B9=B4=EB=93=9C=20=EC=9C=A0=ED=98=95=20?= =?UTF-8?q?=EC=88=98=EC=A0=95=20(#52)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/MyPage/BrandView.tsx | 59 ++++++++++++++++++++------- src/components/MyPage/DateCard.tsx | 25 ++++++------ src/components/MyPage/PersonaView.tsx | 22 ++++++---- 3 files changed, 72 insertions(+), 34 deletions(-) diff --git a/src/components/MyPage/BrandView.tsx b/src/components/MyPage/BrandView.tsx index a7b7b2a..c94bfb2 100644 --- a/src/components/MyPage/BrandView.tsx +++ b/src/components/MyPage/BrandView.tsx @@ -6,8 +6,10 @@ import { ReactComponent as AddIcon } from '@/assets/icons/add.svg'; import { ReactComponent as ArrowRight } from '@/assets/icons/arrowRight.svg'; import { ReactComponent as BrandLogoImage } from '@/assets/logos/brandLogo.svg'; import Card from '@/components/MyPage/Card'; +import DateCard from '@/components/MyPage/DateCard'; import { BrandChip } from '@/components/common/Chip/BrandChip'; import { BrandCardModal } from '@/components/common/Modal/BrandCardModal'; +import { userService } from '@/services/UserService'; export const BrandView = () => { const [isModalOpen, setIsModalOpen] = useState(false); @@ -46,6 +48,9 @@ export const BrandView = () => { Ai 추천 + + {userService.getUserNickname()}님, 이런 콘텐츠는 어떠세요? + {Dummy2.map((item) => ( @@ -62,7 +67,12 @@ export const BrandView = () => { {Dummy3.map((item) => ( - + ))} @@ -73,7 +83,12 @@ export const BrandView = () => { {Dummy4.map((item) => ( - + ))} @@ -84,7 +99,12 @@ export const BrandView = () => { {Dummy5.map((item) => ( - + ))} @@ -146,16 +166,7 @@ const RightText = styled.div` color: ${({ theme }) => `${theme.color.gray700}`}; ${({ theme }) => theme.font.desktop.body1m}; `; -/* -const StyledSlider = styled(Slider)` - .slick-list { - padding: 0 20px; - } - .slick-track { - display: flex; - gap: 20px; - } -`;*/ + const RightIcon = styled.div` width: 24px; height: 24px; @@ -208,7 +219,7 @@ const BrandMenuContainer = styled.div` `; const CenterContent = styled.div` align-self: stretch; - height: 208px; + //height: 208px; padding: 24px; background: ${({ theme }) => `${theme.color.gray100}`}; border-radius: 16px; @@ -231,6 +242,11 @@ const RecommendText = styled.div` color: ${({ theme }) => `${theme.color.primary600}`}; ${({ theme }) => theme.font.desktop.body1b}; word-wrap: break-word; + + > span { + color: ${({ theme }) => theme.color.gray900}; + ${({ theme }) => theme.font.desktop.body1r}; + } `; const RecommendCardContainer = styled.div` align-self: stretch; @@ -352,23 +368,27 @@ const Dummy2 = [ id: 1, title: '생성형 AI란 무엇인가?', description: '생성형 AI의 기본 개념, 역사, 및 발전 과정을 설명하는 콘텐츠', + date: '2024.06.24', }, { id: 2, title: '생성형 AI의 실제 응용 사례', description: '예술, 음악, 글쓰기, 게임 개발 등 다양한 분야에서의 생성형 AI 활용 사례를 소개하는 콘텐츠', + date: '2024.06.24', }, { id: 3, title: '생성형 AI 툴 및 플랫폼 리뷰', description: '생성형 AI 툴 및 플랫폼 리뷰', + date: '2024.06.24', }, { id: 4, title: '생성형 AI와 윤리적 문제', description: '생성형 AI 사용 시 발생할 수 있는 윤리적 문제와 해결 방안에 대한 논의를 다룬 콘텐츠', + date: '2024.06.24', }, ]; @@ -377,12 +397,14 @@ const Dummy3 = [ id: 1, title: '생성형 AI란 무엇인가?', description: '생성형 AI의 기본 개념, 역사, 및 발전 과정을 설명하는 콘텐츠', + date: '2024.06.24', }, { id: 2, title: '생성형 AI의 실제 응용 사례', description: '예술, 음악, 글쓰기, 게임 개발 등 다양한 분야에서의 생성형 AI 활용 사례를 소개하는 콘텐츠', + date: '2024.06.24', }, ]; @@ -391,24 +413,28 @@ const Dummy4 = [ id: 3, title: '생성형 AI 툴 및 플랫폼 리뷰', description: '생성형 AI 툴 및 플랫폼 리뷰', + date: '2024.06.24', }, { id: 4, title: '생성형 AI와 윤리적 문제', description: '생성형 AI 사용 시 발생할 수 있는 윤리적 문제와 해결 방안에 대한 논의를 다룬 콘텐츠', + date: '2024.06.24', }, { id: 5, title: '생성형 AI를 활용한 프로젝트 튜토리얼', description: '텍스트 생성, 이미지 생성, 음악 생성 등 구체적인 프로젝트를 통해 생성형 AI 사용법을 단계별로 설명하는 콘텐츠', + date: '2024.06.24', }, { id: 6, title: '생성형 AI를 이용한 생산성 향상', description: '생성형 AI를 활용하여 개인 및 조직의 생산성을 향상시키는 방법에 대한 팁과 전략을 담은 콘텐츠', + date: '2024.06.24', }, ]; @@ -417,26 +443,31 @@ const Dummy5 = [ id: 7, title: '생성형 AI 관련 인터뷰 및 전문가 의견', description: '생성형 AI 분야의 전문가와의 인터뷰를 통해 얻은 인사이트 공유', + date: '2024.06.24', }, { id: 8, title: '생성형 AI 트렌드 및 최신 뉴스', description: '생성형 AI 분야의 최신 트렌드와 뉴스 업데이트', + date: '2024.06.24', }, { id: 9, title: '온라인 프로필 최적화', description: 'LinkedIn, Twitter, Instagram 등 주요 소셜 미디어에서 프로필을 최적화하는 팁을 담은 콘텐츠', + date: '2024.06.24', }, { id: 10, title: '브랜딩을 위한 비디오 콘텐츠 제작', description: '유튜브 등 비디오 플랫폼에서 자신을 브랜딩한 방법과 소감을 담은 콘텐츠', + date: '2024.06.24', }, { id: 11, title: '퍼스널 브랜딩과 SEO 전략', description: '검색 엔진 최적화를 통해 자신의 온라인 가시성을 높이는 방법을 설명하는 콘텐츠', + date: '2024.06.24', }, ]; diff --git a/src/components/MyPage/DateCard.tsx b/src/components/MyPage/DateCard.tsx index 8618451..19cc8fe 100644 --- a/src/components/MyPage/DateCard.tsx +++ b/src/components/MyPage/DateCard.tsx @@ -1,7 +1,7 @@ import styled from 'styled-components'; const Container = styled.div` - width: 300px; + width: 100%; height: auto; padding: 20px; background: ${({ theme }) => `${theme.color.white}`}; @@ -49,21 +49,22 @@ const DateText = styled.div` word-wrap: break-word; `; -const DateCard = () => { +const DateCard = ({ + title, + description, + date, +}: { + title: string; + description: string; + date: string; +}) => { return ( - ERD 설계 방법에 관하여 - - 모든 국민은 종교의 자유를 가진다. 사면·감형 및 복권에 관한 사항은 법률로 정한다. 국회는 - 국정을 감사하거나 특정한 국정사안에 대하여 조사할 수 있으며, 이에 필요한 서류의 제출 또는 - 증인의 출석과 증언이나 의견의 진술을 요구할 수 있다. -
- 재의의 요구가 있을 때에는 국회는 재의에 붙이고, 재적의원과반수의 출석과 출석의원 3분의 2 - 이상의 찬성으로 전과 같은 의결을 하면 그 법률안은 법률로서 확정된다. -
+ {title} + {description}
- 2024.06.24 + {date}
); }; diff --git a/src/components/MyPage/PersonaView.tsx b/src/components/MyPage/PersonaView.tsx index c2cbac7..7dc6151 100644 --- a/src/components/MyPage/PersonaView.tsx +++ b/src/components/MyPage/PersonaView.tsx @@ -10,7 +10,7 @@ export const PersonaView = () => { infinite: true, speed: 500, slidesToShow: 3, - slidesToScroll: 1, + slidesToScroll: 3, arrows: false, }; @@ -27,11 +27,13 @@ export const PersonaView = () => { - - {Dummy1.map((item) => ( - - ))} - + {Dummy1.map((item) => ( +
+ + + +
+ ))}
@@ -128,17 +130,21 @@ const BottomCardContainer = styled.div` const StyledSlider = styled(Slider)` .slick-list { - padding: 0 20px; + overflow: visible; + } + .slick-slide > div { + margin: 0 10px; } .slick-track { display: flex; - gap: 20px; + align-items: center; } `; const CardWrapper = styled.div` flex: 0 0 300px; box-sizing: border-box; + padding: 12px; `; const BottomImageContainer = styled.div` From 30da652ec1980b6502a43eb5c92f842411f1c305 Mon Sep 17 00:00:00 2001 From: Mungjin01 Date: Thu, 23 May 2024 19:31:51 +0900 Subject: [PATCH 13/25] =?UTF-8?q?fix:=20=EB=AA=A8=EB=8B=AC=EC=B0=BD=20?= =?UTF-8?q?=EC=9E=85=EB=A0=A5=20=EC=88=98=EC=A0=95(#52)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/MyPage/MyExperienceView.tsx | 6 ++--- .../common/Modal/BrandCardModal.tsx | 22 ++++++++++++++++--- 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/src/components/MyPage/MyExperienceView.tsx b/src/components/MyPage/MyExperienceView.tsx index cf697dc..664ea3b 100644 --- a/src/components/MyPage/MyExperienceView.tsx +++ b/src/components/MyPage/MyExperienceView.tsx @@ -44,7 +44,7 @@ export const MyExperienceView = ({ clickContentHandler={(newSelected: string) => { setSortOrder(newSelected === '최신순' ? 'desc' : 'asc'); }} - width="312px" + width="201px" contentMaxHeight="172px" multiple={false} /> @@ -75,7 +75,7 @@ export const MyExperienceView = ({ clickContentHandler={(newSelected: string) => { setSortOrder(newSelected === '최신순' ? 'desc' : 'asc'); }} - width="312px" + width="201px" contentMaxHeight="172px" multiple={false} /> @@ -106,7 +106,7 @@ export const MyExperienceView = ({ clickContentHandler={(newSelected: string) => { setSortOrder(newSelected === '최신순' ? 'desc' : 'asc'); }} - width="312px" + width="201px" contentMaxHeight="172px" multiple={false} /> diff --git a/src/components/common/Modal/BrandCardModal.tsx b/src/components/common/Modal/BrandCardModal.tsx index e497cea..076c338 100644 --- a/src/components/common/Modal/BrandCardModal.tsx +++ b/src/components/common/Modal/BrandCardModal.tsx @@ -15,6 +15,7 @@ export const BrandCardModal = ({ isOpen, onClose }: ModalProps) => { const [startDate, setStartDate] = useState('2024.05.15'); const [endDate, setEndDate] = useState(''); const [description, setDescription] = useState(''); + const [status, setStatus] = useState<'진행전' | '진행중' | '완료'>('진행전'); if (!isOpen) return null; return ( @@ -38,13 +39,28 @@ export const BrandCardModal = ({ isOpen, onClose }: ModalProps) => { - + setStatus('진행전')} + > 진행전 - + setStatus('진행중')} + > 진행중 - + setStatus('완료')} + > 완료 From 3537ec89265e6172e65f1fbd3779abcc27557b5b Mon Sep 17 00:00:00 2001 From: aaminha Date: Thu, 23 May 2024 20:50:35 +0900 Subject: [PATCH 14/25] =?UTF-8?q?feat:=20=EB=A7=88=EC=9D=B4=ED=8E=98?= =?UTF-8?q?=EC=9D=B4=EC=A7=80=20=EB=82=B4=20=ED=8E=98=EB=A5=B4=EC=86=8C?= =?UTF-8?q?=EB=82=98=20=EC=84=B9=EC=85=98=20=EA=B5=AC=ED=98=84=20(#62)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/assets/myPage/MypageDiscover.png | Bin 37060 -> 30455 bytes src/components/MyPage/Card.tsx | 4 +- src/components/MyPage/PersonaView.tsx | 149 ++++++++++++++++++++------ 3 files changed, 116 insertions(+), 37 deletions(-) diff --git a/src/assets/myPage/MypageDiscover.png b/src/assets/myPage/MypageDiscover.png index 471813408cc78b14880f123119a5d9a6479eb1d3..c578f64a41006f8f01d3201e834adc9e1bf141a1 100644 GIT binary patch literal 30455 zcmeFY=R;H5^F16yP(j2iU;zQWCn{}*fgI#HUfbd z=RhEa*Jqi5Pt@Zqf!{&re4bhOfk3Pr^j{31tj|}04;lQ7G}J*=!`Ih=znpea(^Uh3 zYLi%x?U+EIzo^YvN4GaQ$1VCoQ+gD@n1AnIFn~~ar{B|Z!t%! z3ErSxg*?B@9(c>)gV!}41Z-s0O=ZWB;!j>D_)UhjEL4l6I+df{AvleZ)kEbGvZm8R z`hGy5$MC-Yen$TMr$m9fG+Thm9I!2 z4xL~9BcN#v_xH7etu?&#Y5x$tzS{`+SKjegTtAt65?mbsihOP*!;pVosQo_WdlCgt zQQ2eeJ7oSsJFXAfdcNP(nx2IvSfr6pI1~A)U3puSpoj>k=g;_NDYd}|Fzgm3=_ILB zDz>fWP>H7`y=rTary1#W`1K+6J6}CP8@ED;Xzl@(eLl6`Orw+xK4n{9WOIWRG4^em$M-*y4*}G<{{2 zb%z$dHA|_#=H!G~m89!@yMn(i=!CWftS~t*Us<^ZQe8ef2fC>Kg`pa8@_?+ebC{eS zCo-yd!tmm%#)X`plxdr}hY!|?@CJ_Nr~@}d&%4c4=5RexeJ#86P}ohSc!AgYD>-cw z`#0A7vKn@6AMH`;-^X@J4)n^PKN9)*b~=>3bg$EQnvi;48;O?OyMOtgrYPYrA}>rJ zGSX330x#*OZiGfbIG`FG{&j0%YqgA^0yV$@|LuLWGVcq2FD{MoY>aUhtQW z19a|amvyQ%l4g_&_Zs1=Ng9&zfV`l#y>(Ab`*d=A#(SEqU0K9lBNyOj9aGnO-^Z8gB+x#!8 z$3n-yuy65{ck!Ch4g%NwHeN}ThSHXE(n|*S#*zJndh4hcA$J{~z8(qlG)1ZB-&;GAu-vm(0o|ED`zrzX_xKs|)1LDo-h~1)t8a1{ z#pZYaO#ehROt(LD3NZ~H`PiwKX;JKzQ}w2bjU&ZMey6|oJB)HclZI$R#*7NW`s9{*!b)dhbAR;FlEn% z&<$eNGfb6UiX%jnlx4Pm8?b$t*Le-pF4lxg?wOt7TYM`0ThMCivdy+6=? z=+02{;LfNXU7n7ROlq6R9_a-?pCa-6-|`YTX@Wf|dqPNZg>)wCJu^OZF8~)d+ z@XERz$~)Sz{v^*sJn+iOkA?HIsrQS0q9BxBNJLtD;6V(ve{(gHxB7Y=#9+(eZx!zm zH#uxhrpH?7JNO3!s93;i0RaEwRn+*YqLYvXIIm>jtN zUs~<+SWZh{xYDoL>PpH)cA+~N(-G!Ga;;DB;#fe=q6xpL^A0Z^=kB&Wbb=l~{q62# z9%i#_G!Vx%%2{?6*H?mO?<5O4n&eE47>V+TEJu?eka1E+q0K)Zt-sVk{}4|w74QMC zVm=f&KR8oxXp5WyBft(8*pDpRPXctuJyek8SYRu&n#w4eP~J#5I|*3%6TsyRPQ_Y+ z!zW)2;sgALep;E?ML5)j!kVcK#MVz$D+Savl;^ibTb$!JN>n@a+M%?f;i##@>IS^7 zQnk(Ap&w!XwDlMgwb4Y$9ztZF!)cZ-F9hz#gvVKrnHE&fl-*ty-aU3$Y?_(vPZ)d1 zzHhn9-wBR~Qr2h(tzSphvy93hsOTE6ssnb>M|l%sE#Y@wBE(}MT2<9a_U!VY=aN7; z`SgqtZIpeJtAHUOgJS$9a6pySFjm)_P~pQXQKA+=YOY}&yzXt#UKW%lCwzY)d|^uX z!XgVc+kpie-a;Jv=(*Ohs4?U(p?|f~=#8kSVml(Bb7+N}6pt-jX%X-&DM`J5n8-9B zWV@Xh)7?1Vprw%#ZfO+0bFlu_OOTY&jq(aq|0<>_^np=zoo=y$Ekg(p{w)WKlkV% z%uGGjw6en*u1(oM#l$;TODF6zGyW1^Uofgv8dqpnrF>@%u^;(c9)a)6*AdNlT zkcq(u%V2HeTVU;+`Zn*@zwH}&whJ@iWx%(rE5pQ%3)(|wWzSOYUV+s z3SvLVNys@(?&tTxL={IK(JJcrpRc(Wq2etfSZMWu#%sNdriZ-=44`Pb-A+A{{S~KZ zi7+=7z-LxS`)n$kM2&aoz~ab*XRB!OGTHD)IYSCC2gr-qAiG` zWx~=-hChi5zCGvhg9gi0c5oB5mq07b4cC9v48w785T! z%FBa3C5j3GXtHj{gq61zRSWyyP49kLTcV|Ao00@yf|npdiuL-S;w9ZpEf+>IvF@f; zD&#GE$x7Q@@IA0~hj2Hw)>5Q{L=uFhA@AH0ezmHIK)D3;$L-wt##vCTc@5uJeYrB+ z)lGYbIv0C%>eZLc$K}iShD$zjsil72lRuo6}cFc%Y=@61!Q>ap=97 zmds9cu?VglFB;6kBCxtP)&uN>N%#1EQ}v4D?uV4irS=Ht?$N)IA&j8!F<;q0Z*rnd zR*T18&*{er(ZWJLij{<%f7Gg#10GOhVecWaI$X&u!*p8KgC=LZ+hGfdb7)vFcx7r)ZWtB9fzkIWa z_`g>QOSD(ku>=|X9GyZK~fdmx$r^_iS#0_m}EBii8iJ0s+MW=$1OnMfUhJ z-+&IwP|$Ii{Eo9{MhO1s8lfU*6ek(8$_dK%MSC%^fLzatN!4itg8yWzcr|$==T%TJ ze_Gl$8Id1un68$fAZrgFR$@*|0djEq_kM?_ndKFYA+wFI zzFH%sCH#EyTcRK%h32KFJDp}=Y*SEd?zA*ll$`^U2g zrvdN5lh8Q$WTjP#BcaKwIo*S?Wj;o^Q+kGO2hl;K@oXc=>|E z>QsZKQyUA}J=#RfFXc{1uD{B()egqCUSe5y%`u`U=Qfmgv?xATh&`Q!6P(n_3M{)#M3IYNS;}?sDA>)Yr!)E{ zR9{INI@`XwG(@KB7-M!z44`wn>7BCT9d*En+qsI$gyt+#Iu_P;NB@Z!&_!-K^nHc)=c)i99iE1R%=@NPG&_~~${kI(4w z;Yh^2qrl^Xzis4dwY?@Utd6$!KyV(m(IZ_x^uXsAhDt(qHj;UlzD6;wDmmjuNO-K! ze8f(l5T2YEEi%L+2Z^{A;deKTUF^0kjV&B^yHAFv9`TP!K%%1m=GFVL6rQ%#pC)+R zl!tIX#^j>4kn+)5;oHv5fHoMJ5N%uN@pG(DV>kSyenh#RBV28+Q+Q#OA>Xj}H4msi z|9RMQs##X1luO(RHxraiYjrq>=O7qd`8qCcYjqb_-Tn7=y49rvdA1T*NXX87XCCu# zm6o!stn;Iei0x|fzPV|orBgwPfghGSB&(yFXEzvt?B$39H(n1F@PbCv%pkJrf)w4R z7SN7yfr;4Fx8ZRwJk<=$c2@ayvt{P}YJ$LfBahlw_AMbzo)&A>V;&E6oGeqIhXk`~ zFQ$b?4~$-@P6TFAc+cFQZHzjctAt&GdA5*n!K*pUpo$1dD@M1^+zonmGkkowjbQ!MPaNju35KKj@oA5eh4 zx16xid=JkMKFn$;K&iLOPMqj#?4umIX{%oU0^!9so>I4idFg2Pary3N-M#H2ntuhx zi(sk5z&a>HaxY3Lrq73k${}D-ei}VhzbSnd0}7`e?XQOE4Lp&_m{NtrtmNMYsz-dt z1g5#G6>cfzJXn*5d8Iz5m%%<5K$gxvu@#eu!Ab>|2N$pMBkT{wlZw6W3wR3U3EG8p z?!?I-mv%}5oR^l9QSSfbRa%(}ZLRs*e4Yeyo?qXo^-|W)3CPV^KBF}m_~v(~bnD9p z@?>uD*Q`q|5tR*wKY&#(NP{Ae>6zBQa%+>4TcHE3yJI&{bN3Mjm2j{@hACQ$(KFT; z-)@71T8~kTM@_*HMjvqZ9+^NOymeY?5yw*#V@`;BM2mXo1e7ygdUs>RzX>&SBshUo z2K#QCj!r3C#g=jLEF#S9-FX%Ke-;@D?;>fC>}zcb*k@j=Q}Jv#1x!1qk5QD6ps!vy8?ixewthnJ!yj&ALzqGTOGKT3M{qEL}&I$TL=5HZg8gSYefY zJB85d{JT4L1;AxPgqf=8X!sB_v4Krp31L(c6wn_iGhz)5_q??j>p`SB-f&>dkhnI1 z4*EWK91-dqk`~BwYoRnR+?_;R@J_pHVV@@ywpnjY2xyq27qe5gC0nQs-29SG`j!0s zhkuQ~^8FQj9=AY_ULrMI+Yxk<{^&Q89+<@?=N~*$`=|YaNHNCbdQP{@db+pbd%?Or zRQ`xrU6BTj^(Qw?2gQ@fK)p%+7x~PMpQC} zv+>C4v=O=C)-ZfyN=H(3V{|Qaleq&q=ldS7P}RGQt`3(W?)b8GP=`M5?X#>wM=RaU zGnhS#eZksHP?cEEoTyM-Nj#fIjJM<91beBM&n3*k)};B$)VIpFOnDWtD2 z$H+(-jQ)|sp~lx&yo$^fLXC7Ox3UzhZ#inuwl&^%h-qAtFIfGt_7k=GCb~ISNNx`8 z2s?A0&Ds-o)!*Mg!)@XZ4>L;a#-Ft3tG;0z$D-Q4Zime_=_gJrv4Rx;%5z6HcBYH2 z*_sC5q+`8wTilHFlOA!L3)u=8EZ)*T6Z!NpT}djR$%w9I&R1h}V>7qDKcy<4(s!Cr zYLY+t>wzst;~aKHR&AU-_S`JSF`{hBt79j%dODw|OjyXnuX*4M?OJlMXR0Fftu!c0 zreZO7UXs`GTc!a_o?v0#0NFgW)9~g)<#xP1#d~tZ<;OcN=Dy`zAv4>sfO)JxIT(%a zaHe$R3KV{u&+GUXkt?94-NOalw^DhzosZfZ*VeV-+}IDD%(ihkIVY{bFohH3H>)L` zfilg9a=5j$M`*uQ{CL9_t@uWeb>}bq68%#@KW`R33TOy&Z~SfSrW&Is`N2Ce?I7|$kH1*bl-t)k=DtTUW8j>v z_21s}%9zF@EPD*)$;Q7-YcLRk@{7rib{IM9$NMY29qcNJ=!^F}-_t^BLiXJ$r6Kp$ z6bv+Pn^%7e#awD1#*zDrHRal;2CPpiDS=#jp`0D>nO=fir2(v;?ZOWP!mjehYOqzX z29N`!o5f|Hvla9kePQq{?hRVMD#2C)E*`0j^r$Y2ZWcMTJ=sYgxPWv2bU6q;ZYXd! zmIX}NBfhPdxLmNzy#cmlx*!0og=IWsD=T9ltn$v;*5Ua>)1uS+dIry?ARQenQ1)hm zpQqBYcW$;&MKS79}pQw#$55uX3!x6HP$Uw{Ga@4<|8#aI$GSpcre~=)E?p5Yt zHQf(8W09@q#Y%U!5dW?Yub@}C;9SG|=HM5T%9#8T4?EOTHx?sfP2Mu}(s0DQoO^nA zU^&~q2-pL0Q{>!NHQgCsw;x&^%ZgfYz$%GC~b&NG-a>Z~x`0k-J};mUuq~vo7HAY-^+aE!E9KA4ET(qZGT1=-c4$WiST~4bnte1Ql_zs zUItY>D2uke07q`?r9285uHyz0_hLby3_CyRs;k|Cu$GwQgAR#_zARKQ8Ja&DXb3)T zU0g}(=XzqX!`k;`uQVlP+j;91wGWuYDhle1 zaPTtx+&vAt$P}Ip0{vU+?ki@3%o!fm!;0lNbpKgh$i|ItP#44vWm@}mvU9WiTcuov zGaPyob+0>N=IsX8-iXWrazD#l*4=TxCtTh@$KeT3W#qiVotB1ZijbV zJ^E_+f(i)};Ga{5RwwSHI`J}wtn%ip9Bn&D%JoAywxF=9p{Omb25@MDb3i4U@9F-j zMC667ZJs7~Z0S?4_+pWrU!=juGO)2!UFRXQY#o@!!&E0FecvPo)`G8L+qhYlIjGF{ zjxfp~mzk9vAh9t4#e{)uEEs%}JZsV~(_<90Uj$y$E_NsV;<;Auw~2BOEbk3Y-Te7c zz3A!R~+kAefog*5YO0tCr69zG47r(Vh8| z6Q;^qwn8w>)*~ngne(8mw8tFoObpc==qc^U!mn}{Gx0KBe%u=^?9Walp9)DY7q+}m zz4~VUomj#d&{sNJXsskNWXpNymY->FZx0x|ikJmFuQ!pmKH{?br?gFVVo9NZrKyb~ z7xV?<=A0}`;yFgpt1fS#wAQpLY`DeCXd3Sk-v}c^>+OHAq}*yW0(@tKw6<23sS**c zX^WZ7#ecSW-@vU-8Iu=054w1nZpP#yKHxcShxWsj?6+?5%hk@v2JQ*eEil?0=yRMm z*Vfk7w3Vxua#Aku>TyeqCSkohha~Jkkp^^mXw(E}`m2L9>!I8JqW4vK)GQo~&=K1) zt7m7M(gWO{yEs;!`R=pL!B6tX-i>3VVYKK44{k-;^R#9*6QQ z>XeilQD6LnjiV06N!X9d+h|PRLQ}MxJms@XAh*;8xLF2uzkO)(7XDCw-2E&_b)PPz zd?_=u98Y2peacW~C&^rKele9HsjHy2Jzm9OE0pQrL9lpLZTn*5@yS9MPS}`$}p)?Mya_5(40d1Z} z$Pmf6P&z9&*T-BdT36Gf|P{N$;g6!oNd7F z$#hshXz4LmV6Gg$kqH^HAu-9QO1-TBSkws?8an467?^cu5CGKnzT;^^xh3$*XMzB* zZ&XJ`G4Kd(v>RF~p8(G9n5ISfa0clj2%mXhnoWo3jaFP?`7n?sR?orCvS4?rIQkC|7_4Op@EOeq z!w4&uOd~fJ-%huQdhc(Pge%RuL+|N3$q(P=VE|ox21D|oTJUA|al$xfGZ){7;t!P< zi)mNd7v2CcHsoWx?C4x-_M1=d>7sORWt;({jExEiM90103++B0JitOG%i(`%Sf`Ui znv&B6D#Y&_xZbZE7G}~L$uyR{L#ByYL_r$xzW|M(p_-q&i~&S9*13ex^X3vPX}v*W zat;ncgI5T-ZY8$Uj@+pt*h?;AI@oT=H)1F|r($;Ir#EiVg{tIYSe970=5T%i0~x(b)3 za2H|7&6^g(b|UPRo;0%AF&&?nIIA?6@QfDtw$RY>UQVx4-NLOz!GAB)iFGdF=ph5h zk^U$LV4kLO=o#4NOnfF%+KCo%uld(0zr8iX30F=&FfMWNYRwHiZ(oIvHbA6(j*=ug ztQP+T47D|G21dGly6pKfqUZW+dr%ekRnwrXIOe$H(wI3as zp@yZtOoXSfTo7m&Ftcim9~z&V%NO&U3Xv@F&~&%AtxY@c!CrsLwQzLz@z8il-9OWV ziJz{8FWgF_(ckF+yc2k;H?rLQ{d4y;S?`%8+su0BA<0txyxi#tD`Mhxd3#33&j134 z#*=qWn>9ZHL#Yd4$A5d7L8C8$!x{a`dAi~AX8=)b9Ump~!m=dN?`DS12O1ksJWhq= zv~Ff9GV7pc%ZqL=D_q_(S0}%CPdeV*FMcZq?3li0Mr>R zDNeKSK>4)u(Ut@`O8x+bu9PxBXh}^{`$vf@P1$b=OKJ@Y z`HhX}dn46yEU#w^=h0{B|8ArEkP~B{GOY)6H-MOQU16 z<7m-?*7puN76g>cOp8;^j9nVa0{}i~7Hse{6Q%J_^ zb*#Zn#<1?Gsz9-84Wwjuyx{aLR^E1cs(e2{jh4>K%j--g-~ba}rLXw8zhI3BR$5Ec zb6el7_0wEVyLCKwnP&TSj*<AStI5GdO32P z(R29Hr z0C&$GaKl`xRhfn5#ekhD2|E^?X7N+E4ILX+JBa_?jNwJT@=5b|g6^6{eW$>ih=B9vA4rKuKGf91s#0=w<>*mziB$x?1yxdEsZqi1JVd(?CCsD|6DJJMQ&sud@}6^)oJkMT6Uv z5`ya~9Wa#cMN~QfasU8`0eNM9a~M|2nRL7Z$0nvZwmNhtkE`mYdMQo012!&dwC-&{ zo5e!*A}XnKCMbsdZ~*K1!))iz`G}!76@Nu4ztM0Fw_?Ag3AKWH6DT%UXSlFn2?xw0jpX$g_ygy zh0=_+EL;iLFg@veQ?8ix%cu9%m?|4+gB|dxjjO$psm}lT;U!%4Q)=gCMvWyjzvM&d zMquT2#x#8(A2Ita8_>tgQ9=bM^ax1gBNc!=d6Phpy#w{Xh0O^a1E-oHsgtU@ltPcj zsI2ZL?qc+~#B(+0K*te{Y7MwAqBr_f&^R}q0mMRg3*Pa3>!|GFrQiQCVsg44De$J4 zm{_29L$p_=p-_M>^Q3)YgOvhzMegvQ;o>|7Aahiu(lJhdGGY7y^W8RN?odXsb|D)! zvHKG%va!hYzYJJuC#u{7$OuV~8U8yIx*O#fmQCd6Yy`fvgjZacHk8(8Ens#B+S4LI zmC^=&zg5nmy)w~u8!g>pmQy1DxD9LpA24v44-~sY;_~=+O$n?VUbA=-JtvnKw_4!cfeC@h`Zpuoe+PxH4$%7bN9sdZKID) z1_CO2ETr3-mYOsf6btdM`?|M2L8pWb5dHXGrRBq0bPF5Cx3IYq^{c(MxIhI(#i8kG zb97<^Kx(&N81=~NAtnmDe9NP_>4yAor5BnvNaMxYY~6}7&V$31Zc-65lT?MtWIK$i z7hHHvXc^$UD@{DWsFK@RLPia)HHZhK>I>}g`=6g*Qk;P?Ns5bbPh#HR4(Gv+R1a(# zBT1LcwZDh}6Ry@2F_*j3N4?^jn_E&=3z^*&1a&B=(&V(dP5IYk$`QLl`5={(I|sZ&2pzPO^q~zVU1q zO3~(U^r25L>pTW3wH)%NmrBAf{hbip=rwx}1e$J%=T5WBU}S5W4z;@5{W`}AcX1;U znO&4MlWCpm13x}ay<lqmLjiLE=n3tIYcX6sS9XrRnL8dMQ3oumd zFP#+^UhMEQmek~#C^YHf`UCiY%-gtCo?+n-^Sy;@Bf|F<5x zSfH7Q39v%Dg>_uNSN8rCc|7$854AiCAGG8X$TczAF{YWfnSr^yaq_=<^vm^akxMVc zk$wYhPZ%2(RBExIc&r)cF?TFJ6#O>gWTrLcB%Dk(%ayyKqY!jHqlLRr`Vr%`YI|Fw#`WwHo?)pbZ!P7pS7rk^r~dlC$|G%ceH+9>^G^9z1YGCQSARMwYg3?oK2T zGY?v=lkvJ48wxy3ROOdPZ~e%$KPzhWJFL4poZSPNL<(vHFEF`{DY6JeEY;ZQ_ z5Sec>T97(NO?&c^>4b-V@lb&%0&*J-e>F8_+A4OVim(IJ>GHwtpNEtuVAt6HE7c`L z<|Mu6A1X=|Vp?0$&9d3PxqNG?8i8LHjYLFO+<^3bFEN!Bw(C z9RV{FlE6gdpy|YJr6~)A^0o8m9O%#YvuvtAwA>;&_8L#RQkgx-N)0_1=1j_89{t4y zT6__~sYO{Zwg>P4BSGA!p)gV;j=zku0n8XXf1BybT7%ICgefO|lIahoF0pmUGgmxh z@$8KQ;z;y{cy+FnOXA`7H+KAKt?SrR^ls?1=$f&nMvR+gaG_yR9C9HXtM}OiM)}Fw z*+&qzB^N_^BA;L^_U8@2mKZzX$+E!_FE)i5@5#27<*(l_?O_QvD>xeJ9A*IvKZ3%< zFhoXb$7sMjt+gvQj0z177&tQ@7H&_pP4ZrUH~e-)L&ESp$PQqtPlNav$lut*z@$bG zy{XFv5?2*pI2U}Y=&mhP%SN)Z}(j}i{;;n@#rFq?%A~qgV6%u!> z|4RUjaLY@H(KXze<^8+?T$ZVL<5IoM!`;>FkS}!Uqla~FHax#ihL@uWsOe#050ujW z3i8+G<)N3YMHNa{4lAgmb-xix9Q?-H=zzA*Re#*m)|)`<${o$?lC7auVRF~Q#KUx= zAlew*r5CX$bA9Htcfy@skhm>k?wOPIo_eIm2LcQPfA^Iw-w~QLM|H^_ZZ2$$PCF3Z z-p~y{K(KMB9sYbRV)4~5yW{sR zXQH^{segLCXBe_XZpyyQW82d|UPZQjPo3;!_*U#WtpFQO`mY}Eump47SrjH zXD$%yW4rX8-RGWPvY2P(P+zuo;=i!pu>3qNy)sbtc`Ss1vNrt0`4_v; z5Q643M}ckAqO$tLta2sW5%m#0UAmt{92Hx_k;9&~sZK$aW@~H{6bJkayq@IZ5(C@z z^~RNAXN%r7i>!&ZUCh-Uz~V?n-Y=0D>N;^FxvF}M_^LW$m1UPcpZAsmUvfMTy7LM! zj6M9i=z~qMbY_G1A@#aY>8pMnq#RK^1o9@#A09|aXIL>svVZ117B-0(GkakujX{{#@AUSV8ql zIuF;)ta#HfGt9*kw8g$LAYfL^OtJ)A$WwwfRr(@kd7lWq2nzI@;~g!Xjdd}*?W!GV z8ZoJ;WDCq_G^IRdP1lzT^AKPH3c6Z*|dj-DKEeIxBt%DyD$+4(**0_$uAC5#GBdoAm))GynJX zBUvBDuO>k5QI?T*beMkm2w<)G$KaXZZiIrFJ1+gQ{%O}B|LHys1~jo=qkEbN5deF! z<xF~D_Pl#}|?xIX6w`i3gCYaUN5IxQnh=`scCC)ArHlBO%Bh7vo ze3N0TYS;W)S5$w!MT zQ$!h=LDctDgEuoM8Luj8>ufocf^z7dM71U3PqE-FpW3hkWxgBnr>U=QPM}Coif`7l z)>WaQ6p8y(!@Q%{G_yCzK;)EMWWnSI&)3A`aX)^Q zE1zY)y61dh82oG>psI40kO?YH%hBqCh zP`@oUDTMVVWeJ??<$mQIQZsX*Bw{~lkv_z;#pk_L`VJt4omm1KH)M)>C)ArHxEi-GGJURf{kLi8nXE-?{oc07 ztkxf^h4mbDKvKg)8o6Jpc2}X5-HKse=GXZGVhT?)S5{1Sd(}P*ZB}n@jr~M=-H&Av zy7^J@b+)@)zzuFoPyJsG!WP#hK178y zq+ZuA?SY@bL~tU{XHoy4**LAc;v+KjLi^-U(L>P(VV4D;(@5fL1QU$7%gXC=^h&*4 zt6czHU?t{bL%GmwN>xqRH|w$2UcLM+0oIlgX2A;@Y{For@E5!JIgw~$j8J&nw{QY* z|HIe*?aS$V%YSG}#__|O7wS)2C26BQsflAYFT{k&W@F%+X2v61Z?C3Sx1EZ-0aSUn z$LbVg9mRep!Z*p)5u_@)?YAqwMQYQFHp^|(&j$k<(T8&{jAHKLuT4qr_;xp?4dp7d zdfD)1vdU;o+z9*5(?C15YAGjAPV_{<>e4oNG%u*-%>v= zHRLRGXzxA^W%Ah3d>~pU-I59(|ykPTu^TaSZiP+U>GiVx^5LJuGC5t zr(A8QFaUeEj!DpZ z--#OoV)B?5b~9488uqMn(2MP%VFzjrX{qq>VyU>8JI~9o+uJ84ZBdr|W~)1?NFS>V zsWue{n!bzpv*BB>(o$@Fx|o{WE4QuR06hVewNmC(a-FDxKVLwyo4p?5`D8*H=b1CZ zolnbzfAuE_a)QSLY=US~Glfh8Um~qFe_kjMQxUDs<2h=IZC>8uk!4cR3u~X}>_%Hv zPD*`cxN#m}w7NUfeDagr8%>5=8{;0m-Zp z9K7)m(zPotE?xu+?!UV?Fa4pUKL_3U1M%vfW{}AKFm359{MxK%Q7HJ)OJ>0WLOi zG3%87ufdWp`1 z(N4?!F($fzY!thZ&(cH+_E-pPm(v=MsTXjHo7WBeHC5-M`zBRVLdcSZVA|>`qh0FF z4-+2ff3oVAek5auTV*oO`N6v)eb(!6O!$)NV-?dNt0IyMLi-S?`cu*pHYsk0E#X&O zcTxqufxZL%)cjkvv|%nmkqDZ>L-c93y2;VfEE7Yp>jiBFoZ%05uPCL|sz25`Bk)hW z8FC@NrW~Ip^LUg;WhtZr>TAvbUPVynrj-ekw{*Qi+ppk%XQChj-B;579_@(>nVAzU zawJDo(x|Q2kV}D11M0+0FmF=fA}qUFEt69rL^P55OHY`0l;MWECxJ2YO?iPxu}NiI zU@niUc>J9kqK?cmrtY^`{;|BL7-3NtfkUx0C7$!MDwK}>`xF5kh{X$2c84&}@1NV7 zMnm#VP#9JwC%N)Z)+Kx=w8tF2M_FU1X)32w#psgNcfFi#=Fa!u*bDs5v@DH{*AtVb9(mkm?>FIbD=sT1&h3+dIP3acAM%y=&qnyG9&vM6l9?5w+^} z{$Io}FGt|g&yR5r|LYPu>Wj=c&E2*VeGIvEJ>ut7oi8B&WhUEDt^{OivH@+KF}h&( zU5gDR=KoJpY@)@)IQEGddW0_!P^_w!00nfbtmf(cdVy9K`M!I1|LzlQ^*TbSD7(*T zpIVisTbS9>4`>Cc@}S7IF=;l?zozbsU*@nH0ZlcmC)J%NEpCtb@dU{$4a0K$34Ek+ zWVt8{4p91F!2&#;`9s%F$noUs3m(bqv&m4rt=>JwrlO&$^cZghnin_lEoeo&ar^@4 z>}#MS|BpxJN6B6-^A)&K1`F=q4R#HaTE(!Y&Fw!w-s=ivNhssCW+aDnytABmJkhLT z!dJw^y(g*I;W4R+!T8Mb@5;RkJ2rWF=XoaPxdgNQVC4=P77&p!*grm zJm|(ffUw_~r<3&3Us`=k+@3x3C3%?q7_S@CO4{WPS8+Hqw!1PU1+-+gti|KAJGXM} zj!sICrq$>w^|LC6uMMvi$r&|I{oMWM?xOxhjr_H+UR>Sxxl?5Db-4H`AX@g_MugnqF86v_g$j4t;`VLqmYp z0PX61;7nMMC-Xmh^s^u5)y|_H90#Z)cg2M|feT41D#u8-)%He;2-+_3jNgI^eBvL_ z|AxKnEqf{nUB$Vvo5TkdPYpVcdSBH0dGvHtBmZ}aPZ5f+(uaL%y$VK#n8}fx=Bb?* zpyK$9BFm-jM#$4}U~W!dL9k-%v%J$_tw84JK&{7EcZVQMFZAlk=G#QZ0lBf!%}rCj zl@9g`j)KEGzzjzcaAXo|)~Q*Ox)0*91aA`Dc=e=e@kcJqa}Kz_G=s#*mI@^j3_&AG zo!Ai>Gs|fWG@K7U$AY%hQw}1`y-g~Agi=UtRl+4awSy#E{SN&7V6f5N2e$p9byH9^xLfZ;u%&uAlDn%TDn!4k zC?IQOy>d@FVQKAkpN$^D)mLvsmuVvu9U^1bMj-jgB&#!6U~>0q+7plSUaR+ptsfP= zMX9F*0kSG4ozBngf+k z#iKc(^(e>SMV0&Vpte#pTW8<`csL|_%4i+h^&8m#^`m>WO`WA*#IXQ5kxO}-$>Cojo zlIz7&Ry@(?ec?)4c%tTfCmwmiGZe_GMN2C`JX{Yc^7z3bo*@)$uUE~kE6boN=J1#~ zzidRAGI+tArCq+0iuWEG9sMBO3tS7pLzG{$^WQr-ya7Q%hbS^XPIOVUCSR-i+CEd$ zybHmf%x;@#VlIvGbbQ=W^S4TFN{1wjC-N#@hPzkpHuK;!YKnsHkSCVrD#>zKk)ZOS z%i6`8qbsj_bjiyzo5t7aHy2vD)G_*0y$2zCu3gyI?bcQ4HX*{>+|=XU5p3@V?aoJg zVQ1GtC6~1O890mMbj91Y)#pbLnG zpmO_R*wNlw`WOYH4AVP6tHgG-m3xvyVuz+jvP(sWy%ZY;L+Y&x{`TyAaJ3`Stx>P!(b-9EqP zsCqx!(^}u!_bPSddvs8EFPV-Kxj{bx#?8OO`^0}WCrIzunk$+>fY!UCMT|w*DmZTd zU7Cz)Ya|pG%#Zo1#n^_ZYJo4Qedu`Vt!9NTHmagDGq)%}uz^>J(jUhpO~5_U=C%Vy zJJHE?=~!T-MoU0C)>Fp7*r1yHHEhRxNAc5{7uB}bLiCFgJmOEE4E(g79@aZfrO`@j zD$i+C`3%g%fGPJuG31=l)c2yQ`m8r#A3z^RwvXKZ0>OmRPJ50v9syTKNcyxQA7xaM zHSL~K?!dj)yFj`QIt|3PJ8vP*cv6~P>YV%2@#fLW+Y6mXDkCpr)}8Cyy6e4VBIl3Z zH<;n{va<UE%_1N4&n2 zbM4S_{dA7tGH~x(BE3>8lc#gc#Be%|F0(Ql%Kg9g&ikv$rG5871QkWy0v4)nw}2oZ zN|7$06zL^FLKBe|dKW@30v2%71?fE@bO=c(iUONnLnxsrMvxW+0@BaK{l4FG);j;d z`QhXj*TVJWnP;AvduHzYb6sITtzj^7EZx>W(#v0Nm0J*cD5+Mi0*XE@EY$S3#E#9t zKJ|*fiD(nO{VAoJWgYo%8+}(MK2-QXT`yHj8f3`*MD3Z(TGl!kXda0|{sB;w{sq=J zMFe`{WD02d14v)Q0i7fJPK_zOcO!?@w;rGVbD~86nn2tMyrP_Od(2 z_V8edSRNNu#sI0(c#4Ykbw2P4lFh8uK!Lr9muLH!pB|65V842zeLxn1@{)fc1sP&8 z|I;u6Tc7Tbpr;;J8fL?etoO-;MwxNAsJEP`wZ{+m{;94!It6Rd8m+K$Gco8Snpn9| zwK%BrS;)TN<#sMNdFn*PhceB=z!tWbIxNC(yLF_elC~9VqcqKlJdiH%MCa2{=Qslc zL13v*KE;||``&DCyLFv9KfLEUdz~}1H2wTv*z_;+$6l(ajU9x>pe`<{W&s%r*1$=-WrE%Q@)e98pwIyeQE>fzUDQc84D zSGK6YRI-v1O0r~==JPdc>1$Itn`6x|0VWRwQ{&e^H!i7@3g@i^zKvvtKHlYhwzNZ{^Z>Hm6 zVrxR@vt=qeXGX7W*KO0Nl`jVrAeL z+aq(Y)0u~zqzjkV4OmOg1u%X~4gPzJxyN2<<{b~WuyZzNw^Ym!gkTTtGXI71>zS9f zgu|HFO+m+u4q6)i$QlG?;Jfnj=A+e{f0fMNpx`8wN!aNzA(}1~{&N&SUn<({c@}K# zgMVy`SA1R8nRd+3^vjOD<#6e1cn!bNY1*KBi`Ju`eR9+>e%r&)Y&V}|Au3Bpc}ons zAeyy1VBhtrsa1X_!$F@rs}!vYZuyWYM+)STBJ}^v8+)YYGfsQSyXwlcigraHK-8n@soY4w+<&vUvL)=Ify}l3QRhFzo z%rWUMp6j}GuRRt`Jir02bo{odB* zR>gb7jsvY(ubu70rJ3SW&$bDgElQhpvZbmmuQolVLJap}|K;%>I)2D~8OAkod=R1` zarqRdH||N9assn4XJgXP8>tyf55Jx?-fU(al!HU%x8hTfkV>)bz?IU=PaG@DP{!B5 z3RLQUKqCn-hY0Fnpg4{=nt2>*+|=H_*n*b3S5{n3p-tqEk$fw%XSfc!GH#n+ z-E#Zl(cNPeyh91MLf=L^;e#3B$b-Fg+7*V-z{`aUCv_r{0z1m?;r4Q&ruvl^k3MKJN<#B} zd=a_2Rp5CBLv@gQ``ts5X+v|v2dMBYv8zkS6Pee_!?Kud>n@a?9$bX53PL{`w{cNQ zlZCc{L}U44Sc!lhS=@SpOVMfcmeIMzCRKmM^rS&p!VRqy?Nfs71L^IV~7|CCR z;7f9}h&bKp$GWv4J+e9Mqld(A4E}sJVOcPL2wBIIZbqr# zTWgtR4!f$*8V<3RxrGy;rAMTBUQ*toYH4OyA_|Ko0c3gXRCEC9iEbUj1P7EX`9(G# zM@r41u2H!G_xQ{HkWD%P`ZMH~ z7M+N6m2Sc-k^XLzUU!S32;+$_GB=Gs4)!ZE_HYQpE+-YILtRONm<0L~YfH$AJ2jlJ zp5joC6L^7kU3$L={{mxA{*-BKP+};8Yq4h^I;}H+r_3o^n{Do?3FmvOVF`Sh&AEsm z#U1{4r!hUpAW9%#l@KM9E&DP|qYA4+VpSEk}Bz{Kw^m}8joor zg6+MuhgV0WW5x3XxkR(7(tc3OHdvY6X zfHm}|^Ev9q6qvmw58I3N&!!aEKhR{{g!+`Dr&{vXZS{TPOSMJ)a-$Ox{wX8heIcP< zzpnsu7rC`8E@;IKb%kPyf;twhXq|pGfJYlLN)p}&z9>b4WhM5?mMi1^pnu7s*-;N8 z34LL3#VUY-xjc*U0NC~V-c!Y~TClw1mUNa9FeUo9GIUW2GC~LTN3Jm8r>89^@4vBW z?Yd-}Y?i$8^XJc-3V@9jaUqFY%bt@z#X7R-l?FX%W2o|^qf7wgp|gF9`u6q$9g$GM zE+K5nNszb07-M;O*!U6OU`s#~;N@`uYp5H#pZM(7jT8R^VV%kkgYV>(coL3|5Wf8V z>i?y_QUF9ckZYc36ARn0AUG6)vr!s z`*Y;2(PS1Nc4n#2EOnKud#;@(o0KgB4dLmM+yS7to?biyWJHX9qmxivJe?@Awq-G+ zjQ(L}xb$Xd9q{|auB@YeU6OsYXOs)HUQSL9NacTXe98{-g5W(CJx(^e1|_bH*Vtzi zpz3T|<9JG2K!f5O;+5VEL2?ekCMhQj;9(9qu&k$0SEidHQ*KULzA`WLAG47O+-+I8JexLZ0|1i6uU``SIs8WKNXwMd` zg2JGnNGyG131K-)pdiC5sf|uOOGzgi&aN&k0oSK?x@{YCA*kj4o*{E6GT(CFs+aB} zVDB9~)%yQNEbmklpQV5Z6c7YpS@F(!T^@*OFJvlf~R|di;BfDP*wL6~@?R!47 zj9RUMn>RHDb)m_$fn4%$>?oE2BEd@^F!wS~lrbY%rcU--)h(ONJZs(=cBC^5+D1l2 zq7k59I*obQVCQ(c>i&G<;1E;z4Uo?uJcY*Ew32_q1aDap4L>4>BYNq+RZGA{jV5jl zZUVd};5;Ab{Z2=ZA(OH2+)!pjTU06Bce`-$&U5r9klQv|h%+0KOIq>=u&#-@M-*t1 zC}`4$#g!FGTIKmirSRQ|?Y7hr^|jG&uTzrIvGDf^)475DSqfV+D)b@d40<56@O)`G zg@r{z|1``Mv}F%e=UpP|3Qo8&X{_uh1#FhY8YRdjp>wmcgqHzXOc#}~vD3lbj!265 z?c4eWL{FGW&~a+%J^ovr;4xXgCTNM~;#naeq(b@(l9A)pwo>j!lq_wi)EF<*$Xb-dVJoIct`Mg%MQWA zYjfsq(I^-jaXhbrQ$B#Di~0x#j<6v*u&N|($Sl2K^I(jxK#RiQDQLK_pI^qkUlH4l zmNu$>m=kVLoSdvIfUZl>WX%=*^7+^}-MRnX^u2nAlA{v#*n@l{qT$gwBhX0r8m!K$ zBl6+YeI2c(MBl@Dr;_4MAqa#U^zhZU$BIDr$2dG=nM6I-wf)`1!wip&FRK%$rx7`H zrwonXaaNWf(D|Q;=}sRmSKo4$h=83lbDx?^PSMrUQ_+Z(PTC3Ts-n%=#=EYEzn-}; zQGdtJl|(&7aRW_ww5R0AFu*Nc86k8Y6XNgK?|Ge%ZEKZ4ohYOc%i;LhCXgicBKDT1 zgL~H&+q6n38{8!22JW6oJemI5)9h@?f3IZ%z4uk#3wIHRDm>)vM0RaJLAP{BxxXv@CD0+U=_yid9ph?XVxX|-$jN6@={U5dIC#OO6`O((C z09b&WN=QJT0D+tYzzKxCP^bdc^o9<_0+g-(8t*UCLIf5Z zbaPBp-%LP9I)ZzJKRdx_IdmI6|HNHTyvyZiVgGbZ^Qq;zx!ncWoh;AUp3 zd~8y|c;9U|r)~xiQU4>^dl)8{*!fp;*aXlPmcRq>dvyP;!4p)vh#v%^t$nl{Zp)pt znBWP;%79G`otuH=+?rTg<}A5EOS=sfA&$L5QDhEhr(|o^XEF1dK(jC?(QSkYUZ%EDWQ2bR(h(4qEqx!zXq6im3Ai7f# zdxhT?0-@03i%{OxJX=afJfF0t3h~Z+Q;VBk8$roTZai#K$Sr52s9!UP7r~D+x;ts| z2FY1AAO7b$-4T}S6Q?uTjYYIf9M@c(oN7QkLwk~*(mRm)Qn>s!1d>E|hbnnI1m-%? zu=}47l? z={J*S557~|SIlx}F|#OU1P;0i2Rj^&^8unYz=G(v@bl^gO&R{zDBIfok4Vdko1BeM z3c!PHY;4&0&~0Za5+jU|2lSyI6Nw_DIECFwh~x~EZQwc+^_-vHSiwM))9<(&e@9SB%)NWT1-`QMg-7JX|8Cnz z&%3)T!LCfHaAjh30DB|J6>%qn7u+a*HCxd`J1y=aI_d+a=9{GHXS!gTZoPEXljRnO zBwq?I>erPu=gc54k^%uA29cgSdB%TvSF&`b-{K}6IH?GCI40+h`m2TpG#w4 z_vTBTb}0gP|5oxHadKPU6bQx{03uHBw6YZNwz*1lzyi+VW-OAJ4@X}!S5@$nx(9(6 z&?Q<=3m4ao`PhmEiq^oZkU>>(eg!IAdjEX}h$(O(I|k;zQQfmNlaXoR)cL5U z^avK9Z3wxmo-XC`VvDJVE-xrnGv_XD_#j?^4s*$fnhW4ZJQp z3;A%V4_F|BjkE;uK!g!;YQ0|xN#a@#Hr(`m6=46aB51xV4{LOJ%OoeByYIzZqClTE z%CfGvk?!CO`?%N1^Oz9kaRfmAp!kQ`gp%2yHXVlf73@shin+5%oq6@MSmir6A={gq zX+V7rknp(sWt9q0RvNnE1?*#z~rrP&wsxrw&mPPce$&K=W}Pn1y@?R zjBv~C{{I*Nzh$pi71`@a(>ETR-dY|2<&vDoZhd$$pA5p$m-NPMuWtjfjl`-;(&uz{ z_ke#c1~EIDwMdubTy_FBEc}nk5t?JV&Gbm;!m#U)Li#6d$`1xrnAWswGwD44fgcpd z5|iedTXrlK`Z)-&g@E(kV3o-{;v5pMpdYUPpcnTw=w{5CA*5+_k&atZ|Mc1e6YR+_ z%a=<|QFGnQ zACV!`OZM%r9@x&mF~1}wT1`b87E;it_ITjS&AiJ&0uCjp_ea0&mJhVFiW7k5+P**Q zAJl6ji@FE<5?At{a8nQ`U1WZJOVsPBBUw5nd_Bz8&RQ5QATv;D7=7}Ore-bEs%mfB z`OkZBm1g^nm?pag&b*~a#Tjuiv)GW?xJze%a~+s(f{9D37zQ+cTSyR?hXnVF(nhiu z?;N&OY$bVKlF~i`A`vMELPy@-P>|c&>e9a+%&|A9*GSDB_ruJ-bV!y9(F+6bWvzQ| zT79DRX&Kq=;@TLb8U;!bvF@AXlQo)N z1JZj_3BM5f*Kdi4nCQcPZArHqKA+ezZ09DwlTwwVZ7=_0^+hwci;4Qf<>qh`IZY-+ z646(iEfLaGk7q4C-=u=Rc6PNVEeKd7~|8CIX zN0h{f94W1A{{u#|Cgf0zId(@X;5T`TgMC*eR*Ygu*H7 zhPmhF?taRqNJ7X#jbHWDn={_9U)AlWq_z&t_8)sH!tO$&c@gYB~b&Kr%pdc_Y@N{dVDe( zCw)0b{y0L!_)jP1{@0*cTmfxl*Sn%qM4;}^$M7Rw%t+gPMwSCj)mE19hPHjbb4{g! z%|%hYccov2Is=06B!}}%4p9~cCl4pE{h8i5E`P4m+^jsNyDl;LW1i8)6S=Uq28^)P z_G-(@vZc#Gsmm>3FVoL>0uo90`n(|MjDGr_=N@*#&XM!JuspiEg1H5u&A!;IC~r+w zPqvSGhHWwAaFCQXYSWCEyRDN*zG@k<$`CP zMhswPj6#LDWALIn<5#B%`0=uq?$eTtS2lpJ-^MS${^z-qr>8AXss_2EuTAfhRKK^G zwCe~ZRw>O;q@~88XLrUp&Rd=*c{x%<+B0%~W?jz^lgQxXlbr3cwqJEBLX{xElS%dc!?%9;&gKpi;OhWzpO$FVXBRo8i^Sof? zRT;=J)oQ8pmY;lG=9A}yb8;`bioTCl-kLe;Xc3+0(XcAU<|x-Hey0X1rrf=J7Jo35 z%;P(IaJu5r7I1lflzNOHXXW?FM64#;kHONO3d2{_8tT}KN>P=(>NMYA)4l(TkY zkmR#1nGuF@G`lf_le7U|eeV!{nU|m2#reA}wb`|`Cz%pT$CFe!)&SSB74F-vsGhYR zzRl_<`EDBe6H2hUhrE?-b}HW~1~s6p)l#!pOk$eu2Zr_&iyPENr`NhS+$Xg+0|4Xy zY3ra;;CxwQaMt+GuH0Ct>~1s5jM(#SDlht%z^*xz8=@}@HWHCJ4Am*mgq@wP25c*p zy=PCda3397FBJaH&N?aD@G86_TS#a3{pnAfXPnNPmwDk*GSRzP$T%!70c9HyxFl7t za|>DFTZeq!vVEENiu7qQx4Y88*P)g0E3j-6+(_0Grlp5jNX4((vE`7;$BQL89^9&{ z&NUQ$-conNg(_Fh@dpbDQMLeUZ77_X5KVA|hRl%G)rv6FZ4p5nO7n z72Nc_IHhYf52O70aj&%^NWje0Z)$KH&`inyt~Jjio^dspFbmvceMXbI__YBuW!dHs zEyjMrV0#uOc1zfKelIK0mCD*0@(Z1@oU{MI68kzZ{a~V=Q_jR>uZ|<8hNIizQ`|A4 z%eHiei8LENQMbEAFZ&(=o+~`@Xj77_u0Y;4E5w;BWoCvG$Is`6*E@L@O`jQ8N==X6 z!;W(Z)RS7LzGUqGprJ|i&0A45%9h?P1Cjzgw2yiWmR7|@POdj`uz$Xt-iL(JMUGeh z5}~joM`)Mri;@iTTC zd+O~g23}KtNEmHo%jOV4iL*?Q<<5PeQCa*`JQ$z@~Hs(K}|0aMM7!(rxGjW1=g zQiEM9d?@kMf)!uxqRF*_4P0@|RzK=1xBZy!;np<&#y6$7$u-}NCJ95Wmth!S@!~Y0 zo0P;^@AKE#!2PYD%(hIV9a1#Pb%ipzzK#r*#pK0a@oP*`DXUL*Sc=VVnTgQ7DCqk- zbyYpl4nLE~V5Yy>MDCC%EoyfRIpQaF zZPnIyNDH{N5k*<1WV6J29$jvVqXqPJ%tR=EY4TBfbxNxuD9R-$GyRqwdVb!Hi+$Y( zQ&}wbK8X9={_vaJzFlU>`%h3d$YM-*tyw_1!u%9NvNve*o^;LpYQU)uZJk-zZ_{aK zt;mQ4q+>|A(9+bo6w((?BXuPKo&%rW_BAD8g^Ep|of5d>FSUuXZJ}|N8RbnGy4kb) zQ#;j|n#u@R!|}oDRdUlb%c3h+j3V{Wa?#UG(mJuu3jW^D>2*pXx*AjDh%XQHUWjx& zy)(uDF$LXOazD*>GA{i>n}{4F+b%V4@p7J6pYywWD*yC{yw@L?pUYu+R;nyyg0%Nn z*0|OZ(tYJ_?OoMm!i!S;O1Q^kl=j}I`jkj9`MtZN2XEeEo}=gd?ZZUp7ekx(UnKnq zY0pSAwd7*E%hJ?Vk4fszoWaZ<_*dY0ysN{@udg=Tes|aH1p_4M1z4v!1Z&B|Vw1{& z5wRJ}3y9C(QeG{I5DMgxI1*&{dW9iHwiI1zWX`y2PG}UeXfIRwb=j z8oD|mCGqy%FViT=wRK!2=EfXOXVkl3%nR6no)q&f8(Zh9LEeO9;NO>1D`9=q`k4mCKdp#H*_6L^Y!Oz;H8#%fLaWT^G*s3rMmck1Vd{)6bF zi>st}yq}Pa9lgsGbyh_87Yi3V7>V0RNb)n+So#*fWnYlC*@?}ft$}{-1oX-!|yK$>DpA(*N&%+%+5Rv^PHLSl~5vjPOu%+dsWY{x^M zuKdR-aSNrU?~YaRKg`RUZStJ^mfKg#7S*DbO@;S(f$RYNXKSwd)_IO3pfXO&L=gB( zBN|a%pKkC@7R|MIU&L;?p6JY6xH;PBHsi}<4azVv$B`iaPzC&}=`6c=MDcGUUJ;1m}p-=csl*?o$8EL7o4g8n3E?1h`V_8eI z{EzO=AKNa|HQIbG8`L{7=^qEOA#``H&$`K4(3BI6Lf?Ecy3UX-9|y0L?uQ{^CN&l* z@8g^O`cdpiFQ+uwm?e8)kLrGU4QR)7zup6NmOxiL*8P)&PS?WWMNxZ(tB|Xl`)Ujj z?O4i^QBjDN?2rQ9y7U6-c9H04iN(L(*DAikq^?tvYQpt8_Y-enr)Qqw_gH3h6M?m= z#(2{Vu!{?0q1$K+E+aIbAKm>ToTh-TlfP&FOQ@FW``Ziqj_E z?#%ZBD0E(vZ+KREVFfr*XL!p6O`R5Ne7oIDlboz~xeH7!irDG2Yd=!knggj_Xjo|a z#coM#nBR4m7yhXEkZT{WmEhFaRnM=Hwa%~g_3RX=jea?N;U=MD>SI^` zf9U{o4z-#idNgqnM%E=cPrTuu7sBH7dJCw1E*GgMp{Ef zPRwY4oUpSfKIBrJ{egu}{T#5r-M#W+JX~MM=SBz}VVzSrfi!t|BtPP$ornlfh$ciDQs^boT!m z<#Y#%_tHjkMIfay{$}JWW(w!$uAg%qy&!kEF&)p`lL}a;&oh$~6FtC7`SuSf*C#wu z?){l^ByGvesIv34%};aRM`D+!S4-lS3_q34H=dWQR^qB3Ps}h!yeJZ3@Q8F>`GdrA zGHRtxT;zty0@0}~=>sOzvTPkgYEbcM-XktqRVa>z~^6j`@^Bt{TkrOxi@$#gIfk{Lyuros%Kjuzed9=B? zIfhlK9V!}Fcd-y4OSb8eN;6#XH>o6?=6%S0Z+Zge8q=4j-4%e&MW79XQTjL6`rh5` zXvXbzVWSPZWqkG;QUXjOj{T$u)<(Qcri*KRbLS>TFPXcMqqgpx$u&e<`!AuClCvUW zq$;=FD^zlNRj%1QK2=4S&zQIx!f!)eisK_vBVY5cmN%|HVuX|^(oZnwYex*Vlq`(? zjB;$EOvYo}r>3TYEFZ$VKSJO5ayU+@H{ZuheuH5)tH=suij;z<=XTVk0Br+<|I?7V zT0OiJ?Z4`|VRQWoa=Nqxg#se4sz9$>CM0-b-ERB^BxzTT-yIP;s zAXLAqN~$CiWuh#XT!-{YpB}+zko(u^XPA?Vs~H4sGsefPy2K|Mj01shUT{xIIlM*f zdGL`S3Ng$byN3XtS@Dn8@}y$NY;OMLXZ5_fgIzLenJxn$xpa-WOZ-x6mp^cyU>5LD z-u*vprK{%y*lM{VPEU__rqud7X|*#u4SL=0e>M2GSN|VO9twJ{Yp8D)sk&2MpIhJ$ zLztWREq)Q7nY-S-dugPO@_8zHn&k69S;p!%OerRZTG*+06qy~4)8!kuuu=KNlyudC ztM`JHCB8AYyVw4(Ez-k5T5I_~vOpV17&Gag zex!w4sf3Fw6LrFC&7OKf0|$#vwOw@YsW5>n3-E%@h=7T$V~}JzO>}%eGh}MoS&8+5 zS8Act+ooro3HlbTbZPL3>Ngr6@q~Ve{|^~Z#;H@O@QE^nVra4^H%xP-u~*V9_b9h| zMZk-U_7gSKj2r zKNR;U>e>e0<$Ze%DnYJeu$+E{*bhzZJPPG1q*#~9`f(-b-y|2G5Ma$;9i-Gnl!WNV z)2He&Y?3)o=mGRv2vopIL&TT4{HS@qTaTmuMoHccpj9O;^f0aD>~$5owyz!@SQRVp z0tWsmByzsB{+E>>+N7dBWU)5fa7%kWk2=B4ayIvf zr1D3&nbjuM!wk;8<-4#!Rd;7Yju!MNAbQCRTDOIuf)WZ-CORAW8!+^P0uOyrLC0SrEUdK9b zE)2=J4Z_ERTUIyVFQaC2KBA9dTTUfd4O9kY`x>C(h<0up#3}eYS@JC9&84`%6ze;dM#XZ%a~4zdMB= z&pBi_V=&UtHiLu|z$bK~Oi@30krtX~YOIraNkZPv~WdEA)RM=Vd?_&_CkzT`~Ba jXZ-(v_B+wj4M8AUJP1S+{}(;* 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 diff --git a/src/components/MyPage/Card.tsx b/src/components/MyPage/Card.tsx index d8aab70..60bc5bd 100644 --- a/src/components/MyPage/Card.tsx +++ b/src/components/MyPage/Card.tsx @@ -1,7 +1,7 @@ import styled from 'styled-components'; const Container = styled.div` - width: 100%; + width: 300px; height: auto; padding: 20px; background: ${({ theme }) => `${theme.color.white}`}; @@ -27,7 +27,7 @@ const InnerContainer = styled.div` const Title = styled.div` align-self: stretch; color: ${({ theme }) => `${theme.color.gray800}`}; - ${({ theme }) => theme.font.desktop.body1r}; + ${({ theme }) => theme.font.desktop.body1m}; word-wrap: break-word; `; diff --git a/src/components/MyPage/PersonaView.tsx b/src/components/MyPage/PersonaView.tsx index 7dc6151..6f3dffe 100644 --- a/src/components/MyPage/PersonaView.tsx +++ b/src/components/MyPage/PersonaView.tsx @@ -1,10 +1,22 @@ +import { useEffect, useRef, useState } from 'react'; + +import html2canvas from 'html2canvas'; import Slider from 'react-slick'; import { styled } from 'styled-components'; +import { personaAPI } from '@/apis/personaAPI'; import DiscoverImage from '@/assets/myPage/MypageDiscover.png'; +import { DownloadButton } from '@/components/DefineResultPage/Button'; import Card from '@/components/MyPage/Card'; +import { PlainButton } from '@/components/common/Button/PlainButton'; +import { PERSONA } from '@/constants/persona'; +import { userService } from '@/services/UserService'; +import { DefineResult } from '@/types/test.type'; export const PersonaView = () => { + const [defineResult, setDefineResult] = useState(null); + const [isFront, setIsFront] = useState(true); + const captureRef = useRef(null); const settings = { dots: false, infinite: true, @@ -14,11 +26,53 @@ export const PersonaView = () => { arrows: false, }; + useEffect(() => { + personaAPI.getPersonaMember().then((res) => { + setDefineResult(res.payload); + }); + }, []); + + const handleDownloadImage = () => { + if (!captureRef.current || !defineResult) return; + + const capture = captureRef.current; + + html2canvas(capture, { scrollY: -window.scrollY }).then((canvas) => { + const image = canvas.toDataURL('image/png').replace('image/png', 'image/octet-stream'); + const link = document.createElement('a'); + link.href = image; + link.download = `${defineResult.name}-${isFront ? 'front' : 'back'}.png`; + link.click(); + }); + }; + return ( - + + {defineResult && ( + <> +
+ {PERSONA[defineResult.name]} 조각을 가진,{' '} + {userService.getUserNickname()}님의 페르소나 +
+ card setIsFront((prev) => !prev)} + /> +
+ + 자세히보기 + + +
+ + )} +
@@ -26,21 +80,16 @@ export const PersonaView = () => { - - {Dummy1.map((item) => ( -
- - - -
- ))} + + + {Dummy1.map((item) => ( + + ))} +
- +
@@ -66,7 +115,6 @@ const StyledInnerContainer = styled.div` const StyledTopContainer = styled.div` align-self: stretch; - height: 1381px; flex-direction: column; justify-content: flex-start; align-items: center; @@ -76,7 +124,7 @@ const StyledTopContainer = styled.div` const TopContainer = styled.div` align-self: stretch; - height: 706px; + height: fit-content; padding: 24px; background-color: ${({ theme }) => `${theme.color.primary50}`}; border-radius: 16px; @@ -87,19 +135,44 @@ const TopContainer = styled.div` align-items: center; gap: 24px; display: flex; + + .title { + ${({ theme }) => theme.font.desktop.body1b}; + color: ${({ theme }) => `${theme.color.gray700}`}; + .highlight { + color: ${({ theme }) => `${theme.color.primary500}`}; + } + } + + .image-container { + width: 210px; + height: 340px; + border-radius: 21px; + box-shadow: 0px 0px 5px 0px rgba(0, 0, 0, 0.13); + cursor: pointer; + } + + .button-container { + display: flex; + flex-direction: column; + gap: 8px; + + svg path { + fill: ${({ theme }) => theme.color.white}; + } + } `; const BottomContainer = styled.div` align-self: stretch; height: 627px; + //flex-grow: 1; padding: 24px; background-color: ${({ theme }) => `${theme.color.gray150}`}; border-radius: 16px; overflow: hidden; border: 2px #dfdfdf solid; flex-direction: column; - justify-content: flex-start; - align-items: flex-start; gap: 24px; display: flex; `; @@ -128,30 +201,36 @@ const BottomCardContainer = styled.div` width: 100%; `; -const StyledSlider = styled(Slider)` +const StyledSlider = styled.div` + width: 100%; + .slick-list { - overflow: visible; - } - .slick-slide > div { - margin: 0 10px; - } - .slick-track { - display: flex; - align-items: center; - } -`; + padding: 5px; -const CardWrapper = styled.div` - flex: 0 0 300px; - box-sizing: border-box; - padding: 12px; + .slick-track { + width: 100% !important; + display: flex; + gap: 12px; + } + .slick-track:before, + .slick-track:after { + content: none; + } + } `; const BottomImageContainer = styled.div` - width: 988px; - height: 393px; - position: relative; display: flex; + justify-content: center; + + border-radius: 16px; + background: ${({ theme }) => theme.color.white}; + box-shadow: 0px 0px 5px 0px rgba(0, 0, 0, 0.13); + + img { + height: 390px; + object-fit: cover; + } `; const Dummy1 = [ From 118206c81209df078584c54874002d68f619ea1f Mon Sep 17 00:00:00 2001 From: aaminha Date: Thu, 23 May 2024 21:11:42 +0900 Subject: [PATCH 15/25] =?UTF-8?q?fix:=20QA=20=EC=82=AC=ED=95=AD=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 --- src/components/DiscoverTestPage/SpeechBox.tsx | 3 ++- src/routers/router.tsx | 8 ++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/components/DiscoverTestPage/SpeechBox.tsx b/src/components/DiscoverTestPage/SpeechBox.tsx index ab60a14..b7ceb1a 100644 --- a/src/components/DiscoverTestPage/SpeechBox.tsx +++ b/src/components/DiscoverTestPage/SpeechBox.tsx @@ -2,6 +2,7 @@ import styled, { css } from 'styled-components'; import ChatBotProfile from '@/assets/icons/chatbot.png'; import { ReactComponent as User } from '@/assets/icons/user.svg'; +import { userService } from '@/services/UserService'; interface SpeechBoxProps { children: string; @@ -11,7 +12,7 @@ interface SpeechBoxProps { } export const SpeechBox = ({ children, isUser = false, isContinuous, isEnd }: SpeechBoxProps) => { - const userNickname = '유저이름'; + const userNickname = userService.getUserNickname(); return ( diff --git a/src/routers/router.tsx b/src/routers/router.tsx index 6f1bcc8..e5d9820 100644 --- a/src/routers/router.tsx +++ b/src/routers/router.tsx @@ -61,10 +61,10 @@ export const Router = () => { } /> } /> - - }> - } /> - } /> + + } /> + } /> + } /> From 397e8779629e19c3c0b16a38c87a3868de0983f4 Mon Sep 17 00:00:00 2001 From: aaminha Date: Thu, 23 May 2024 22:07:21 +0900 Subject: [PATCH 16/25] =?UTF-8?q?fix:=20QA=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/assets/icons/lock.svg | 10 ++++ .../DesignResultPage/ResultView.tsx | 2 +- .../DiscoverTestPage/SummaryCard.tsx | 2 +- .../HomePage/RecommendSectionTemplate.tsx | 2 +- src/components/MyPage/PersonaView.tsx | 57 ++++++++++++++++++- 5 files changed, 68 insertions(+), 5 deletions(-) create mode 100644 src/assets/icons/lock.svg diff --git a/src/assets/icons/lock.svg b/src/assets/icons/lock.svg new file mode 100644 index 0000000..53ca682 --- /dev/null +++ b/src/assets/icons/lock.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/src/components/DesignResultPage/ResultView.tsx b/src/components/DesignResultPage/ResultView.tsx index b7821a6..c828334 100644 --- a/src/components/DesignResultPage/ResultView.tsx +++ b/src/components/DesignResultPage/ResultView.tsx @@ -62,7 +62,7 @@ const StyledContent = styled.div` // 디자인 시스템에 없는 폰트 스타일 font-family: 'Spoqa Han Sans Neo'; font-weight: 500; - font-size: 48px; + font-size: 36px; line-height: 48px; color: ${({ theme }) => theme.color.gray900}; diff --git a/src/components/DiscoverTestPage/SummaryCard.tsx b/src/components/DiscoverTestPage/SummaryCard.tsx index 86943b2..0c3d333 100644 --- a/src/components/DiscoverTestPage/SummaryCard.tsx +++ b/src/components/DiscoverTestPage/SummaryCard.tsx @@ -22,7 +22,7 @@ export const SummaryCard = ({ category, title, descriptions }: SummaryCardProps) {descriptions.length > 0 && descriptions.map((description) => (
- {description} + • {description}
))} diff --git a/src/components/HomePage/RecommendSectionTemplate.tsx b/src/components/HomePage/RecommendSectionTemplate.tsx index b9664d4..427d62e 100644 --- a/src/components/HomePage/RecommendSectionTemplate.tsx +++ b/src/components/HomePage/RecommendSectionTemplate.tsx @@ -34,7 +34,7 @@ export const RecommendSectionTemplate = ({ {children} )} diff --git a/src/components/MyPage/PersonaView.tsx b/src/components/MyPage/PersonaView.tsx index 6f3dffe..3a07246 100644 --- a/src/components/MyPage/PersonaView.tsx +++ b/src/components/MyPage/PersonaView.tsx @@ -1,10 +1,12 @@ import { useEffect, useRef, useState } from 'react'; import html2canvas from 'html2canvas'; +import { useNavigate } from 'react-router-dom'; import Slider from 'react-slick'; import { styled } from 'styled-components'; import { personaAPI } from '@/apis/personaAPI'; +import LockImage from '@/assets/icons/lock.svg'; import DiscoverImage from '@/assets/myPage/MypageDiscover.png'; import { DownloadButton } from '@/components/DefineResultPage/Button'; import Card from '@/components/MyPage/Card'; @@ -17,6 +19,7 @@ export const PersonaView = () => { const [defineResult, setDefineResult] = useState(null); const [isFront, setIsFront] = useState(true); const captureRef = useRef(null); + const navigate = useNavigate(); const settings = { dots: false, infinite: true, @@ -27,7 +30,7 @@ export const PersonaView = () => { }; useEffect(() => { - personaAPI.getPersonaMember().then((res) => { + personaAPI.getDefineMember().then((res) => { setDefineResult(res.payload); }); }, []); @@ -65,7 +68,14 @@ export const PersonaView = () => { onClick={() => setIsFront((prev) => !prev)} />
- + { + navigate('/understand'); + }} + > 자세히보기 @@ -89,6 +99,16 @@ export const PersonaView = () => { +
+ lock +
+
정의하기 테스트의 추가 분석 결과를 확인하고 싶다면
+
셀피스 프리미엄에서 만나보세요.
+
+ + 셀피스 프리미엄 구독하러 가기 + +
@@ -227,10 +247,43 @@ const BottomImageContainer = styled.div` background: ${({ theme }) => theme.color.white}; box-shadow: 0px 0px 5px 0px rgba(0, 0, 0, 0.13); + position: relative; + overflow: hidden; + img { height: 390px; object-fit: cover; } + + .blur { + width: 100%; + height: 100%; + background: var(--modal-bg, rgba(18, 18, 18, 0.36)); + /* blur */ + backdrop-filter: blur(5px); + position: absolute; + top: 0; + left: 0; + z-index: 3; + + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + + ${({ theme }) => theme.font.desktop.label1m}; + color: ${({ theme }) => theme.color.white}; + + .lock { + width: 30px; + height: 30px; + margin-bottom: 20px; + } + + .text-container { + margin-bottom: 20px; + } + } `; const Dummy1 = [ From 2ec3e6cffa49d454767ee1fdf38a8664d6b68731 Mon Sep 17 00:00:00 2001 From: aaminha Date: Thu, 23 May 2024 22:11:09 +0900 Subject: [PATCH 17/25] =?UTF-8?q?fix:=20=EB=9D=BC=EC=9A=B0=ED=84=B0=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 --- src/apis/client.ts | 13 ++++++++----- src/routers/router.tsx | 44 +++++++++++++++++------------------------- 2 files changed, 26 insertions(+), 31 deletions(-) diff --git a/src/apis/client.ts b/src/apis/client.ts index c2b9375..956ad60 100644 --- a/src/apis/client.ts +++ b/src/apis/client.ts @@ -11,10 +11,13 @@ export const noAuthClient: AxiosInstance = axios.create({ export const authClient: AxiosInstance = axios.create({ baseURL: import.meta.env.VITE_API_BASE_URL, withCredentials: true, + headers: { + Authorization: `Bearer eyJhbGciOiJIUzM4NCJ9.eyJ1c2VySWQiOiIxNTlmNDU0Mi1lYmZmLTRhY2QtYTYwMy1hNGZhNGY5NDUxN2YiLCJpYXQiOjE3MTYzMDk2NTAsImV4cCI6MTcxNjU2ODg1MH0.Ror8pzHZ1eaUWgWsBJoihEp7xeBgw1H19ctzH1AwFntUrbU3NjrkSdBvXI9ZZy9C`, + }, }); -authClient.interceptors.request.use((config) => { - if (userService.getUser().nickname === '') { +/* authClient.interceptors.request.use((config) => { + if (userService.getUserNickname() === '') { const registerToken = authService.getRegisterToken(); if (registerToken !== null && registerToken !== undefined) { config.headers['Authorization'] = `Bearer ${registerToken}`; @@ -25,9 +28,9 @@ authClient.interceptors.request.use((config) => { } return config; -}); +}); */ -authClient.interceptors.response.use( +/* authClient.interceptors.response.use( (response) => { return response; }, @@ -41,4 +44,4 @@ authClient.interceptors.response.use( } return Promise.reject(error); } -); +); */ diff --git a/src/routers/router.tsx b/src/routers/router.tsx index e5d9820..cf4ae23 100644 --- a/src/routers/router.tsx +++ b/src/routers/router.tsx @@ -23,23 +23,17 @@ import { LoginPage } from '@/pages/LoginPage'; import { OnboardingPage } from '@/pages/OnboardingPage'; import { RedirectPage } from '@/pages/RedirectPage'; import { SelfUnderstandPage } from '@/pages/SelfUnderstandPage'; -import { ExceptPreMemberRoute } from '@/routers/ExceptPreMemberRoute'; -import { MemberPrivateRoute } from '@/routers/MemberPrivateRoute'; export const Router = () => { return ( }> } /> - }> - } /> - } /> - } /> - - }> - } /> - } /> - + } /> + } /> + } /> + } /> + } /> }> @@ -50,21 +44,19 @@ export const Router = () => { } /> } /> - }> - - }> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - - - } /> - } /> - + + }> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + + + } /> + } /> } /> From df6469d2b7a09bf90d12d7b4788f735b1839f88d Mon Sep 17 00:00:00 2001 From: aaminha Date: Thu, 23 May 2024 22:20:32 +0900 Subject: [PATCH 18/25] =?UTF-8?q?fix:=20=EB=A7=81=ED=81=AC=20=EB=9D=BC?= =?UTF-8?q?=EC=9A=B0=ED=84=B0=20=EC=97=B0=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../HomePage/RecommendSectionTemplate.tsx | 2 +- src/components/common/Card/PreviewCard.tsx | 32 +++++++++---------- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/components/HomePage/RecommendSectionTemplate.tsx b/src/components/HomePage/RecommendSectionTemplate.tsx index b9664d4..427d62e 100644 --- a/src/components/HomePage/RecommendSectionTemplate.tsx +++ b/src/components/HomePage/RecommendSectionTemplate.tsx @@ -34,7 +34,7 @@ export const RecommendSectionTemplate = ({ {children} )} diff --git a/src/components/common/Card/PreviewCard.tsx b/src/components/common/Card/PreviewCard.tsx index fd92aa6..6965cb3 100644 --- a/src/components/common/Card/PreviewCard.tsx +++ b/src/components/common/Card/PreviewCard.tsx @@ -1,4 +1,4 @@ -import { useNavigate } from 'react-router-dom'; +import { Link } from 'react-router-dom'; import styled from 'styled-components'; import { PlainChip } from '@/components/common/Chip/PlainChip'; @@ -11,22 +11,22 @@ interface PreviewCardProps { } export const PreviewCard = ({ imageUrl, title, keywords, path }: PreviewCardProps) => { - const navigate = useNavigate(); - return ( - path && navigate(path)}> - - -

{title}

-
- {keywords.map((keyword) => ( - - {keyword} - - ))} -
-
-
+ + + + +

{title}

+
+ {keywords.map((keyword) => ( + + {keyword} + + ))} +
+
+
+ ); }; From fb989535c7911e484fc6917272b6be858ea162d9 Mon Sep 17 00:00:00 2001 From: Mungjin01 Date: Thu, 23 May 2024 22:26:02 +0900 Subject: [PATCH 19/25] =?UTF-8?q?fix:=20=EB=A7=81=ED=81=AC=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 --- src/components/ExperienceRecommendPage/AdevertieseCard.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/ExperienceRecommendPage/AdevertieseCard.tsx b/src/components/ExperienceRecommendPage/AdevertieseCard.tsx index a661ea7..2da6c5e 100644 --- a/src/components/ExperienceRecommendPage/AdevertieseCard.tsx +++ b/src/components/ExperienceRecommendPage/AdevertieseCard.tsx @@ -9,7 +9,7 @@ import { AdvertiseCarousel } from '@/components/ExperienceRecommendPage/Advertis const AdvertiseCard = () => { return ( - + @@ -19,7 +19,7 @@ const AdvertiseCard = () => { Card 2 - + Card 3 From fd8be0215b46b642fab9451f9c5efd0e20dd825e Mon Sep 17 00:00:00 2001 From: aaminha Date: Thu, 23 May 2024 22:36:54 +0900 Subject: [PATCH 20/25] =?UTF-8?q?fix=20:=20=EC=9C=A0=EC=A0=80=20=EB=93=B1?= =?UTF-8?q?=EA=B8=89=EC=97=90=20=EB=94=B0=EB=A5=B8=20=EC=84=9C=EB=B9=84?= =?UTF-8?q?=EC=8A=A4=20=EC=A0=9C=ED=95=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/ExperienceRecommendPage.tsx | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/pages/ExperienceRecommendPage.tsx b/src/pages/ExperienceRecommendPage.tsx index d425232..6a314c3 100644 --- a/src/pages/ExperienceRecommendPage.tsx +++ b/src/pages/ExperienceRecommendPage.tsx @@ -1,14 +1,19 @@ //import { useState } from 'react'; +import { useEffect } from 'react'; + +import { useNavigate } from 'react-router-dom'; import { styled } from 'styled-components'; import AdvertiseCard from '@/components/ExperienceRecommendPage/AdevertieseCard'; //import { AmountBox } from '@/components/ExperienceRecommendPage/AmountBox'; import { ExperienceRecommendTab } from '@/components/ExperienceRecommendPage/ExperienceRecommendTab'; //import { Dropdowntest } from '@/components/ExperienceRecommendPage/testdropdown'; +import { userService } from '@/services/UserService'; import { SectionContainer } from '@/styles'; export const ExperienceRecommendPage = () => { + const navigate = useNavigate(); /*const [selected, setSelected] = useState([]); const handleContentClick = (content: string) => { setSelected((prevSelected) => @@ -18,6 +23,13 @@ export const ExperienceRecommendPage = () => { ); };*/ + useEffect(() => { + if (userService.getUserState() !== 'MEMBER') { + window.alert('로그인이 필요한 서비스입니다.'); + navigate('/auth'); + } + }, []); + return (
From de54233579b5cfb084565e33a9656cfb2f6d36da Mon Sep 17 00:00:00 2001 From: aaminha Date: Thu, 23 May 2024 23:04:03 +0900 Subject: [PATCH 21/25] =?UTF-8?q?fix:=20=ED=82=A4=EC=9B=8C=EB=93=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 --- src/constants/defineChip.ts | 102 ++++++++++++++++++------------------ 1 file changed, 51 insertions(+), 51 deletions(-) diff --git a/src/constants/defineChip.ts b/src/constants/defineChip.ts index 4051596..36a80f2 100644 --- a/src/constants/defineChip.ts +++ b/src/constants/defineChip.ts @@ -1,59 +1,59 @@ export const CHIP_DATA1 = [ - '남성적임', - '솔직함', - '검소함', - '소박함', - '말이 적음', - '어울리기 좋아함', - '단순함', - '이상주의적', - '지구력 있음', - '이해심 많음', - '남을 잘 도와줌', - '봉사적', - '감정적', - '사람들을 좋아함', - '친절함', - '신체적으로 건강함', + '거침 없는', + '솔직한', + '욕심이 없는', + '지구력 있는', + '활동적인', + '소소함을 즐기는', + '낯가리는', + '단순한', + '사람들을 좋아하는', + '어울리기 좋아하는', + '친절한', + '이해심 많은', + '남을 잘 도와주는', + '봉사적인', + '감정적인', + '이상주의적인', ]; export const CHIP_DATA2 = [ - '탐구심 많음', - '논리적', - '분석적', - '합리적', - '정확함', - '비판적', - '내성적', - '지적 호기심', - '수줍음', - '신중함', - '지배적', - '통솔력', - '지도력 있음', - '말을 잘함', - '설득력', - '열성적', - '낙관적', - '외향적', - '야심적', - '경제적', + '탐구적인', + '논리적인', + '분석적인', + '합리적인', + '정확한', + '지적 호기심이 풍부한', + '비판적인', + '내성적인', + '수줍은', + '신중한', + '리더십 있는', + '통솔력 있는', + '지도력 있는', + '말을 잘 하는', + '설득력 있는', + '경제적인', + '야망 있는', + '외향적인', + '낙관적인', + '열정적인', ]; export const CHIP_DATA3 = [ - '자유분방함', - '개방적', - '개성적', - '정확함', - '상상력 풍부함', - '독창적', - '비협동적', - '빈틈없음', - '세밀함', - '감수성 강함', - '변화를 좋아하지 않음', - '계획적', - '조심성 있음', - '완고함', - '책임감', + '상상력이 풍부한', + '감수성 강한', + '자유분방한', + '개방적인', + '독창적인', + '개성적인', + '개인중심의', + '정확한', + '완벽주의인', + '조심성 많은', + '세밀한', + '계획적인', + '안정적', + '완고한', + '책임감 있는', ]; From a5184a70981672fe330ef891d702f1eaac496cec Mon Sep 17 00:00:00 2001 From: aaminha Date: Thu, 23 May 2024 23:07:25 +0900 Subject: [PATCH 22/25] fix --- src/apis/client.ts | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/apis/client.ts b/src/apis/client.ts index 956ad60..7088a0f 100644 --- a/src/apis/client.ts +++ b/src/apis/client.ts @@ -11,12 +11,9 @@ export const noAuthClient: AxiosInstance = axios.create({ export const authClient: AxiosInstance = axios.create({ baseURL: import.meta.env.VITE_API_BASE_URL, withCredentials: true, - headers: { - Authorization: `Bearer eyJhbGciOiJIUzM4NCJ9.eyJ1c2VySWQiOiIxNTlmNDU0Mi1lYmZmLTRhY2QtYTYwMy1hNGZhNGY5NDUxN2YiLCJpYXQiOjE3MTYzMDk2NTAsImV4cCI6MTcxNjU2ODg1MH0.Ror8pzHZ1eaUWgWsBJoihEp7xeBgw1H19ctzH1AwFntUrbU3NjrkSdBvXI9ZZy9C`, - }, }); -/* authClient.interceptors.request.use((config) => { +authClient.interceptors.request.use((config) => { if (userService.getUserNickname() === '') { const registerToken = authService.getRegisterToken(); if (registerToken !== null && registerToken !== undefined) { @@ -28,9 +25,9 @@ export const authClient: AxiosInstance = axios.create({ } return config; -}); */ +}); -/* authClient.interceptors.response.use( +authClient.interceptors.response.use( (response) => { return response; }, @@ -44,4 +41,4 @@ export const authClient: AxiosInstance = axios.create({ } return Promise.reject(error); } -); */ +); From 9e984765655b8fed5b21d53da19a82e934b2b0cc Mon Sep 17 00:00:00 2001 From: aaminha Date: Thu, 23 May 2024 23:10:38 +0900 Subject: [PATCH 23/25] =?UTF-8?q?fix:=20=EB=9D=BC=EC=9A=B0=ED=84=B0=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 --- src/routers/router.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/routers/router.tsx b/src/routers/router.tsx index cf4ae23..79a0586 100644 --- a/src/routers/router.tsx +++ b/src/routers/router.tsx @@ -14,6 +14,7 @@ import { DesignTestPage4, DesignTestPage5, } from '@/pages/DesignTestPage'; +import { DiscoverResultPage } from '@/pages/DiscoverResultPage'; import { DiscoverStartPage } from '@/pages/DiscoverStartPage'; import { DiscoverTestPage } from '@/pages/DiscoverTestPage'; import { ExperienceDetailPage } from '@/pages/ExperienceDetailPage'; @@ -57,6 +58,7 @@ export const Router = () => { } /> } /> + } /> } /> From 2e5643b7d8bf9b470aa52a77eed0cee5513a7114 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EB=AF=BC=EC=A0=95?= <102593109+emilywin825@users.noreply.github.com> Date: Thu, 23 May 2024 23:14:09 +0900 Subject: [PATCH 24/25] Update README.md --- README.md | 1065 +++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 1044 insertions(+), 21 deletions(-) diff --git a/README.md b/README.md index 0d6babe..6c55565 100644 --- a/README.md +++ b/README.md @@ -1,30 +1,1053 @@ -# React + TypeScript + Vite +# 💠 나만의 조각을 찾아 브랜딩하는 공간, 셀피스(SELPIECE) +> 셀피스는, 퍼스널 브랜딩의 초기 여정에서 겪는 명확한 방향 설정이 어려운 문제를 해결하기위한 솔루션입니다. +> -This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules. +![1](https://github.com/KUSITMS-29th-TEAM-D/29th_Semi_README/assets/113084292/10062d76-7829-4597-8201-83e385bf7920) +![d23](https://github.com/KUSITMS-29th-TEAM-D/29th_Semi_README/assets/113084292/8cd43206-5b8b-4cc0-9983-ddcbe5e0d3ba) -Currently, two official plugins are available: -- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md) uses [Babel](https://babeljs.io/) for Fast Refresh -- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh +
-## Expanding the ESLint configuration +## 🕊️ 팀명 -If you are developing a production application, we recommend updating the configuration to enable type aware lint rules: +### 팀명 : 쿨피스 (cool_ps) -- Configure the top-level `parserOptions` property like this: +![팀원](https://github.com/KUSITMS-29th-TEAM-D/29th_Semi_README/assets/113084292/d8b34c94-6e95-4e98-b0f2-fa106fefd094) -```js -export default { - // other rules... - parserOptions: { - ecmaVersion: 'latest', - sourceType: 'module', - project: ['./tsconfig.json', './tsconfig.node.json'], - tsconfigRootDir: __dirname, - }, -} + +### R&R +
+ 저희는, RAIC 기법에 따라 아래와 같이 R&R 분배를 진행했습니다. +
+ R (resposible) 실무 담당자 : 실제 업무를 수행하는 사람

+ A (Accountable) 의사결정권자 : 업무 피드백 및 to-do 분배 등 의사 결정권을 갖는 사람

+ C (Consulted) 업무 수행 조언자 : 업무에 대한 피드백을 수행하는 사람

+ I (Informed) 결과 통보 대상자 : 업무의 진행 상태와 결과에 대한 보고를 받는 사람 +
+ + +| | 업무 내용 | 민선 | 민혜 | 수현 | 예림 | 민하 | 정민 | 민정 | 상호 | +| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | +| 공통 | 팀 운영 및 문화 관리 | RA | C | R | C | C | C | C | R | +| | 운영문서관리 | RA | RA | R | I | I | I | I | R | +| 기획 | 가설 설정 및 실행 | RA | RA | R | R | R | R | R | R | +| | 고객 리서치 및 분석 | R | RA | A | A | I | I | I | I | +| | 핵심 기능 정의 및 flow 제작 | R | RA | C | C | C | C | C | C | +| | QA 관리 및 실행 | RA | R | R | R | R | R | R | R | +| | 사전 배포 및 데이터 관리 | RA | R | I | I | R | R | R | R | +| 디자인 | 브랜드 스프린트 | RA | RA | RA | RA | R | R | R | R | +| | 화면 설계 및 와프 제작 | R | RA | RA | RA | I | I | I | I | +| | ui 디자인 | C | C | RA | RA | I | I | I | I | +| | ux 디자인 | C | C | RA | RA | I | I | I | I | +| 개발 | 팀 업무 관리 | C | I | C | I | RC | RC | RC | AR | +| | API 구현 & 연동 | C | I | C | I | AR | AR | AR | AR | +| | 이슈점검, QA | I | R | I | I | AR | AR | AR | AR | + +> 저희 팀은 ‘나에 대한 근본적인 이해’에 대해 끊임없이 고민하고 싶은 팀원들이 모였습니다. 나를 이해하는 과정에서 치열하게 노력을 하고 있는 이들과 호흡하며 그들의 문제를 마주하다보면, 흥미로운 사업 아이템을 개발/발굴할 동인이 되리라 확신하여 아래와 같은 리서치를 진행했습니다. +> + +
+ +## **🔎 서비스 개발 배경** + +팀 쿨피스는 아이디어 선정 이전, 서로의 흥미를 파악하기위해 ‘넌 어떤 사람이야? 뭘 좋아해?’ 등의 질문에 대한 답변을 하고 서로를 알아가는 온보딩을 진행했습니다. 그러던 중, 저희는 선뜻 나의 흥미, 강점, 성향 등에 대한 답을 내리지 못한다는 것을 인지했습니다. 즉, 나조차도 나에 대해 잘 알고 있지 못하다는 것이었는데요, 저희의 시작은 바로 이 지점이었습니다. + +왜 나는 나에 대해 잘 알지 못할까, 사용자들에게 나를 잘 알 수 있는 경험을 주는 건 어떨까 라는 생각으로 **서비스의 사용자들이 자신을 깊이 이해하며 살아가도록 돕는 것**을 저희 팀의 목표로 설정했습니다. 단, 이는 팀의 내적동기와 목표에 불과했기에 __관련하여 문제가 존재하는지, 서비스를 사용할만큼의 동인이 있는 문제인지에 대한 가설 실험을 진행했습니다.__ + +![image](https://github.com/KUSITMS-29th-TEAM-D/29th_Semi_README/assets/87255791/9787ef77-a763-4fe1-a9f6-a5865d579573) + + +해당 실험을 통해 2030세대의 __자기이해에 대한 니즈__ 를 확인했지만, 그 니즈가 서비스를 사용할 동인을 가지는가에 대해서는 부정적이라는 결과를 도출했습니다. + +이에 따라 **`서비스 사용의 동인을 가지는, 자기이해에 대한 강력한 니즈를 가지는, 자기이해의 과정에서 ‘문제’를 겪고 있는 집단` 을 발굴하기 위해 IDI(n=26)와 성공한 퍼스널브랜더와의 전문가인터뷰를 설계/진행하며 2차 리서치를 진행했습니다.** + +![image](https://github.com/KUSITMS-29th-TEAM-D/29th_Semi_README/assets/87255791/e0a9d8bd-9654-4d63-a414-67f08035492c) + +그 결과, __나로써 새로운 가치를 창출하고자하는 집단__ 은 자기이해에 대한 강력한 니즈와 그 과정에서 문제를 겪고 있다는 점을 발견했습니다. 그들은 공통적으로 ‘퍼스널 브랜딩’을 목적이자 목표로 하고 있었으며 이에 따라 저희는 ‘퍼스널 브랜딩’ 의 여정을 시작한 집단이 초기 설계 단계에서 겪는 문제를 해결할 수 있는 솔루션에 대해 고민하게 되었습니다. + +```csharp +* 자기이해 * +def) 자신의 성향과 강점, 수익 창출로의 연결이 가능한 전문성을 인지하는 것 +``` + +> *퍼스널 브랜딩이란, 나만의 개성과 매력, 재능을 브랜드화하여 가치를 높이는 행위로 대표적인 퍼스널브랜더로는 ‘드로우앤드류’ , ‘노마드코더’ 등이 있으며 최근 SNS를 활용하여 수익화를 하는 행위가 대표적인 퍼스널 브랜딩의 결과로 볼 수 있습니다.* +![퍼브](https://github.com/KUSITMS-29th-TEAM-D/29th_Semi_README/assets/113084292/a78229d4-3f60-4968-8d36-c60d319cb309) + + +
+ 케이스 및 직군별 분류 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
유형브랜딩 방식
기업인 + • 소셜 미디어 활용 : LinkedIn을 통한 네트워킹 및 전문성 공유
+ • 블로그 및 포트폴리오 : 자신의 전문성을 보여주는 블로그 작성
+
예술가 및 디자이너 + • 포트폴리오 웹사이트 : 작품 집필 및 디자인 스킬 공개
+ • SNS 마케팅 : Instagram을 통한 자신의 스타일 전파
+
프리랜서 + • 개인 브랜드 로고 및 웹사이트 : 자신만의 로고와 웹사이트를 통해 브랜드 인식도 향상
+ • 고객 리뷰 및 평가 공개 : 고객 만족도 및 신뢰도 증대
+
개발자 + • GitHub 및 Open Source 참여 : 자신의 코드를 공유하고 오픈 소스 프로젝트에 참여하여 전문성을 보여줌
+ • 개인 블로그 및 튜토리얼 : 자신의 전문 분야에 대한 글쓰기 및 교육 콘텐츠 제작
+ • 온라인 커뮤니티 활동 : Stack Overflow와 같은 커뮤니티에서 활발한 참여로 전문가로서의 명성 구축
+
기획자 + • 포트폴리오 제작 : 성공한 프로젝트 및 기획안을 정리하여 웹사이트에 공개
+ • 네트워킹 이벤트 참여 : 업계 세미나나 모임을 통한 관계망 확장
+ • 멘토링 및 강연 : 후배들에게 지도하거나 강연을 통해 경험과 지식 공유
+ • 개인 블로그 : 개인 블로그나 사이트를 통한 자신의 전문 분야 글쓰기
+ • 소셜 미디어 활용 : facebook, instagram, twitter 등을 통해 업게 동향 공유 및 인사이트 제공
+
마케터 + • 소셜 미디어 활용 : facebook, instagram 등을 통한 자신의 브랜드 구축. 트렌드와 시장 분석을 통한 컨텐츠 제작 및 공유
+ • 케이스 스터디 및 웹세미나 진행 : 성공한 마케팅 케이스 공개 및 웹세미나를 통한 지식 전파
+ • 개인 브랜드 캠페인 : 자신의 마케팅 능력을 보여주는 개인 브랜드 캠페인 실행
+
+
+ +
+ +## ⚠️ **문제 & 솔루션** + +### 셀피스가 해결할 문제 + +```csharp +나를 브랜딩하여 세상에 알리고자 하는 집단이, +퍼스널 브랜딩의 초기에 '나를 이해하는 과정' 에서 겪는 문제 ``` -- Replace `plugin:@typescript-eslint/recommended` to `plugin:@typescript-eslint/recommended-type-checked` or `plugin:@typescript-eslint/strict-type-checked` -- Optionally add `plugin:@typescript-eslint/stylistic-type-checked` -- Install [eslint-plugin-react](https://github.com/jsx-eslint/eslint-plugin-react) and add `plugin:react/recommended` & `plugin:react/jsx-runtime` to the `extends` list +
+ + + +
퍼스널 브랜딩을 본격적으로 시작하고자 하는 사람들은, [인지-탐색-구축]의 과정에 해당되는 ‘자기이해’에 대한 강력한 동기와 문제를 가지고 있습니다. 그 중에서 저희가 해결하고자하는 문제는 다음과 같습니다.

+ +**[1] 자기이해에 대한 어려움** + +퍼스널 브랜딩을 시작하는 단계에서, 자신을 정의하고 강점과 적성을 파악하는 데 어려움을 겪는다. + +- **나는 어떤 사람인지, 무엇을 잘하고, 무엇에 대한 열정이 있는지 파악하기 어렵다.** +- **내가 어떤 브랜드를 구축해서 퍼스널 브랜딩을 성공시킬 수 있을지 모르겠다.** +- **자신의 강점과 약점을 명확하게 알지 못하여 브랜드 방향 설정에 어려움을 겪는다.** +- **타인과 차별화되는 자신만의 매력을 찾는데에 어려움이 있다.** + +
+ +**[2] 자기이해와 퍼스널 브랜딩에 대한 이해 부족** + +퍼스널 브랜딩의 과정에서, 자기이해와 어떤 방법에 따라 나를 이해하고 퍼스널 브랜딩을 해야 실패하지 않을 수 있는지 모르겠다. + +- **심층적으로 나의 전문성을 포지셔닝 하고싶은데, 그 방법을 모르겠다.** +- **나와 유사한 방향성을 가진 사람들의 사례를 접하기 어렵다.** +- **퍼스널브랜딩과 관련한 방대한 학습 자원이 산발적으로 존재해 한 곳에서의 탐색이 어렵다.** + +
+ +### 셀피스가 제시하는 💡솔루션 + + + + +`1️⃣ 자기이해를 기반으로 한 정체성 확립` + +퍼스널 브랜딩 이전에, 나의 적성과 흥미 등 나를 더 잘 이해할 수 있도록 한다. +- 간단한 과정을 통해, 자신의 흥미와 적성을 확인할 수 있다. +- 내 흥미와 적성을 살린 브랜드 방향을 설정할 수 있다. +- 타인과 차별화된 나만의 키워드를 확인하고, 정의한다. + +
+ +`2️⃣ 브랜드 방향성 설정 및 정보 제공` + +퍼스널 브랜딩과 자기이해에 대한 교육 프로그램을 제공하여, 퍼스널브랜딩에 대한 정보 및 지식을 함양할 수 있도록 한다. +- 서비스에서 다 해소하지 못한 자기이해에 대한 니즈를 교육 프로그램 수강을 통해 달성한다. +- 퍼스널 브랜딩과 관한 강의를 통해, 퍼스널 브랜딩을 더 잘할 수 있는 방법들을 학습한다. + +
+ +## **📊 리서치 및 시장조사** + +### 1️⃣ 목표 시장 정의 : 왜 이 시장이 유의미한가 + +셀피스는 퍼스널 브랜딩에 대한 여정을 시작한 집단 중에서, MVP를 통해 실제로 출시 알림 신청을 진행한 6.1% 의 전환율을 기반으로 초기 시장을 설정하였습니다. 저희는 시장 규모 및 니즈 확인을 자체 CVR 수치로 확인했으며 그 결과, 응답자 수 129명 중 21명 (6.1%)이 서비스 출시 알림을 신청했습니다. + +![Untitled](https://github.com/KUSITMS-29th-TEAM-D/29th_Semi_README/assets/87255791/44b7af06-bd03-4087-ad41-61506c7169f3) + + +### 2️⃣ 시장 성장 가능성 : 왜 이 시장이여만 하는가 + +퍼스널 브랜딩이라는 용어에해서는 아직 다양한 정의가 존재하나, 플랫폼 사회화와 일의 패러다임 변화가 가속화되면서 퍼스널 브랜딩에 대한 시장의 관심도와 규모가 증가하고 있습니다. 저희는 해당 시장에서 고객들이 겪는 보다 뾰족한 문제를 발굴하여 해결함으로써, 퍼스널 브랜딩을 위한 자기이해 솔루션으로 거듭나고자 합니다. + +
+

시장 전망 1_일의 패러다임 변화로 인한 성장가능성

+
+ +쿨피스_ERD_2 + +커리어의 기준이 기존의 조직 중심에서 개인 중심으로 나를 위해서 일하는 시대로 변하면서 스스로 전문적 역량을 길러 지속 가능한 수익을 창출하는 것이 중요해지고 있습니다. 더불어, 평생직장의 개념이 사라지고 새로운 직업이 생겨나면서 N잡러 등 짧고 다양한 직업으로의 전환을 통해 나만의 가치와 역량을 중심으로 업을 달성하는 주체로서의 일(work)로 변화하고 있습니다. + +이러한 흐름에 따라 자신의 가치관에 따라 이직을 하거나 기업/클라이언트에게 끊임없이 자신을 어필해야하는 상황에 놓이는, **즉 퍼스널 브랜딩을 해야만 하는 상황에 지속적으로 노출되는 케이스가 증가하고 있는 추세입니다.** + +
+
+ + +
+

시장 전망 2_플랫폼 시장의 성장 및 1인 기업의 등장

+
+ +저희 팀은 다양한 플랫폼을 통해서 개인이 자신의 개성과 창의성을 수익으로 연결하는 게 가능해짐에 따라 앞으로는 회사에서 월급 받는 사람보다 플랫폼에서 정산받는 사람들이 더 많이 늘어날 전망을 포착했습니다. **즉, 나를 하나의 ‘브랜드 자산’으로 만들어 수익을 창출하는 케이스가 늘어나고 있습니다.** + +![Untitled (2)](https://github.com/KUSITMS-29th-TEAM-D/29th_Semi_README/assets/87255791/f3411ead-63a2-46b2-a8e3-40f06031499f) | Screenshot 2024-05-01 at 08 54 42 +---|---| + +2021년 기준 1인미디어 산업의 총 매출은 약 2조 5천억원으로 집계되었으며, 그 중 광고(36%)와 영상제작 분야에서 높은 비율을 차지하고 있었습니다. 또한 디지털크리에이터의 전체의 64.5%가 자체 콘텐츠를 제작하고 있으며 부업으로 수행하고 있는 비율이 전체의 59.8%임을 확인할 수 있었습니다. 콘텐츠 장르의 경우, 라이프스타일(36.1%), 정보전달(30.7%)의 순으로 높은 비율을 차지하는 것으로 나타난 결과를 통해 1인미디어 산업이 **퍼스널 브랜딩의 주 수단으로서 개인의 정체성을 드러내는데 중요하게 작용할 것임을 시사하고 있으며, 저희는 이 지점에 주목하여 퍼스널 브랜딩 시장에 진입하고자 합니다.** + +
+
+ +
+ +### 3️⃣ 기회 및 임팩트 예측 : 어떻게 더 잘 풀 수 있는가 + +이 시장에서 셀피스는 ‘나를 브랜딩하여 세상에 알리고자 하는 집단이 퍼스널 브랜딩의 초기에 '나를 이해하는 과정' 에서 겪는 문제’를 ‘자기이해와 프로그램’을 통하여 해결할 것 입니다. + +#### 경쟁사 조사 및 차별성 도출 + +![37](https://github.com/KUSITMS-29th-TEAM-D/29th_Semi_README/assets/87255791/f804e34e-d862-48ef-810b-22514f87fe39) + +![경쟁사조사](https://github.com/KUSITMS-29th-TEAM-D/29th_Semi_README/assets/87255791/96b8e61b-d34d-4bd8-8f5a-f6504d2474bb) + +
+ +## **✔️ 서비스 핵심기능 및 소개** + +### 솔루션 가치 제안 + + + +`1️⃣ 자기이해를 기반으로 한 정체성 확립` + +자기이해_돌아보기, 정의하기를 통해 나의 정체성을 확립할 수 있게 돕는다. + +`2️⃣ 퍼스널 브랜딩을 위한 정보 및 교육 제공` + +프로그램을 통해, 퍼스널 브랜딩 / 자기이해와 관련된 강의를 수강하여 학습할 수 있도록 한다. + +`2️⃣ 브랜딩 방향성 구축 및 관리` + +마이페이지의 대시보드를 통해, 브랜딩의 방향성을 구축하고 관리할 수 있도록 한다. +자기이해_설계하기를 통해 방향성을 구축할 수 있다. + +### 기능설명 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
기능설명의도
+ 돌아보기 Discover + + 자기이해 페이지 내 테스트 중 하나로, 챗봇과의 대화를 통해 과거 나의 삶을 회고할 수 있는 기능
+ → AI챗봇과의 채팅
+ → 라이프디자인 기법을 기반으로 구성된질문
+ → 4분면 시각화를 통한 자기이해
+
+ 라이프디자인에 기반한, 챗봇과의 대화를 통해
+ 회고에 사용자의 부담을 간소화 하면서도,
+ 자연스럽게 나를 이해할 수 있도록 함.
+
+ 정의하기 Define + + 자기이해 페이지 내 테스트 중 하나로, 홀랜드 검사 이론을 기반으로 설계된 질문과 태그형 답변 방식 제공
+ → 테스트 결과 유형에 따른 조각 카드 시각화 +
+ 홀랜드 검사 이론을 기반으로, 가벼우면서도 유저에게 신뢰있는 방식으로 자기이해를 할 수 있도록 함.
+ 해당 기능을 통해 흥미, 적성 등을 파악할 수 있도록 함.
+
+ 설계하기 Design + + 자기이해 페이지 내 테스트 중 하나로, 내 브랜드의 방향성을 설정하는 기능
+ → 분야 및 키워드 선택
+ → 플랫폼 및 브랜드 가치 설정
+
+ 간단한 방식으로, 퍼스널 브랜드의 방향성을 설정하고 셀피스에서 고유한 브랜드를 ‘디자인’ 하기위한 첫번째 스텝을 제공함. +
+ 프로그램 + + 유저가 자기이해와 브랜딩을 보다 잘 할 수 있는 교육 콘텐츠 제공
+ → 자기이해, 브랜딩으로 세분화된 추천
+ → 자기이해, 퍼스널 브랜딩 관련 외부 프로그램 정보 상세 열람 및 신청 기능
+
+ 카테고리를 3분야로 분할하여, 유저가 목적에 따라 추천 및 신청을 경험하도록 함.

+ [자기이해] 자기이해에 어려움과 깊은 고찰에 대한 갈망이 있는 유저의 페인포인트를 해결하기 위함.
+ [브랜딩] 브랜드 방향성을 정하는 과정에서, 퍼스널브랜딩 분야에 대한 정보의 부재라는 페인포인트를 해결하기 위함.
+
+ 마이페이지 + + 대시보드를 통해 유저의 활동을 시각화하고 개인 정보를 관리할 수 있는 기능
+ → 나의 조각 유형 카드
+ → 유형 진단 결과 그래프
+ → 신청한 활동 목록
+ → 정보 수정
+ → 추천 콘텐츠 목록
+
+ 셀피스 내에서 활동한 기록을 한 눈에 열람할 수 있도록 함.
+ Define 테스트를 통해 도출된 조각 유형과 그에 대한 자세한 설명을 확인할 수 있으며, 기본정보를 수정할 수 있도록 함.
+ 추천 콘텐츠 목록을 통해 브랜드를 구축했지만, 유저가 브랜드를 관리하는 과정에서 겪는 어려움을 해결해줌.
+
+ +### 서비스 블루프린트 + +![블1](https://github.com/KUSITMS-29th-TEAM-D/29th_Semi_README/assets/113084292/d22bbd6a-ebc7-44bc-89ba-bdc6118e2512) + +![블2](https://github.com/KUSITMS-29th-TEAM-D/29th_Semi_README/assets/113084292/9f2ad9ea-3b1b-4e49-a04e-b35a190ae758) + +### Information Architecture + +![IA](https://github.com/KUSITMS-29th-TEAM-D/29th_Semi_README/assets/113084292/10228c21-6734-47b0-b51a-363d39639699) + + +### 기능명세서 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
구분Depth 1Depth 2Depth 3요구사항 상세 설명
소셜로그인1.소셜로그인_구글, 네이버, 카카오 + 소셜로그인 기능 ( 소셜로그인의 목적성에 맞게 버튼 누르자마자 + 다른 큰 절차없이 로그인 될 수 있도록 구현 )
메인 → + 소셜로그인 버튼 입력시 기본동의만 진행하고 바로 소셜로그인 될 + 수 있도록
+
기본정보1.1. 기본정보 입력 - 필수 + 유저 기본 정보
1. 닉네임 : 중복안됨, 특수문자 입력불가
2. + 직업
3. 관심분야 데이터 : 최대 3개 입력
+
기본정보21.2. 기본정보2 입력 - 필수 + 기본 이해도를 기반으로, 서비스내에서 자기이해를 할 수 있는 + 기능을 다르게 제공하며 키워드를 입력받아 기본 알고리즘 세팅 + 진행

1. 스스로에 대한 이해도 : 1~100점까지 선택 + 가능
2. 00님을 표현할 수 있는 키워드 : 최대 5개 입력
+
홈화면1. 내 페르소나 묘사_로그인상태 + 마이데이터(내가 입력한 정보) 를 활용하여, 내가 어떤 사람인지 + 보여주는 기능

유저는 해당 기능을 통해, 내가 어떤 키워드를 가진 사람인지 + 스스로를 납득시킵니다.

[설명]

1. 크리에이터 조각을 가진 민선님
2. 현재 + 페르소나에서 나온 결괏값에 포함되는 키워드, 조각 노출

[표기 + 데이터]
1. 조각명
2. 닉네임
3. 키워드
- + 테스트 전 : 온보딩 시 입력한 5개 키워드 / - 테스트 후 : 테스트 + 결과로 도출된 키워드 자동 배열
4. 조각 이미지
- + 테스트 전 : 물음표 조각 / 테스트 후 : 결과 조각
+
2. 맞춤형 경험 추천 + 마이데이터를 활용하여, 나에게 맞춤화된 경험을 추천하는 기능 + (최초 회원가입에서, 00님을 표현할 수 있는 키워드 & + 관심분야를 기반으로)

유저는 해당 기능을 통해, 나에게 적합한 새로운 경험을 + 추천받을 수 있습니다.
1. 분야 필터
2. 이미지 키워드 필터
3. 필터 + 새로고침
4. 경험 추천 미리보기
+
3. 맞춤형 프로그램 추천 + 자기이해를 위해, 자기이해와 관련된 세미나나 강연 등을 + 추천해주는 기능
유저는 해당 기능을 통해, 나를 + 이해하기위한 방법론을 학습할 수 있습니다.

1. 형태 + 필터 (온라인, 오프라인)
2. 금액 필터
3. 필터 + 새로고침
4. 프로그램 미리보기
+
홈화면비로그인 홈_랜딩 화면 + 랜딩페이지
마이데이터를 활용할 수 없기때문에 서비스의 + 기능을 설명하는 랜딩페이지와 같은 역할을 합니다.
+
자기이해1. 자기이해 홈 + 자기이해 홈은, 돌아보기 / 정의하기 / 설계하기로 이동할 수 있는 + 페이지임과 동시에 나에 대한 이해를 보여주는 첫 + 페이지입니다.
유저는 해당 기능을 통해, 퍼스널 브랜딩을 + 위한 나를 이해하는 과정을 거치며 실제로 어떤 브랜딩을 할지 + 설계하는 과정을 거칩니다.
+
2. 정의하기_Define2.1. 정의 테스트 진행 + 현재 나는 어떤 선택을 하는 사람인지, 어떤 성격의 사람인지 + 파악할 수 있도록 하는 기능
유저는 해당 기능을 통해, 나의 + 성격, 흥미, 능력 등을 파악하여 나라는 사람을 설명할 수 + 있습니다.

[온보딩 테스트 방식_홀랜드 테스트 기반 ⇒ + 조각카드 도출]
(feat. 조각카드 도출 로직 설명 참고)
+
2. 2. 정의 테스트 결과 + 유저는 총 8개의 조각 중 하나의 결과를 받습니다. 해당 조각에 + 따라 내가 어떤 유형인지 확인할 수 있습니다.
1. 조각 앞면 + 이미지 - 고정값
2. 조각 뒷면 이미지 - 고정 X (백엔드에서 + 불러와야함)
1) 조각명
2) 내가 선택한 키워드
00형_ㅐㅐㅐ,000,xxx
3) + 같은 조각을 가진 브랜더 노출
+
2.2.1. 이미지 저장 + 조각 카드 이미지가 저장되는 기능
+
2.2. 2. 카카오로 공유 + 카카오톡으로 공유되는 기능
+
3. 돌아보기_Discover3.1. 챗봇과 회고 + 챗봇과의 대화를 통해 나의 과거와 대화할 수 있도록 하는 기능
*챗봇의 + 역할 : 나의 과거에 대해 물어보고 답변에 따라 그때의 감정이 + 어땠는지 등을 물어보는 역할
과거 나는 주로 어떤 + 모습이었는지, 내가 이전에 추구했던 모습들은 어땠는지 나와의 + 대화를 통해 과거를 반성하고 돌아볼 수 있도록 하는 기능

유저는 해당 기능을 통해, 내가 과거에는 어떤 사람이었는지, + 이러한 사람이었기때문에 이런행동을 했구나 등 나에 대한 + 이해도를 높여갈 수 있습니다.

1. 대화 주제 _ 건강, + 커리어, 사랑, 여가
2. 챗봇과 대화

3. 대화 내용 자동 저장 (chat gpt 처럼) +
3.1. 1. 결과요약 미리보기 + 결과요약 미리보기
해당 기능을 통해, 채팅으로 + 대화함으로써 가독성이 떨어지거나 한번에 그 결과를 볼 수 없는 + 상황을 방지하여 질문과 질문에 따른 답변을 요약해서 볼 수 + 있도록 하는 기능
1. 카테고리
2. 질문
3. 답변 + 요약
4. 결과 보기
+
3. 2. 라이프 디자인 결과 + 1에서 대화한 내용을 기반으로, 4분면 속에 키워드를 나타나게 + 하는 기능 (랜덤하게 키워드 도출) +
4. 설계하기_Design + 내가 설정한 이상향의 나를 확인할 수 있는 기능, 내가 되고 싶은 + 이상향을 설정하여 더 나은 내가 되도록 유도하는 기능
+
1. 나 설계하기
2. 내 포지셔닝 선택
+
3.1. 나 설계하기 + 진단테스트를 통해 추출된 키워드를 기반으로, 나를 이상적인 한 + 문장으로 표현하는 기능
1. 분야 선택
2. 키워드 + 선택
3. 플랫폼 선택
4. 나 정의 ⇒ 나는 ---한 갓생 + 유튜버이다
+
3.2. 내 포지셔닝 선택 + 나의 강점, 약점을 기반으로 4분면에 나를 위치시켜, 내가 + 시장에서 브랜딩될 포지션을 선택하는 기능 +
경험추천 + 이상향 페르소나를 기반으로, 나를 브랜딩하여 효과적인 퍼스널 + 브랜딩 전략을 수립할 수 있도록 새로운 경험을 추천하는 기능 (홈 + / 자기이해 / 브랜딩 / 콘텐츠)
1. 키워드 필터
2. 경험 + 필터
3. 정렬 순서 설정
+
1.1. 경험 자세히보기 + 경험 추천에서 추천한 기능에 대한 상세 기능
1. 경험 + 이름
2. 추천 게시자 : 서비스 or 유저네임
3. 추천 + 키워드
4. 리뷰
5. 신청하기
+
1.1.4. 경험 리뷰 + 같은 경험을 해본, 다른 유저 (조각을 가진, 로그인한 상태) 가 + 경험에 대한 코멘트를 남김으로써 해당 경험이 어떤 효용을 + 가지는지 유저끼리 소통하는 기능 +
1.1.5. 동참하기 + 동참하기 버튼을 통해 함께하고 싶은 경험을 다른 유저와 함께할 + 수 있도록 하는 기능 +
1.2. 경험 게시하기 + 함께하고 싶은 경험을 게시하는 기능
1. 경험 이름
2. + 추천 키워드 설정
3. 모집 인원 입력
+
마이페이지1. 프로필 정보 + 프로필의 기본정보를 관리하는 기능
1. 프로필사진 / 닉네임 + / 연결된 계정
2. 기본정보 1 수정
3. 기본정보 2 + 수정
+
2. 내 페르소나 달성 대시보드 + 내가 설정한 이상향 페르소나에 얼마나 달성 중에 있는지 + 대시보드의 형태로 보여주는 기능 +
2.1. Discover결과_ 내 조각 카드 열람 + 테스트를 통해 도출된 나의 조각카드를 열람해, 내 흥미와 적성을 + 파악할 수 있는 기능 +
2. 2. Define결과_라이프디자인 결과 열람 + 챗봇과의 대화를 통해 도출된 라이프디자인 결과를 사분면으로 + 확인할 수 있는 기능 +
2. 2. Design결과_내 페르소나 열람 + 설정한 내 페르소나, 브랜드의 방향성을 열람하고 수정하는 기능 +
추천 브랜드 콘텐츠 + 내가 설정한 내 브랜드의 방향성 (= 내 페르소나) 에 맞는 + 발행하면 좋을만한 콘텐츠의 주제, 플랫폼 등을 간단히 추천해주는 + 기능 +
3. 신청한 프로그램 + 경험 추천에서 내가 ‘신청하기’를 누른 클래스들의 히스토리를 + 목록으로 미리보기 기능
1. 썸네일 (사진, 제목, 활동 + 분야)
2. 게시글 미리보기 노출 최대 3개
+
3.1. 신청한 프로그램 자세히 보기 + 신청한 프로그램의 전체 목록을 열람할 수 있는 기능
1. + 프로그램 썸네일 (사진)
2. 프로그램 이름
3. 진행 기간 + (활동 일시)
4. 프로그램 카테고리
+
4. 정보 수정유저의 정보를 수정할 수 있는 기능
5. 탈퇴하기 + 탈퇴 및 유저 데이터 삭제
- 기존 활동 내역 및 정책 안내 → + 안내사항 확인 동의 체크박스 → 탈퇴하기
- 30일 뒤 계정 + 삭제
+
6. 로그아웃
+ + +
+ +## **👀 서비스 타겟층 정의** + +![12](https://github.com/KUSITMS-29th-TEAM-D/29th_Semi_README/assets/113084292/02cac044-9cc2-4480-91e2-abcf055e99b0) + +
+ +> **타겟 유형 분류** +> + + + + + +
+ +> **페르소나 & 유저 저니맵** +> + +![13](https://github.com/KUSITMS-29th-TEAM-D/29th_Semi_README/assets/113084292/e90dfd23-bfc1-472c-a793-2057df2527b7) +![남1](https://github.com/KUSITMS-29th-TEAM-D/29th_Semi_README/assets/113084292/8a49d9ec-b527-4820-9c54-0ac6992d915a) + +![14](https://github.com/KUSITMS-29th-TEAM-D/29th_Semi_README/assets/113084292/337ebf6b-8077-4e9b-8489-d2c78a63cc73) +![박1](https://github.com/KUSITMS-29th-TEAM-D/29th_Semi_README/assets/113084292/1145b5a6-0c79-48c6-a960-eebb3584ffd7) + +
+ +## **📊 서비스 비즈니스 모델** + +![서비](https://github.com/KUSITMS-29th-TEAM-D/29th_Semi_README/assets/113084292/5bfcc9b3-8ae2-442b-83a3-a8bd982eae56) + + + + + + + + + + + + + + + + + + + + + +
관련파트너 1관련파트너 2내용
셀피스유저 + 셀피스는 서비스를 통해 유저가 궁극적으로 목표했던 ‘퍼스널 브랜드’를 구축할 수 있도록 돕습니다. 이에 따라 유저는 퍼스널 브랜딩 이전 ‘자기이해’ 에서 나아가 퍼스널 브랜딩과 관한 정보 습득, 학습 / 퍼스널 브랜딩 정체성 확립까지를 경험합니다. 그 과정에서 유료 컨텐츠나 컨설팅 프로그램을 유료 서비스화하여 (class 101과 유사한 비즈니스 로직) 프리미엄 구독제도를 도입하고자 합니다.

+ [프리미엄 구독 서비스 ]
+ 1. 페르소나 챗봇 도입을 통한 커스터마이징 기능
+ 2. 성격 유형 테스트(mbti 기반) 진행 기능
+ 3. 아카이빙 및 검사 결과 기록 저장기한 연장 : 60일 → 영구저장
+ 4. 브랜딩 관리를 위한 로드맵, 트래킹 툴 제공
+ 5. 1:1 맞춤형 컨설팅 연결
+
셀피스기업 / 퍼스널브랜더 + 서비스 확장 계획에 따라 추후 퍼스널 브랜드, 자기계발 등과 관한 기업, 성공한 퍼스널 브랜더와의 계약관계를 통해 ‘검증된 교육 컨텐츠’를 제공하고자 합니다. 이에 따라 셀피스의 이해관계자로는 유저 외에도 전문 퍼스널브랜더, 기업도 포함되며 이들은 유저에게 교육 프로그램을 제공하고, 교육프로그램 제공으로 인한 수익을 얻습니다.

+ 추가적으로, 유료 유저에게는 1:1 맞춤형 퍼스널브랜딩 컨설턴트로써 컨설팅 세션을 제공합니다.
+ 1. 페이지 내 광고 배너
+ 2. 외부 퍼스널 브랜딩 강의 및 프로그램 파트너십
+ 3. 예비 브랜더 연결 및 수수료 수익
+
+ +### 비즈니스 모델 캔버스 + +![72](https://github.com/KUSITMS-29th-TEAM-D/29th_Semi_README/assets/113084292/96829ad6-c450-4790-8132-c193713b515b) + +
+ +## **🎨** 디자인 무드보드 + +![24](https://github.com/KUSITMS-29th-TEAM-D/29th_Semi_README/assets/113084292/e62b38ef-d88e-4a81-9fcb-3a483ce5aa05) + +![73](https://github.com/KUSITMS-29th-TEAM-D/29th_Semi_README/assets/113084292/54a57fda-731b-4917-b65e-b64e7a9f4ed2) + +![74](https://github.com/KUSITMS-29th-TEAM-D/29th_Semi_README/assets/113084292/77f14b28-c02f-40af-91a6-bb46805ac09e) + +![21](https://github.com/KUSITMS-29th-TEAM-D/29th_Semi_README/assets/113084292/7298323f-8c6c-42c8-9143-403ce089afa9) + +![22](https://github.com/KUSITMS-29th-TEAM-D/29th_Semi_README/assets/113084292/4b6ead9f-5f49-462a-a19d-7a0aff5f14bd) + +![76](https://github.com/KUSITMS-29th-TEAM-D/29th_Semi_README/assets/113084292/bde2d9f5-8fbe-49bb-a23c-4073eeb2a8b2) + +![75](https://github.com/KUSITMS-29th-TEAM-D/29th_Semi_README/assets/113084292/b5c5b2e9-296d-4950-964c-c6e254308d76) + +
+ +## **🌐 System Architecture** + +selpiece_아키텍처 + +

+ +## **📜 ERD** + +셀피스_erd + +

+ +## **🛠️ Stacks** + +### **📘 Web/Android** + + + +**`React`** +- React는 가장 핵심 요소인 Virtual Dom을 이용하여 불필요한 화면 갱신을 최소화합니다. 이를 통해, 성능 향상을 시킬 수 있으며 빠른 렌더링을 지원합니다. +- React의 생태계는 비교적 방대하며, 개발자 커뮤니티도 활발합니다. 그만큼 다양한 라이브러리, 플러그인 등이 개발되어 있어 생산성을 향상시킬 수 있습니다. +- React는 컴포넌트 기반 아키텍처를 채택하고 있으며, UI 요소들을 컴포넌트로 분리하여 개발하고 조합하는 방식으로 구성할 수 있습니다. 따라서, 컴포넌트의 재사용성을 용이하게 하며, 코드 수정 및 유지보수에 효율적입니다. + +**`Typescript`** +- Typescript는 Javascript 기반의 정적 타입 문법을 추가한 언어로, 타입 추가로 인해 안정적인 개발과 높은 수준의 코드 품질을 유지할 수 있습니다. +- 컴파일 과정에서 타입을 지정하기 때문에 컴파일 에러 예방, 손쉬운 디버깅이 가능해집니다. +- 변수, 함수, 매개변수, 함수 반환 값 등 타입 어노테이션(type annotation)을 추가할 수 있으며, 이를 통해 개발자가 코드의 의도를 명확하게 표현할 수 있습니다. 따라서 다른 개발자들이 코드를 이해하기 쉽게 도와줄 수 있습니다. + +**`Styled Components`** +- Styled Components는 CSS를 Javascript로 작성된 컴포넌트에 바로 삽입하는 기법으로, 컴포넌트 스타일링을 쉽게 구현할 수 있습니다. 뿐만 아니라, Javascript의 기능을 활용하여 동적인 스타일을 생성하거나 조건부 스타일을 적용할 수 있습니다. +- CSS를 컴포넌트 기반으로 스타일링함으로써 컴포넌트 단위로 스타일을 정의하고 관리할 수 있습니다. 따라서, 컴포넌트 지향적인 스타일링이 가능하하며, 전역 스타일 충돌을 방지할 수 있습니다. + +**`Vite`** +- Vite는 개발 서버가 빠르게 번들링하고 HMR(Hot Module Replacement, 앱을 종료하지 않고 갱신된 파일만 교체하는 방식)을 지원함으로써 빠른 개발 속도를 제공합니다. +- Vite의 사전 번들링 기능은 ESbuild를 사용하고 있어 기존 번들러 대비 10~100배 빠른 번들링 속도를 가지고 있습니다. + +**`Recoil`** +- Recoil은 React를 위한 상태 관리 라이브러리이기 때문에, React의 기본적인 훅(hook)과 개념을 활용하여 상태 관리를 보다 쉽고 직관적으로 할 수 있습니다. 따라서, 러닝 커브가 비교적 낮아 쉽게 사용할 수 있습니다. +- Recoil은 비동기 처리를 기반으로 작성되어 동시성 모드를 제공합니다. 따라서, 다른 전역 상태 라이브러리처럼 비동기 처리 라이브러리에 의존할 필요가 없습니다. + +**`Axios`** +- 크로스 브라우징 최적화로 브라우저 호환성이 뛰어나며, Javascript 내장 라이브러리인 fetch와 다르게 오래된 브라우저 지원 불가에 대한 걱정이 필요하지 않습니다. +- Promise 기반으로 만들어졌기 때문에 데이터를 다루기 편리합니다. 뿐만 아니라, 많은 기능을 제공하고 있어 요청과 응답을 보다 쉽게 다룰 수 있는 편의성을 제공합니다. + +**`Vercel`** +- Vercel은 서버리스 아키텍쳐 기반으로, 사이트가 원활하게 작동하도록 모든 관리 작업을 처리합니다. 뿐만 아니라, CI/CD를 쉽게 설정할 수 있습니다. 따라서 개발자가 코드 개발 외적으로 관리해야 할 요소를 줄여줍니다. +- CDN을 통해 전 세계 여러 위치에 제공하여 빠른 로딩 속도와 확장성을 제공합니다. + +
+ +### **📗 Server** + + + +**`Spring Boot`** + - 설정이 간소화되고 개발 생산성이 향상되는 스프링 기반의 프레임워크로, 내장된 톰캣과 같은 서버를 사용하여 애플리케이션을 간단히 배포할 수 있습니다. + +**`Gradle`** + - 의존성 관리 및 빌드 도구로, Groovy나 Kotlin 기반의 DSL을 사용하여 프로젝트를 빌드하고 관리할 수 있으며, 멀티 프로젝트 빌드 및 다양한 플러그인 지원으로 유연성이 뛰어납니다. + +**`Spring Security`** + - 다양한 인증 및 권한 부여 기능을 제공하여 보안을 강화하며, 사용자 관리, 인증 프로세스 설정, 접근 제어 등의 보안 요구 사항을 손쉽게 구현할 수 있습니다. + - OAuth2.0 프로토콜을 통해 인증 서버에 접근하는 방식으로 소셜 로그인을 구현할 수 있습니다. + +**`JPA(Hibernate)`** +- 객체와 관계형 데이터베이스 간의 매핑을 단순화하여 데이터베이스에 대한 복잡한 SQL 쿼리를 작성하지 않고도 데이터를 다룰 수 있습니다. +- 객체지향 프로그래밍의 장점을 그대로 유지하면서 데이터베이스와의 상호작용을 편리하게 할 수 있습니다. + +**`MySQL`** +- 오픈 소스 관계형 데이터베이스 관리 시스템(RDBMS)으로, 안정적이고 높은 성능을 제공합니다. +- 대용량 데이터 처리와 트랜잭션 처리에 효과적이며, 다양한 운영 환경에서 널리 사용됩니다. + +**`Redis`** +- 메모리 기반의 데이터 저장소로, 빠른 속도와 낮은 지연 시간을 제공하여 데이터의 실시간 처리와 캐싱에 적합합니다. +- 생산성이 뛰어나고 확장성이 우수하여 대규모 시스템에서도 효율적으로 사용될 수 있습니다. +- 소셜 로그인 과정에서 Refresh Token을 저장하는 용도로 활용할 수 있습니다. + +**`JWT`** +- JSON 웹 토큰으로, 토큰 기반의 인증 방식을 사용하여 사용자 인증 및 권한 부여를 수행합니다. +- 토큰 자체에 정보를 포함하므로 데이터베이스 조회 없이도 효율적인 인증이 가능하며, 암호화된 형태로 토큰을 전달하여 보안을 강화할 수 있습니다. + +**`Nginx`** +- 로드 밸런싱과 리버스 프록시 기능을 통해 트래픽을 새로운 버전의 애플리케이션으로 원활하게 전환할 수 있습니다. + +**`Docker`** +- CI/CD를 진행 할 때 실행 가능한 서버 애플리케이션을 도커를 통해 컨테이너화 시켜 서버 환경에서 쉽게 실행할 수 있게 합니다. + +**`Docker Compose`** +- 복잡한 애플리케이션을 쉽게 정의하고 관리할 수 있으며, 개발 환경에서부터 프로덕션 배포까지 일관된 환경을 유지할 수 있습니다. + +**`Github Actions`** +- 자동화된 워크플로우를 통해 Blue/Green 환경에 대한 코드 변경을 각각 자동으로 배포할 수 있습니다. +- Github에서 제공하는 CI/CD 프로세스로 젠킨스와 같은 별도의 파이프라인을 구축할 필요가 없다는 장점이 있습니다. + +**`NCP(Naver Cloud Platform)`** +- NCP Server + - 확장성과 유연성을 바탕으로 다양한 인스턴스를 효율적으로 관리 및 배포할 수 있습니다. + - 체계적인 가이드라인을 제공해 빠르고 정확하게 서버 구축이 가능합니다. +- Object Storage + - 데이터 무결성 및 복원력을 보장하고 초대용량 데이터를 저장할 수 있습니다. + +
+ +### **🗣️ Co-working-Tool** + + + +
+ +## 🔖 Naming Rules + +### **📘 Web/Android** + +- **컴포넌트명 (components)** + - **폴더명** : 컴포넌트랑 직접적인 폴더명은 PascalCase 사용 + - **파일명** : PascalCase 사용 +- **함수명, 변수명, 이미지 파일명** : camelCase 사용 +- **상수명** : SNAKE_CASE 사용 +- **타입명** : PascalCase 사용 + +### **📗 Server** + +- **패키지명** : 한 단어 소문자 사용 `Ex) service` +- **클래스명** : 파스칼 케이스 사용 `Ex) JwtUtil` +- **메서드명** : 카멜 케이스 사용, 동사로 시작 `Ex) getUserScraps` +- **변수명** : 카멜 케이스 사용 `Ex) jwtToken` +- **상수명** : 대문자 사용 `Ex) EXPIRATION_TIME` +- **컬럼명** : 스네이크 케이스 사용 `Ex) users_id` + +
+ +## **️🔏 Commit Convention** + +### **📘 Web/Android** + +- 형식: `태그: 커밋 내용 (#이슈번호)` + +### **📗 Server** +- 이슈 번호 붙여서 커밋 `Ex) #4 [feat] : 로그인 기능 구현` +- Body는 추가 설명 필요하면 사용 + +### **📌 Type** + +| commit 명 | commit 뜻 | +|-------------| --- | +| `feat` | 새로운 기능 추가 / 일부 코드 추가 / 일부 코드 수정 (리팩토링과 구분) / 디자인 요소 수정 | +| `fix` | 버그 수정 | +| `refactor` | 코드 리팩토링 | +| `style` | 코드 의미에 영향을 주지 않는 변경사항 (코드 포맷팅, 오타 수정, 변수명 변경, 에셋 추가) | +| `chore` | 빌드 부분 혹은 패키지 매니저 수정 사항 / 파일 이름 변경 및 위치 변경 / 파일 삭제 | +| `docs` | 문서 추가 및 수정 | +| `rename` | 패키지 혹은 폴더명, 클래스명 수정 (단독으로 시행하였을 시) | +| `remove` | 패키지 혹은 폴더, 클래스를 삭제하였을 때 (단독으로 시행하였을 시) | + +
+ +## **🔀 Git Flow** + +- 생성한 이슈에 따라서 브랜치 생성 `Ex) feature/#4/login` + +| 브랜치 명 | 설명 | +|------|--------------------------------------------------------| +| `main` | 소프트웨어 제품 배포하는 용도로 쓰는 브랜치 | +| `develop` | 개발용 default 브랜치로, 이 브랜치를 기준으로 feature 브랜치를 따고, 합치는 브랜치 | +| `feat` | 단위 기능 개발용 브랜치 | +| `fix` | 단위 기능 개발 수정용 브랜치 | +| `hotfix` | main branch에 배포 코드가 합쳐진 후, 버그 발생 시 긴급 수정하는 브랜치 | From 704926d5449914e0566e7cd465f3ba4ec8b2dff0 Mon Sep 17 00:00:00 2001 From: aaminha Date: Thu, 23 May 2024 23:17:54 +0900 Subject: [PATCH 25/25] =?UTF-8?q?fix:=20=EB=8B=89=EB=84=A4=EC=9E=84=20?= =?UTF-8?q?=EC=97=86=EB=8A=94=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 --- .../ExperienceRecommendPage/ExperienceRecommendTab.tsx | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/components/ExperienceRecommendPage/ExperienceRecommendTab.tsx b/src/components/ExperienceRecommendPage/ExperienceRecommendTab.tsx index 66b9aa0..e6e3068 100644 --- a/src/components/ExperienceRecommendPage/ExperienceRecommendTab.tsx +++ b/src/components/ExperienceRecommendPage/ExperienceRecommendTab.tsx @@ -44,8 +44,12 @@ export const ExperienceRecommendTab = () => { - {userService.getUserNickname()}님, 아직 내가 - 누군지 잘 모르겠다면
+ {userService.getUserNickname() !== '' && ( + + {userService.getUserNickname()}님,{' '} + + )} + 아직 내가 누군지 잘 모르겠다면
이런 콘텐츠들은 어때요?
}