diff --git a/src/GlobalStyle.ts b/src/GlobalStyle.ts index 028be77..6ab33c6 100644 --- a/src/GlobalStyle.ts +++ b/src/GlobalStyle.ts @@ -6,6 +6,19 @@ import PretendardExtraBold from './assets/fonts/Pretendard/Pretendard-ExtraBold. const GlobalStyle = createGlobalStyle` + html { + font-size: 62.5%; + } + + *{ + box-sizing: border-box; + } + + ul,ol,li{ + padding: 0; + list-style: none; + } + @font-face { font-family: 'Pretendard'; font-weight: 200; @@ -44,6 +57,8 @@ const GlobalStyle = createGlobalStyle` body { font-family: 'Pretendard','SUIT',serif; + + } `; diff --git a/src/apis/axiosinstance.ts b/src/apis/axiosinstance.ts index a040008..84b7f74 100644 --- a/src/apis/axiosinstance.ts +++ b/src/apis/axiosinstance.ts @@ -1,7 +1,7 @@ import axios, { AxiosResponse, AxiosError } from 'axios'; const axiosInstance = axios.create({ - baseURL: 'https://flexrate.online', + baseURL: import.meta.env.VITE_APP_BASE_URL, headers: { 'Content-Type': 'application/json', }, diff --git a/src/assets/imgs/flexrateExplain.png b/src/assets/imgs/flexrateExplain.png new file mode 100644 index 0000000..22145b9 Binary files /dev/null and b/src/assets/imgs/flexrateExplain.png differ diff --git a/src/assets/imgs/notification.png b/src/assets/imgs/notification.png deleted file mode 100644 index b804c13..0000000 Binary files a/src/assets/imgs/notification.png and /dev/null differ diff --git a/src/assets/svgs/0_index.ts b/src/assets/svgs/0_index.ts index 4300be6..ca32c30 100644 --- a/src/assets/svgs/0_index.ts +++ b/src/assets/svgs/0_index.ts @@ -4,6 +4,7 @@ import GreenCheckIcon from './GreenCheckIcon.svg?react'; import CircleCheckIcon from './CircleCheckIcon.svg?react'; import CircleCheckColor from './CircleCheckColor.svg?react'; import EditIcon from './EditIcon.svg?react'; +import GraphMonk from './GraphMock.svg?react'; export { HiddenIcon, @@ -12,4 +13,5 @@ export { CircleCheckIcon, CircleCheckColor, EditIcon, + GraphMonk, }; diff --git a/src/assets/svgs/GraphMock.svg b/src/assets/svgs/GraphMock.svg new file mode 100644 index 0000000..7bb9bcb --- /dev/null +++ b/src/assets/svgs/GraphMock.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/components/CoachMarksComs/Tooltip2.tsx b/src/components/CoachMarksComs/Tooltip2.tsx index f7599e2..0d72490 100644 --- a/src/components/CoachMarksComs/Tooltip2.tsx +++ b/src/components/CoachMarksComs/Tooltip2.tsx @@ -41,10 +41,9 @@ const Tooltip2 = () => { return ( -
나의 대출 내역을 바탕으로
+
입력한 정보를 바탕으로 산출된
- 대출금 상환 및 납입 정보를 - 알려드려요! + 맞춤형 대출 상품 이에요!
@@ -99,7 +98,7 @@ const TooltipContainer = styled.span` padding: 20px; position: absolute; z-index: 20; - bottom: -10rem; + bottom: -15rem; left: 20rem; &::after { diff --git a/src/components/DashboardComs/DashHeader.tsx b/src/components/DashboardComs/DashHeader.tsx index c063507..387c9a6 100644 --- a/src/components/DashboardComs/DashHeader.tsx +++ b/src/components/DashboardComs/DashHeader.tsx @@ -63,6 +63,15 @@ const Title = styled.div<{ $borderColor: string }>` border-left: 2px solid ${(props) => props.$borderColor}; padding-left: 8px; `; + +const StSubTitle = styled.p` + color: #8e9cb0; + font-family: Pretendard; + font-size: 10px; + font-style: normal; + font-weight: 600; + line-height: normal; +`; const Bold = styled.span` color: black; font-size: 16px; @@ -72,16 +81,6 @@ const Bold = styled.span` const BoldGreen = styled(Bold)` color: #63c393; `; -const Box = styled.span<{ $backgroundColor: string }>` - //color background color prop으로 - font-size: 10px; - font-weight: 700; - line-height: 12px; - border-radius: 5px; - background-color: ${(props) => props.$backgroundColor}; - color: ${(props) => props.color}; - padding: 3px 5px; -`; const DashHeader = () => { const [coachMark, setCoachMark] = useRecoilState(CoachMarkStage); @@ -109,32 +108,32 @@ const DashHeader = () => {
Flexrate 신용대출 - - {`${data.loan_request / 10000}만원`} - - - {`${data.loan_repay_term * 12}개월`} -
+ + 입력하신 금융 정보를 모두 고려하여 추천된 대출상품이에요. +
- 다음 달 대출금 상환 날짜 + 나의 대출 금리
- 2024년 1월 19일 - - D-31일 남았어요 - + {12}%
+ + 입력하신 금융 정보를 모두 고려하여 추천된 대출 금리예요. +
- 금리 갱신 회차 + 나의 대출 가능 한도
- {data.changes.length}회차 + {300}만원
+ + 입력하신 금융 정보를 기반으로 산출된 대출 한도예요. +
{isVisible && } diff --git a/src/components/DashboardComs/FlipCard.tsx b/src/components/DashboardComs/FlipCard.tsx index be0150a..7b3def9 100644 --- a/src/components/DashboardComs/FlipCard.tsx +++ b/src/components/DashboardComs/FlipCard.tsx @@ -9,8 +9,56 @@ import Tooltip3 from '../CoachMarksComs/Tooltip3'; import { LoanInfo } from '@/state/LoanInfo'; import { output } from '@/state/output'; import { userInfo } from '@/state/userInfo'; +import { SubTitle } from '@/styles/MypageStyle'; -const CardContainer = styled.div<{ $isFlipped: boolean; $isVisible: boolean }>` +const FlipCard: React.FC = () => { + const Info = useRecoilValue(LoanInfo); + const outputValue = useRecoilValue(output); + const score = Math.floor(outputValue.Score); + + const [coachMark, setCoachMark] = useRecoilState(CoachMarkStage); + const data = useRecoilValue(userInfo); + + // stage 값에 접근 + const { stage, mode } = coachMark; + + // stage 값을 업데이트하는 함수 + const updateStage = (newStage: number) => { + setCoachMark({ ...coachMark, stage: newStage }); + }; + + let isVisible = mode && stage === 2; + const [isFlipped, setIsFlipped] = useState(false); + + const handleClick = () => { + setIsFlipped(!isFlipped); + }; + + return ( + + + 1:1 맞춤 금리 + + + 60만 건의 데이터에 기반해 + + 합리적인 대출 상품을 제안해요. + + + 약 60만 건의 실제 금융 가명 정보를 활용한 빅데이터 + 분석 모델로, 개인의 연소득, 주거형태, 고용형태, 입사년도 + 나이, 성별 등 다양한 요소를 종합적으로 고려하여 + 개인 맞춤형 대출 상품을 제안드려요. + + + {isVisible && } + + ); +}; + +export default FlipCard; + +const CardContainer = styled.div<{ $isVisible: boolean }>` width: 100%; height: 100%; box-sizing: border-box; @@ -37,215 +85,57 @@ const CardContainer = styled.div<{ $isFlipped: boolean; $isVisible: boolean }>` } `; -const CardFlipper = styled.div<{ $isFlipped: boolean }>` - width: 100%; - height: 100%; - position: relative; - transition: transform 0.6s; - transform-style: preserve-3d; - transform: ${({ $isFlipped }) => - $isFlipped ? 'rotateY(180deg)' : 'rotateY(0deg)'}; -`; - const CardFace = styled.div` position: absolute; width: 100%; height: 100%; backface-visibility: hidden; - display: flex; - align-items: center; - justify-content: center; - font-size: 24px; color: white; `; -const CardFront = styled(CardFace)` +const CardBack = styled(CardFace)` + background-color: #fefcf2; display: flex; flex-direction: column; - gap: 0.85em; - color: black; - & > div { - /* border: 1px solid #d9d9d9; */ - outline: 1px solid var(--Gray3, #d9d9d9); - border-radius: 8px; - width: 99%; - height: 45.5%; - display: flex; - flex-direction: column; - } -`; -const Wrapper = styled.div` - width: 90%; - padding: 22px 21px; - & > h1 { - color: #595959; - font-family: Pretendard; - font-size: 13px; - font-weight: 700; - line-height: 16px; - } - & > div { - width: 95%; - display: flex; - justify-content: space-between; - margin-top: 0.2em; - margin-bottom: 0.5em; - & > span { - display: flex; - align-items: center; - gap: 0.2em; - & > h2 { - font-family: SUIT; - font-size: 28px; - font-weight: 700; - line-height: 35px; - } - & > h3 { - font-family: SUIT; - font-size: 13px; - font-weight: 600; - line-height: 16px; - margin-top: 0.8em; - } - & > h4 { - font-family: Pretendard; - font-size: 12px; - font-weight: 600; - line-height: 14px; - color: #8c8c8c; - margin-top: 0.9em; - } - & > h5 { - font-family: SUIT; - font-size: 14px; - font-weight: 700; - line-height: 17px; - color: #51b13a; - margin-top: 0.8em; - } - & > h6 { - font-family: Pretendard; - font-size: 10px; - font-weight: 600; - line-height: 12px; - color: #bfbfbf; - margin-top: 1.1em; - } - & > img { - width: 0.7em; - height: 0.7em; - margin-top: 0.4em; - } - } - } -`; -const RateBox = styled.span` - display: flex; - align-items: center; justify-content: center; - width: 87%; - padding: 0.5em 1em; + padding: 2.7rem 2.4rem; + border-radius: 10px; +`; + +const StTitle = styled.p` + color: var(--Black, #262626); font-family: Pretendard; font-size: 10px; + font-style: normal; font-weight: 700; - line-height: 12px; - text-align: center; - color: #414141; - border: none; - border-radius: 5px; - background-color: #f4f4f4; -`; -const ScoreBox = styled(RateBox)` - color: #51b13a; - background-color: #e3f5ee; - color: #397356; - & > div { - color: #63c393; - } + line-height: normal; `; -const CardBack = styled(CardFace)` - background-color: #e8f7f7; - background-image: url(${flip1}); - background-size: contain; - background-repeat: no-repeat; - transform: rotateY(180deg); +const StLayout = styled.div` + display: flex; + flex-direction: column; + gap: 0.5rem; + margin: 0.8rem 0 1.8rem; `; -const FlipCard: React.FC = () => { - const Info = useRecoilValue(LoanInfo); - const outputValue = useRecoilValue(output); - const score = Math.floor(outputValue.Score); - - const [coachMark, setCoachMark] = useRecoilState(CoachMarkStage); - const data = useRecoilValue(userInfo); - - // stage 값에 접근 - const { stage, mode } = coachMark; - - // stage 값을 업데이트하는 함수 - const updateStage = (newStage: number) => { - setCoachMark({ ...coachMark, stage: newStage }); - }; - - let isVisible = mode && stage === 2; - const [isFlipped, setIsFlipped] = useState(false); - - const handleClick = () => { - setIsFlipped(!isFlipped); - }; +const StStrong = styled.span` + color: #77645e; +`; - return ( - - - -
- -

나의 대출 금리

-
- -

{data.loan_initial}

-

%

-

이번 분기 기준

-
- - -
%
-
전달 대비
-
-
- - 💵 연봉이 오르면 금리가 저렴해진다? -
-
-
- -

나의 신용 평가 점수

-
- -

{data.newCreditScore}

-

-
- -
상위 68%
-
-
- - NICE 신용평가점수보다 약{' '} -
{data.newCreditScore - data.creditScore}점
차이나요! -
-
-
-
- -
- {isVisible && } -
- ); -}; +const StP1 = styled.p` + color: var(--Black, #262626); + font-family: Pretendard; + font-size: 16px; + font-style: normal; + font-weight: 700; + line-height: normal; +`; -export default FlipCard; +const StP = styled.p` + color: #8d96a1; + font-family: Pretendard; + font-size: 11px; + font-style: normal; + font-weight: 600; + line-height: normal; +`; diff --git a/src/components/DashboardComs/LoanHistory.tsx b/src/components/DashboardComs/LoanHistory.tsx index 88af3dc..7dda3d4 100644 --- a/src/components/DashboardComs/LoanHistory.tsx +++ b/src/components/DashboardComs/LoanHistory.tsx @@ -1,15 +1,96 @@ -import React from 'react'; -import { styled } from 'styled-components'; +import React, { useEffect, useState } from 'react'; +import styled from 'styled-components'; +import '../../styles/CustomTooltip.css'; import { useRecoilState, useRecoilValue } from 'recoil'; import { CoachMarkStage } from '@/state/CoachMarkStage'; -import { LoanInfo } from '@/state/LoanInfo'; -import Tooltip6 from '../CoachMarksComs/Tooltip6'; import { userInfo } from '@/state/userInfo'; -import customLocaleString from '@/utils/customLocaleString'; +import TransverseGraph from './TransverseGraph'; +import { SubTitle } from '@/styles/MypageStyle'; +import Tooltip6 from '../CoachMarksComs/Tooltip6'; + +const Container = styled.div<{ $isVisible: boolean }>` + width: 100%; + height: 100%; + box-sizing: border-box; + /* border: 1px solid #d9d9d9; */ + outline: 1px solid var(--Gray3, #d9d9d9); + outline-offset: -1px; + border-radius: 8px; + display: flex; + flex-direction: column; + gap: 2rem; + position: relative; + padding: 2.8rem; + + z-index: ${({ $isVisible }) => ($isVisible ? '10' : '1')}; + //코치마크 + + &::before { + content: ''; + position: absolute; + top: -5px; + right: -5px; + bottom: -5px; + left: -5px; /* 테두리 바깥쪽 영역 */ + z-index: ${({ $isVisible }) => + $isVisible ? '-1' : '0'}; /* div 뒤에 배치 */ + background-color: #fff; + border-radius: 10px; + display: ${({ $isVisible }) => ($isVisible ? 'block' : 'none')}; + } +`; +const Wrapper = styled.div` + display: flex; + flex-direction: column; + & > p { + font-size: 13px; + font-weight: 700; + line-height: 16px; + letter-spacing: 0em; + color: #595959; + padding-bottom: 0.75em; + } +`; +const Num = styled.span` + color: #21272d; + font-size: 3rem; + font-style: normal; + font-weight: 550; + line-height: normal; +`; +const Per = styled.span` + color: #8c8c8c; + font-size: 13px; + font-weight: 400; + line-height: 16px; + margin-right: 0.4em; +`; +const Text = styled.span` + font-family: Pretendard; + font-size: 12px; + font-weight: 600; + line-height: 14px; + color: #8c8c8c; + margin-right: 5em; +`; +const Chart = styled.div` + width: 100%; +`; + +interface ChartFunctionParams { + series: number[][]; + seriesIndex: number; + dataPointIndex: number; + w: { + globals: { + labels: string[]; + }; + // ...w에 대한 추가적인 타입 정의 + }; +} const LoanHistory = () => { const [coachMark, setCoachMark] = useRecoilState(CoachMarkStage); - const isloan = useRecoilValue(userInfo); const data = useRecoilValue(userInfo); // stage 값에 접근 @@ -21,180 +102,67 @@ const LoanHistory = () => { }; let isVisible = mode && stage === 5; + const changes = data.changes; + const lineData = changes.map((item) => item.change_loan_initial); + return ( - - 나의 대출 히스토리 - - - 대출시작일 - 2023년 12월 19일 - - - 금리 변경 횟수 - 0회 - - - 상환 횟수 - 0회 - - - 연체 횟수 - 0회 - - - - - - - - -

상환 기록이 없습니다

-
-
+ + +

유사 소득층의 대출 금리 범위와 나의 금리 범위 위치

+
+ {`0 ~ 21`} + % + 20대 여자 + {`8 ~ 12`} + % + 나의 범위 +
+
+ + + + + 내 상품의 금리 범위 + + + + 대출 상품을 가입한 유사 소득층의 평균 금리 범위 + + {isVisible && } -
+ ); }; -const Dash = { - Wrapper: styled.div<{ $isVisible: boolean }>` - position: relative; - width: 100%; - height: 100%; - box-sizing: border-box; - border-radius: 8px; - /* border: 1px solid var(--Gray3, #d9d9d9); */ - outline: 1px solid var(--Gray3, #d9d9d9); - outline-offset: -1px; - display: flex; - flex-direction: column; - gap: 0.5rem; - transition: 0.5s; /* 변화가 있을 때 시간차 주기*/ - z-index: ${({ $isVisible }) => ($isVisible ? '10' : '1')}; - //코치마크 - - &::before { - content: ''; - position: absolute; - top: -5px; - right: -5px; - bottom: -5px; - left: -5px; /* 테두리 바깥쪽 영역 */ - z-index: ${({ $isVisible }) => - $isVisible ? '-1' : 'none'}; /* div 뒤에 배치 */ - background-color: #fff; - border-radius: 10px; - display: ${({ $isVisible }) => ($isVisible ? 'block' : 'none')}; - } - - &:hover { - transform: translateY(-2px); /*위로 5px이동*/ - box-shadow: 5px 5px 5px 0 #d9d9d9; - } - `, - Title: styled.p` - margin: 22px 22px 0 22px; - color: var(--Gray8, #595959); - font-family: Pretendard; - font-size: 0.8rem; - font-style: normal; - font-weight: 700; - line-height: normal; - `, - Cate: styled.div` - margin: 0 22px 0 22px; - display: flex; - justify-content: space-between; - & > span { - flex: 1; - display: flex; - flex-direction: column; - gap: 8px; - } - & > span:not(:nth-child(1)) { - border-left: 1px solid #bfbfbf; - padding-left: 1rem; - } - `, - Label: styled.p` - color: var(--Gray6, #8c8c8c); - font-family: Pretendard; - font-size: 12px; - font-style: normal; - font-weight: 600; - line-height: normal; - `, - Content: styled.p` - color: #000; - font-family: SUIT; - font-size: 15px; - font-weight: 800; - overflow-wrap: break-word; - `, - ScrollBoard: styled.div` - position: absolute; - bottom: 0px; - display: flex; - width: calc(100% - 22px); - gap: 0.5rem; - padding: 0.5rem 0 1rem 22px; - overflow-x: scroll; - overflow-y: hidden; - white-space: nowrap; - &::-webkit-scrollbar { - height: 7px; - } - - /* 막대기 */ - &::-webkit-scrollbar-thumb { - border-radius: 20px; - background-color: #a6a6a6; - border: 5px solid transparent; - } - - /* 백그라운드 */ - &::-webkit-scrollbar-track { - background: #f1f1f1; - background-size: cover; - } - - /*스크롤바 커스텀 끝*/ - `, -}; -const BoardItem = styled.div` - min-width: 150px; - height: 7rem; - border-radius: 10px; - border: 1px solid var(--Gray3, #d9d9d9); - background: #f9fafb; +export default LoanHistory; +const StLabelWrapper = styled.div` display: flex; flex-direction: column; - justify-content: center; - align-items: center; gap: 1rem; - & > p { - color: var(--Gray9, #414141); - font-family: Pretendard; - font-size: 12px; - font-weight: 600; - } `; -export default LoanHistory; +const StLabelContainer = styled.div` + display: flex; + gap: 1rem; +`; + +const StCircle = styled.div` + width: 10px; + height: 10px; + border-radius: 50px; + background-color: #5bc569; +`; + +const StLabel = styled.p` + color: #87898d; + font-family: Pretendard; + font-size: 11px; + font-style: normal; + font-weight: 500; + line-height: normal; +`; + +const StbasicCircle = styled(StCircle)` + background-color: #f6f7f8; +`; diff --git a/src/components/DashboardComs/LoanTobepaid.tsx b/src/components/DashboardComs/LoanTobepaid.tsx index 35f5c42..3841acb 100644 --- a/src/components/DashboardComs/LoanTobepaid.tsx +++ b/src/components/DashboardComs/LoanTobepaid.tsx @@ -9,6 +9,8 @@ import { LoanInfo } from '@/state/LoanInfo'; import { output } from '@/state/output'; import Tooltip4 from '../CoachMarksComs/Tooltip4'; import { userInfo } from '@/state/userInfo'; +import { SubTitle } from '@/styles/MypageStyle'; +import { GraphMonk } from '@/assets/svgs/0_index'; const LoanTobepaid = () => { const [coachMark, setCoachMark] = useRecoilState(CoachMarkStage); @@ -39,36 +41,48 @@ const LoanTobepaid = () => { return ( <> - 나의 이번 달 대출금 - - - {paidtoAmount.toLocaleString()} - - - - - - -
- - -
+ + 나의 대출 변동 금리 범위 + + 기준 · 사용자 입력 데이터 기반 ML모델 예측 + +
+ {`8 ~ 12`} + % +
+ +
+ + 내 또래의 업직종 구성 + 기준 · 나이대별 직종 + + + 1 + 서비스업 + 25.2% + + + 2 + 서비스업 + 25.2% + + + 3 + 서비스업 + 25.2% + + + 4 + 서비스업 + 25.2% + + + 5 + 서비스업 + 25.2% + + + {isVisible && }
@@ -84,12 +98,11 @@ const Dash = { box-sizing: border-box; border-radius: 8px; /* border: 1px solid var(--Gray3, #d9d9d9); */ - outline: 1px solid var(--Gray3, #d9d9d9); + /* outline: 1px solid var(--Gray3, #d9d9d9); */ outline-offset: -1px; /* 내부로 2px 만큼 옮김 */ - padding: 22px; + /* padding: 22px; */ display: flex; - flex-direction: column; - gap: 0.5rem; + gap: 1.5rem; z-index: ${({ $isVisible }) => ($isVisible ? '10' : '1')}; //코치마크 @@ -111,14 +124,32 @@ const Dash = { display: flex; } `, + Container: styled.div` + position: relative; + outline: 1px solid var(--Gray3, #d9d9d9); + width: 100%; + height: 100%; + border-radius: 10px; + padding: 2.8rem 2.5rem; + gap: 0.8rem; + `, Title: styled.p` - color: var(--Gray8, #595959); + color: #4f5561; font-family: Pretendard; - font-size: 0.8rem; + font-size: 1.3rem; font-style: normal; font-weight: 700; line-height: normal; `, + SubTitle: styled.p` + color: var(--Gray5, #a6a6a6); + font-family: Pretendard; + font-size: 11px; + font-style: normal; + font-weight: 600; + line-height: normal; + margin: 0.8rem 0 1.5rem; + `, LoanPrice: styled.div` display: flex; align-items: flex-end; @@ -133,21 +164,59 @@ const Dash = { }; const Big = styled.span` - color: var(--Black, #262626); + color: #21272d; font-family: SUIT; - font-size: 32px; + font-size: 30px; font-style: normal; - font-weight: 700; + font-weight: 800; line-height: normal; - &::after { - content: '원'; - color: var(--Black, #262626); - font-family: Pretendard; - font-size: 15px; - font-style: normal; - font-weight: 600; - line-height: normal; - } +`; + +const StyleUL = styled.ul` + display: flex; + flex-direction: column; + gap: 1rem; +`; + +const StyleLi = styled.li` + display: flex; + gap: 1.6rem; +`; + +const ListStyle = styled.span` + color: var(--Gray7, #737373); + font-family: SUIT; + font-size: 12px; + font-style: normal; + font-weight: 800; + line-height: normal; + padding-right: 0.2rem; +`; + +const ListContent = styled.span` + color: #21272d; + font-family: Pretendard; + font-size: 12px; + font-style: normal; + font-weight: 600; + line-height: normal; +`; + +const Box = styled.span<{ $backgroundColor: string }>` + //color background color prop으로 + font-size: 10px; + font-weight: 700; + line-height: 12px; + border-radius: 5px; + background-color: ${(props) => props.$backgroundColor}; + color: #d96c87; + padding: 3px 5px; +`; + +const STGraphMonk = styled(GraphMonk)` + position: absolute; + bottom: 5.4rem; + right: 3.2rem; `; export default LoanTobepaid; diff --git a/src/components/DashboardComs/Notification.tsx b/src/components/DashboardComs/Notification.tsx index 6f3002f..0ffae66 100644 --- a/src/components/DashboardComs/Notification.tsx +++ b/src/components/DashboardComs/Notification.tsx @@ -1,11 +1,23 @@ import React from 'react'; -import NotificationImg from '../../assets/imgs/notification.png'; +import flexrateExplain from '../../assets/imgs/flexrateExplain.png'; import { styled } from 'styled-components'; const Notification = () => { return ( - + 정교한 분석 +
+ 또래와의 배교를 통해 + + 더 똑똑한 금융 결정을 도와드려요 + +
+ + Flex Rate는 내 또래의 직장 유형과 금융 상품 선택 현황을 분석한 맞춤형 + 통계 프로그램을 제공해요. 이를 통해 자신의 금융 상황을 또래와 비교하여 + 더 나은 의사 결정을 도와드리고 있어요. + + 이모지
); }; @@ -16,17 +28,45 @@ const Dash = { height: 100%; box-sizing: border-box; border-radius: 8px; - border: 1px solid var(--Gray3, #d9d9d9); padding: 22px; display: flex; flex-direction: column; - gap: 0.5rem; + justify-content: center; + gap: 0.8rem; + background-color: #e8f7f7; - & > img { + & img { width: 100%; - object-fit: fill; } `, + TopText: styled.p` + color: var(--Black, #262626); + font-family: Pretendard; + font-size: 1rem; + font-weight: 700; + `, + MainWrapper: styled.div` + display: flex; + flex-direction: column; + `, + MainText: styled.p` + color: var(--Black, #262626); + font-family: Pretendard; + font-size: 1.7rem; + font-weight: 700; + `, + ExplainText: styled.p` + color: #8d96a1; + font-family: Pretendard; + font-size: 1.2rem; + font-weight: 500; + line-height: 1.8rem; + margin: 2rem 0 4.8rem; + `, }; +const ColorText = styled.span` + color: #1fa3a3; +`; + export default Notification; diff --git a/src/components/DashboardComs/RateChange.tsx b/src/components/DashboardComs/RateChange.tsx index 561abd6..0fc3138 100644 --- a/src/components/DashboardComs/RateChange.tsx +++ b/src/components/DashboardComs/RateChange.tsx @@ -1,13 +1,12 @@ import React, { useEffect, useState } from 'react'; -import ApexCharts from 'apexcharts'; import styled from 'styled-components'; import '../../styles/CustomTooltip.css'; -import up from '../../assets/imgs/up.png'; -import down from '../../assets/imgs/down.png'; import { useRecoilState, useRecoilValue } from 'recoil'; import { CoachMarkStage } from '@/state/CoachMarkStage'; import Tooltip5 from '../CoachMarksComs/Tooltip5'; import { userInfo } from '@/state/userInfo'; +import TransverseGraph from './TransverseGraph'; +import { SubTitle } from '@/styles/MypageStyle'; const Container = styled.div<{ $isVisible: boolean }>` width: 100%; @@ -19,7 +18,9 @@ const Container = styled.div<{ $isVisible: boolean }>` border-radius: 8px; display: flex; flex-direction: column; + gap: 2rem; position: relative; + padding: 2.8rem; z-index: ${({ $isVisible }) => ($isVisible ? '10' : '1')}; //코치마크 @@ -39,7 +40,8 @@ const Container = styled.div<{ $isVisible: boolean }>` } `; const Wrapper = styled.div` - padding: 1.5em 2em 0 2em; + display: flex; + flex-direction: column; & > p { font-size: 13px; font-weight: 700; @@ -50,16 +52,16 @@ const Wrapper = styled.div` } `; const Num = styled.span` - font-family: SUIT; - font-size: 28px; - font-weight: 700; - line-height: 35px; - margin-right: 0.2em; + color: #21272d; + font-size: 3rem; + font-style: normal; + font-weight: 550; + line-height: normal; `; const Per = styled.span` - font-family: SUIT; + color: #8c8c8c; font-size: 13px; - font-weight: 600; + font-weight: 400; line-height: 16px; margin-right: 0.4em; `; @@ -102,140 +104,65 @@ const RateChange = () => { let isVisible = mode && stage === 4; const changes = data.changes; const lineData = changes.map((item) => item.change_loan_initial); - const blockData = lineData.map((item) => item * 1.25); - const duration = changes.map((item) => item.change_insert_time); - - const options = { - colors: ['#FBEAB2', '#80D2D0'], - series: [ - { - name: '', - type: 'column', - data: blockData, - }, - { - name: '', - type: 'line', - data: lineData, - }, - ], - chart: { - height: 185, - type: 'line', - toolbar: { - show: false, - }, - }, - plotOptions: { - bar: { - columnWidth: '65%', - }, - }, - tooltip: { - custom: function ({ - series, - seriesIndex, - dataPointIndex, - w, - }: ChartFunctionParams) { - let idx = parseInt(w.globals.labels[dataPointIndex]) - 1; - let rate = series[seriesIndex][dataPointIndex] / 1.25; // 해당 월의 금리 - let previousRate = series[seriesIndex][dataPointIndex - 1] || 0; // 전달의 금리 - let rateChange = rate - previousRate; // 금리 변동폭 - const startDate = duration[idx]; - const endDate = duration[idx]; - - // 양수 또는 음수에 따른 아이콘 결정 - const changeIcon = - rateChange >= 0 - ? `upIcon` // 양수일 때의 아이콘 - : `downIcon`; // 음수일 때의 아이콘 - - //사용자 정의 툴팁 내용 - return ` -
-
- ${rate} - % -
${startDate} - ${endDate}
- 이전 달 대비 - ${changeIcon} ${rateChange}% -
-
- `; - }, - }, - stroke: { - width: [0, 2.5], - }, - dataLabels: { - enabled: false, - }, - labels: duration, - xaxis: { - tooltip: { - enabled: false, // X축 툴팁 비활성화 - }, - type: 'category', - categories: duration, - labels: { - show: false, // X축 라벨을 숨깁니다. - }, - }, - yaxis: [ - { - labels: { - show: false, // Y축 라벨을 숨깁니다. - }, - min: 0, // 선 그래프의 Y축 최소값 - max: 20, // 선 그래프의 Y축 최대값 - }, - { - labels: { - show: false, // Y축 라벨을 숨깁니다. - }, - min: 0, // 선 그래프의 Y축 최소값 - max: 20, // 선 그래프의 Y축 최대값 - }, - ], - - legend: { - show: false, // 범례를 숨깁니다. - }, - grid: { - show: false, // 그리드 자체는 보임 - padding: { - left: 0, // 왼쪽 패딩을 0으로 설정 - right: 25, // 오른쪽 패딩을 0으로 설정 (필요한 경우) - }, - }, - }; - - useEffect(() => { - const chart = new ApexCharts(document.querySelector('#chart'), options); - chart.render(); - return () => { - chart.destroy(); - }; - }, []); return ( -

나의 대출 금리 변화

+

또래의 대출 금리 범위와 나의 금리 범위 위치

- {data.loan_initial} + {`0 ~ 21`} % - 역대 최저 금리 - {data.loan_initial} + 20대 여자 + {`8 ~ 12`} % - 역대 최고 금리 + 나의 범위
- + + + + + 내 상품의 금리 범위 + + + + 대출 상품을 가입한 20대 여자의 평균 금리 범위 + + {isVisible && }
); }; export default RateChange; + +const StLabelWrapper = styled.div` + display: flex; + flex-direction: column; + gap: 1rem; +`; + +const StLabelContainer = styled.div` + display: flex; + gap: 1rem; +`; + +const StCircle = styled.div` + width: 10px; + height: 10px; + border-radius: 50px; + background-color: #5bc569; +`; + +const StLabel = styled.p` + color: #87898d; + font-family: Pretendard; + font-size: 11px; + font-style: normal; + font-weight: 500; + line-height: normal; +`; + +const StbasicCircle = styled(StCircle)` + background-color: #f6f7f8; +`; diff --git a/src/components/DashboardComs/TransverseGraph.tsx b/src/components/DashboardComs/TransverseGraph.tsx index d359577..8dabebb 100644 --- a/src/components/DashboardComs/TransverseGraph.tsx +++ b/src/components/DashboardComs/TransverseGraph.tsx @@ -1,4 +1,3 @@ -// TransverseGraph.tsx import React, { useRef, useEffect } from 'react'; import * as d3 from 'd3'; import { styled } from 'styled-components'; @@ -7,31 +6,33 @@ type BarChartProps = { value: number; min: number; max: number; -}; // 데이터 타입 정의 +}; -/** 가로막대차트 구현 */ const TransverseGraph: React.FC = ({ value, min, max }) => { const ref = useRef(null); useEffect(() => { - if (ref.current && value) { + if (ref.current && value !== undefined) { const svg = d3.select(ref.current); // 기존 내용을 지우고 새로운 그래프를 그릴 수 있도록 준비합니다. svg.selectAll('*').remove(); - // x축 스케일을 설정합니다. value의 최댓값으로 도메인을 설정합니다. const rate = value; + const width = ref.current.clientWidth; + const start = (8 / 21) * width; // 8% 위치 + const end = (12 / 21) * width; // 12% 위치 + const barWidth = end - start; + const gradient = svg .append('defs') .append('linearGradient') .attr('id', 'gradient') .attr('x1', '0%') - .attr('x2', `100%`) + .attr('x2', '100%') .attr('y1', '0%') .attr('y2', '0%'); - // 그라데이션 색상 정의 gradient .append('stop') .attr('offset', '0%') @@ -49,52 +50,53 @@ const TransverseGraph: React.FC = ({ value, min, max }) => { svg .append('rect') - .attr('width', `100%`) // 배경 막대의 전체 너비 - .attr('height', '12px') // 막대와 동일한 높이 - .attr('fill', '#EEF9F5') // 배경 막대의 색상 - .attr('rx', '8px') // 둥근 모서리를 위한 x축 반경 - .attr('ry', '8px'); // 둥근 모서리를 위한 y축 반경 + .attr('x', 0) + .attr('y', 12) + .attr('width', `100%`) + .attr('height', '12px') + .attr('fill', '#EEF9F5') + .attr('rx', '8px') + .attr('ry', '8px'); - // SVG에 막대를 추가합니다. svg .append('rect') - .attr('height', '12px') // 막대의 높이 - .attr('fill', 'url(#gradient)') // 막대의 색상 - .attr('rx', '8px') // 둥근 모서리를 위한 x축 반경 - .attr('ry', '8px') // 둥근 모서리를 위한 y축 반경 - .attr('width', 0) // 애니메이션 시작을 위해 초기 너비를 0으로 설정합니다. + .attr('x', start) + .attr('y', 12) + .attr('height', '12px') + .attr('fill', 'url(#gradient)') + .attr('rx', start === 0 ? '8px' : '0') // 시작 부분이 아닌 경우 둥근 모서리를 제거 + .attr('ry', start === 0 ? '8px' : '0') + .attr('width', 0) .transition() .duration(1500) - .attr('width', `${rate}%`); // 애니메이션을 통해 최종 너비로 변경합니다. + .attr('width', barWidth); - // 막대에 텍스트를 추가합니다. + // 양 끝에 구분선 추가 svg - .append('text') - .attr('x', 0) // 텍스트의 x 위치 - .attr('y', 25) // 텍스트의 y 위치 - .text(`0%`) - .attr('font-size', '8px') - .attr('fill', '#BFBFBF'); - svg - .append('text') - .attr('x', '95%') - .attr('y', 25) // 텍스트의 y 위치 - .text(`${max + 5}%`) - .attr('font-size', '8px') - .attr('fill', '#BFBFBF'); + .append('line') + .attr('x1', start) + .attr('y1', -50) // 막대 위로 5px + .attr('x2', start) + .attr('y2', 50) // 막대 아래로 5px + .attr('stroke', '#BFBFBF') + .attr('stroke-width', 1) + .attr('stroke-dasharray', '4 2'); // 점선 + svg - .append('text') - .attr('x', `${rate}%`) - .attr('y', 25) // 텍스트의 y 위치 - .text(`${value}%`) - .attr('font-size', '8px') - .attr('fill', '#51b13a'); + .append('line') + .attr('x1', end) + .attr('y1', -50) // 막대 위로 5px + .attr('x2', end) + .attr('y2', 50) // 막대 아래로 5px + .attr('stroke', '#BFBFBF') + .attr('stroke-width', 1) + .attr('stroke-dasharray', '4 2'); // 점선 } }, [value]); return ( -
{value}%
+ {/*
{value}%
*/}
); @@ -128,7 +130,7 @@ const Wrapper = styled.div` const Svg = styled.svg` width: 100%; - height: 2rem; + height: 40px; `; export default TransverseGraph; diff --git a/src/components/MainSidebar.tsx b/src/components/MainSidebar.tsx index 529ae1a..6cc7b05 100644 --- a/src/components/MainSidebar.tsx +++ b/src/components/MainSidebar.tsx @@ -66,29 +66,16 @@ const MainSidebar = () => {

{username} 님, 반가워요!

-

likelion2023

+

FLEXRATE

- -
대시보드
-
    -
  • - 내 대출 관리하기 -
  • -
  • 내 소비 관리하기
  • -
-
분석
    -
  • { - e.preventDefault(); - nav('/editinfo'); - }} - > - 내 신용정보 수정 +
  • + FLEXRATE 대출 상품
  • +
  • 대출 승인 현황
@@ -106,9 +93,9 @@ const MainSidebar = () => { -
설명
+
이용약관
    -
  • 설명보기
  • +
  • 개인 정보 이용 약관
@@ -122,7 +109,8 @@ const Sidebar = styled.aside` left: 0px; border-right: 1px solid var(--Gray3, #d9d9d9); background: #f9fafc; - width: 11.5rem; + max-width: 24rem; + width: 20%; height: 100%; display: flex; flex-direction: column; @@ -180,6 +168,7 @@ const List = styled.div` display: flex; flex-direction: column; gap: 20px; + padding-left: 1rem; .list { padding: 0; diff --git a/src/pages/Dashboard.tsx b/src/pages/Dashboard.tsx index 483c163..0789aae 100644 --- a/src/pages/Dashboard.tsx +++ b/src/pages/Dashboard.tsx @@ -98,32 +98,32 @@ const Dashboard = () => { {isNarrowScreen ? : <>} -
+ 2024년 7월 24일
+ {/*대출상품, 상환날짜, 납부 회차*/}
- {/*대출상품, 상환날짜, 납부 회차*/}
+ {/*FLEXRATE 타당성*/}
- {/*알림*/}
+ {/*금융지식 1*/}
- {/*대출금리,신용평가 점수*/}
- + + {/*금리 범위 / 업직종*/}
- {/*이번달 대출금*/}
+ {/*또래 금리 범위 위치*/}
- {/*금리변화*/}
+ {/*유사 소득층*/}
- {/*대출 히스토리*/}
@@ -131,7 +131,7 @@ const Dashboard = () => { }; const Wrapper = styled.div<{ $isNarrowScreen: boolean; $isVisible: boolean }>` - margin-left: ${(props) => (props.$isNarrowScreen ? '15rem' : '0')}; + margin-left: ${(props) => (props.$isNarrowScreen ? '25rem' : '0')}; width: 100%; height: 100%; box-sizing: border-box; @@ -151,8 +151,9 @@ const Wrapper = styled.div<{ $isNarrowScreen: boolean; $isVisible: boolean }>` const MainDashBoard = styled.span<{ $isNarrowScreen: boolean }>` position: absolute; - width: ${(props) => (props.$isNarrowScreen ? 'calc(100% - 18rem)' : '100%')}; - height: calc(100% - 110px); + width: ${(props) => (props.$isNarrowScreen ? 'calc(100% - 28rem)' : '100%')}; + min-height: 65rem; + height: calc(100% - 16rem); margin: 1.5rem 1rem; `; @@ -183,4 +184,12 @@ const GridContainer = styled.div` } /* 4~5행, 3~4열 */ `; +const StDate = styled.p` + color: var(--Gray8, #595959); + font-family: Pretendard; + font-size: 1.3rem; + font-weight: 600; + margin: 1.6rem 0 1.8rem; +`; + export default Dashboard; diff --git a/src/pages/Login.tsx b/src/pages/Login.tsx index f49d8d8..235dbcf 100644 --- a/src/pages/Login.tsx +++ b/src/pages/Login.tsx @@ -133,7 +133,7 @@ const Login = () => { console.log(tmp); //로그인 api 호출 await axiosInstance - .post('/login', tmp) + .post('/users/login', tmp) .then((res) => { console.log(res); console.log(res.data.token); diff --git a/src/pages/Register.tsx b/src/pages/Register.tsx index daad153..dc6bf6d 100644 --- a/src/pages/Register.tsx +++ b/src/pages/Register.tsx @@ -69,16 +69,16 @@ const Register = () => { const submitRegister = () => { const tmp = { - account: registerValue.accout, + username: registerValue.accout, password: registerValue.password, - name: registerValue.name, - email: registerValue.email, - birth: formatDateToString(birthValue), + nickname: registerValue.name, + // email: registerValue.email, + birth: formatDateToString(birthValue).replace(/-/g, ''), gender: registerValue.gender, - nationality: registerValue.nationality, - phonenumber: registerValue.phonenumber, + // nationality: registerValue.nationality, + // phonenumber: registerValue.phonenumber, }; - console.log(tmp); + //서버통신 axiosInstance .post('/register', tmp) @@ -169,7 +169,7 @@ const Register = () => { /> -
  • + {/*
  • { value={registerValue.email} onChange={handleinput} > -
  • + */} -
      + {/*
      • {btn1 ? ( @@ -207,7 +207,7 @@ const Register = () => { )} [필수] 개인정보 수집 및 이용 동의
      • -
      +
    */}

    이미 계정이 있다면?