diff --git a/.tool-versions b/.tool-versions index 61a78a0..6f8e798 100644 --- a/.tool-versions +++ b/.tool-versions @@ -1 +1 @@ -nodejs 20.5.1 \ No newline at end of file +nodejs 20.15.1 \ No newline at end of file diff --git a/assets/characters/question-flower.svg b/assets/characters/question-flower.svg new file mode 100644 index 0000000..665ed9f --- /dev/null +++ b/assets/characters/question-flower.svg @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/characters/question-tree.svg b/assets/characters/question-tree.svg new file mode 100644 index 0000000..0ec3594 --- /dev/null +++ b/assets/characters/question-tree.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/assets/characters/submit-tree.svg b/assets/characters/submit-tree.svg new file mode 100644 index 0000000..b5f91e5 --- /dev/null +++ b/assets/characters/submit-tree.svg @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/components/badge/badge-period.tsx b/components/badge/badge-period.tsx index 8412924..68e4bce 100644 --- a/components/badge/badge-period.tsx +++ b/components/badge/badge-period.tsx @@ -1,6 +1,5 @@ import { cn } from '@/lib/client/utils' -// !THINK export const periods: { [key: string]: string } = { SIX_MONTHS: '6개월 미만', ONE_YEAR: '6개월-1년 미만', diff --git a/components/carousel/index.tsx b/components/carousel/index.tsx index 4e6790c..9fafc38 100644 --- a/components/carousel/index.tsx +++ b/components/carousel/index.tsx @@ -1,5 +1,5 @@ -import React, { useMemo, useState, useEffect, useCallback, useRef } from 'react' import type { ReactNode, PropsWithChildren } from 'react' +import React, { useMemo, useState, useEffect, useCallback, useRef } from 'react' import { UseEmblaCarouselType } from 'embla-carousel-react' import { EmblaCarouselType } from 'embla-carousel' import { diff --git a/components/compositions/answers/reason/index.tsx b/components/compositions/answers/reason/index.tsx index 73b8c55..55955f2 100644 --- a/components/compositions/answers/reason/index.tsx +++ b/components/compositions/answers/reason/index.tsx @@ -1,5 +1,5 @@ -import { cn } from '@/lib/client/utils' import React, { ComponentPropsWithoutRef, Fragment } from 'react' +import { cn } from '@/lib/client/utils' interface ReasonProps extends ComponentPropsWithoutRef<'div'> { reason: string diff --git a/components/compositions/dashboard/bar-chart/index.tsx b/components/compositions/dashboard/bar-chart/index.tsx new file mode 100644 index 0000000..8084e50 --- /dev/null +++ b/components/compositions/dashboard/bar-chart/index.tsx @@ -0,0 +1,226 @@ +import React, { useEffect, useMemo, useRef } from 'react' + +import { useSession } from '@/provider/session-provider' +import { m, LazyMotion, domAnimation } from 'framer-motion' + +import { PropswithWikiType } from '@/types' +import { RANK_COLOR } from '@/constants' +import useDetailDrawer from '@/hooks/use-detail-drawer' +import { useInViewRef } from '@/hooks/use-in-view-ref' +import { BarChartType } from '@/model/dashboard.entity' +import { Button } from '@/components/ui' + +export const BarChart = ({ + isLoading, + dashboard, + wikiType, +}: PropswithWikiType<{ + isLoading?: boolean + dashboard: BarChartType +}>) => { + const { data } = useSession() + const { handle } = useDetailDrawer() + + const { inView, ref } = useInViewRef({ + once: true, + }) + + const orderByMaxValueList = useMemo(() => { + const arr = dashboard?.rank?.sort((a, b) => b.percentage - a.percentage) + + return arr?.map((item, index) => ({ + ...item, + color: + RANK_COLOR[wikiType][index] ?? + `rgb(${Math.floor(Math.random() * 255)},${Math.floor(Math.random() * 255)},${Math.floor(Math.random() * 255)})`, + text: item.legend.split(' ')[1], + })) + }, [dashboard?.rank, wikiType]) + + return ( + +
+ {isLoading ? ( + <> +
+
+
+
+
+
+ + ) : ( + <> + {orderByMaxValueList?.[0].text === '직접 입력' ? ( + 친구가 써준 답변을 확인해보세요 + ) : ( +

+ )} +
+ {orderByMaxValueList + ?.slice(0, 3) + .map((rank) => ( + + ))} +
+
    + {orderByMaxValueList?.slice(0, 3).map((item) => { + return ( + + ) + })} +
+
+ +
+ + )} +
+ + ) +} + +interface BarProps { + percent: number + color: string + active?: boolean +} + +function Bar({ color, percent, active = false }: BarProps) { + return ( + + ) +} +interface IncreamentPercent { + color: string + percent: number + title: string + active?: boolean +} +function IncreamentPercent({ + active, + color, + percent, + title, +}: IncreamentPercent) { + const countRef = useRef(null) + useEffect(() => { + let animationId: number + + const countAnimation = () => { + if (countRef.current) { + const startValue = 0 + + const DURATION = 3500 + const easeOutQuint = (x: number): number => { + return 1 - Math.pow(1 - x, 5) + } + + const target = percent + + // 최초 시작 시간 + let start: number + + const animate = () => { + if (!start) start = new Date().getTime() + // 현재시간 - 최초시작시간 + const timestamp = new Date().getTime() + const progress = timestamp - start + if (progress >= DURATION) { + if (countRef.current) { + countRef.current.innerText = `${isNaN(target) ? 100 : target}%` + } + return cancelAnimationFrame(animationId) + } + + const p = progress / DURATION + const value = easeOutQuint(p) + if (countRef.current) { + const dest = target - startValue + countRef.current.innerText = `${(isNaN(startValue) ? 0 : startValue ?? 0) + Math.round(dest * value) ?? 0}%` + } + if (p < DURATION) { + animationId = requestAnimationFrame(animate) + } + } + + animationId = requestAnimationFrame(animate) + } + } + + if (active) { + countAnimation() + } + return () => { + cancelAnimationFrame(animationId) + } + }, [active, percent]) + return ( +
  • +
    +
    + {title} +
    + + 0% + +
  • + ) +} diff --git a/components/compositions/dashboard/best-worth/index.tsx b/components/compositions/dashboard/best-worth/index.tsx index a6135b3..8757adf 100644 --- a/components/compositions/dashboard/best-worth/index.tsx +++ b/components/compositions/dashboard/best-worth/index.tsx @@ -1,260 +1,262 @@ -import { useMemo, useRef } from 'react' -import { cn, useBrowserLayoutEffect } from '@/lib/client/utils' -import { Pie, Sector } from 'recharts' -import { Cell } from 'recharts' -import { PieChart, ResponsiveContainer } from 'recharts' -import { PieSectorDataItem } from 'recharts/types/polar/Pie' -import { useInViewRef } from '@/hooks/use-in-view-ref' -import { getDashboardQuery } from '@/queries/dashboard' -import { useQuery } from '@tanstack/react-query' -import { FilterType } from '@/hooks/use-filter' -import { RANK_COLOR } from '@/constants' -import { Button } from '@/components/ui/button' -import useDetailDrawer from '@/hooks/use-detail-drawer' -import { BEST_WORTH } from '@/model/dashboard.entity' -import { PropswithWikiType } from '@/types' +// import { useMemo, useRef } from 'react' +// import { useQuery } from '@tanstack/react-query' +// import { cn, useBrowserLayoutEffect } from '@/lib/client/utils' -export interface Payload { - percent: number - name: number - midAngle: number - middleRadius: number - cx: number - cy: number - stroke: string - fill: string - legend: string - percentage: number - color: string - innerRadius: number - outerRadius: number - maxRadius: number - value: number - startAngle: number - endAngle: number - paddingAngle: number - tabIndex: number -} -const RenderActiveShape = (props: PieSectorDataItem) => { - const { - cx, - cy, - innerRadius, - outerRadius, - startAngle, - endAngle, - fill, - percent, - color, - legend, - } = props as PieSectorDataItem & Payload - const textRef = useRef(null) - const IsStartAnimation = useRef(false) - useBrowserLayoutEffect(() => { - if (!IsStartAnimation.current) { - const DURATION = 1500 - const easeOutQuint = (x: number): number => { - return 1 - Math.pow(1 - x, 5) - } +// import { Pie, Sector } from 'recharts' +// import { Cell } from 'recharts' +// import { PieChart, ResponsiveContainer } from 'recharts' +// import { PieSectorDataItem } from 'recharts/types/polar/Pie' - const target = (percent ?? 0) * 100 +// import { getDashboardQuery } from '@/queries/dashboard' +// import { PropswithWikiType } from '@/types' +// import { BEST_WORTH } from '@/model/dashboard.entity' +// import { useInViewRef } from '@/hooks/use-in-view-ref' +// import useDetailDrawer from '@/hooks/use-detail-drawer' +// import { FilterType } from '@/hooks/use-filter' +// import { RANK_COLOR } from '@/constants' +// import { Button } from '@/components/ui/button' - let animationId: number - // 최초 시작 시간 - let start: number +// export interface Payload { +// percent: number +// name: number +// midAngle: number +// middleRadius: number +// cx: number +// cy: number +// stroke: string +// fill: string +// legend: string +// percentage: number +// color: string +// innerRadius: number +// outerRadius: number +// maxRadius: number +// value: number +// startAngle: number +// endAngle: number +// paddingAngle: number +// tabIndex: number +// } +// const RenderActiveShape = (props: PieSectorDataItem) => { +// const { +// cx, +// cy, +// innerRadius, +// outerRadius, +// startAngle, +// endAngle, +// fill, +// percent, +// color, +// legend, +// } = props as PieSectorDataItem & Payload +// const textRef = useRef(null) +// const IsStartAnimation = useRef(false) +// useBrowserLayoutEffect(() => { +// if (!IsStartAnimation.current) { +// const DURATION = 1500 +// const easeOutQuint = (x: number): number => { +// return 1 - Math.pow(1 - x, 5) +// } - const animate = () => { - if (!start) start = new Date().getTime() - // 현재시간 - 최초시작시간 - const timestamp = new Date().getTime() - const progress = timestamp - start - if (progress >= DURATION) { - if (textRef.current) { - textRef.current.textContent = `${Math.floor(target)}%` - } - return cancelAnimationFrame(animationId) - } +// const target = (percent ?? 0) * 100 - const p = progress / DURATION - const value = easeOutQuint(p) - if (textRef.current) { - textRef.current.textContent = `${Math.round(target * value)}%` - } - if (p < DURATION) { - animationId = requestAnimationFrame(animate) - } - } +// let animationId: number +// // 최초 시작 시간 +// let start: number - animationId = requestAnimationFrame(animate) - IsStartAnimation.current = true - } - }, [percent]) +// const animate = () => { +// if (!start) start = new Date().getTime() +// // 현재시간 - 최초시작시간 +// const timestamp = new Date().getTime() +// const progress = timestamp - start +// if (progress >= DURATION) { +// if (textRef.current) { +// textRef.current.textContent = `${Math.floor(target)}%` +// } +// return cancelAnimationFrame(animationId) +// } - return ( - - - {legend.split(' ')[2]} - - - - - ) -} +// const p = progress / DURATION +// const value = easeOutQuint(p) +// if (textRef.current) { +// textRef.current.textContent = `${Math.round(target * value)}%` +// } +// if (p < DURATION) { +// animationId = requestAnimationFrame(animate) +// } +// } -function BestWorth({ - filter, - wikiType, -}: PropswithWikiType<{ - filter: FilterType -}>) { - const { handle } = useDetailDrawer() - const { ref, inView } = useInViewRef({ - once: true, - margin: '5%', - }) +// animationId = requestAnimationFrame(animate) +// IsStartAnimation.current = true +// } +// }, [percent]) - const { data: statisics, isLoading } = useQuery({ - ...getDashboardQuery(wikiType, filter), - select: (data) => { - const bestWorth = data.data?.statistics.find( - (item) => item.dashboardType === 'BEST_WORTH', - ) +// return ( +// +// +// {legend.split(' ')[2]} +// +// +// +// +// ) +// } - return bestWorth as BEST_WORTH - }, - }) +// function BestWorth({ +// filter, +// wikiType, +// }: PropswithWikiType<{ +// filter: FilterType +// }>) { +// const { handle } = useDetailDrawer() +// const { ref, inView } = useInViewRef({ +// once: true, +// margin: '5%', +// }) - const orderByMaxValueList = useMemo(() => { - const arr = statisics?.rank?.sort((a, b) => b.percentage - a.percentage) +// const { data: statisics, isLoading } = useQuery({ +// ...getDashboardQuery(wikiType, filter), +// select: (data) => { +// const bestWorth = data.data?.statistics.find( +// (item) => item.dashboardType === 'BEST_WORTH', +// ) - return arr?.map((item, index) => ({ - ...item, - percentage: item.percentage ?? 0, - color: - RANK_COLOR[index] ?? - `rgb(${Math.floor(Math.random() * 255)},${Math.floor(Math.random() * 255)},${Math.floor(Math.random() * 255)})`, - })) - }, [statisics]) +// return bestWorth as BEST_WORTH +// }, +// }) - return ( -
    - {isLoading ? ( - <> -
    -
    -
    -
    -
    - - ) : ( - <> -

    - {orderByMaxValueList?.[0].legend.split(' ')[2] === '직접' ? ( - 친구가 써준 답변을 확인하세요 - ) : ( - - 가장 중요한 것은{' '} - - {orderByMaxValueList?.[0].legend.split(' ')[2]} - - 이네요 - - )} -

    -
    -
    - {inView && ( - - - - {orderByMaxValueList?.map((entry, index) => ( - - ))} - - - - )} -
    -
    - {orderByMaxValueList?.slice(0, 3).map((item) => { - return ( -
    -
    -

    - {item.legend.split(' ')[2]} -

    - - {item.percentage}% - -
    - ) - })} -
    -
    -
    - -
    - - )} -
    - ) -} +// const orderByMaxValueList = useMemo(() => { +// const arr = statisics?.rank?.sort((a, b) => b.percentage - a.percentage) -export default BestWorth +// return arr?.map((item, index) => ({ +// ...item, +// percentage: item.percentage ?? 0, +// color: +// RANK_COLOR[index] ?? +// `rgb(${Math.floor(Math.random() * 255)},${Math.floor(Math.random() * 255)},${Math.floor(Math.random() * 255)})`, +// })) +// }, [statisics]) + +// return ( +//
    +// {isLoading ? ( +// <> +//
    +//
    +//
    +//
    +//
    +// +// ) : ( +// <> +//

    +// {orderByMaxValueList?.[0].legend.split(' ')[2] === '직접' ? ( +// 친구가 써준 답변을 확인하세요 +// ) : ( +// +// 가장 중요한 것은{' '} +// +// {orderByMaxValueList?.[0].legend.split(' ')[2]} +// +// 이네요 +// +// )} +//

    +//
    +//
    +// {inView && ( +// +// +// +// {orderByMaxValueList?.map((entry, index) => ( +// +// ))} +// +// +// +// )} +//
    +//
    +// {orderByMaxValueList?.slice(0, 3).map((item) => { +// return ( +//
    +//
    +//

    +// {item.legend.split(' ')[2]} +//

    +// +// {item.percentage}% +// +//
    +// ) +// })} +//
    +//
    +//
    +// +//
    +// +// )} +//
    +// ) +// } + +// export default BestWorth diff --git a/components/compositions/dashboard/binary-chart/index.tsx b/components/compositions/dashboard/binary-chart/index.tsx new file mode 100644 index 0000000..167981c --- /dev/null +++ b/components/compositions/dashboard/binary-chart/index.tsx @@ -0,0 +1,195 @@ +import React, { useId, useMemo } from 'react' + +import { useSession } from '@/provider/session-provider' +import { m, LazyMotion, domAnimation } from 'framer-motion' + +import { PropswithWikiType } from '@/types' +import { MAIN_COLOR } from '@/constants' +import useDetailDrawer from '@/hooks/use-detail-drawer' +import { useInViewRef } from '@/hooks/use-in-view-ref' +import { BinaryChartType } from '@/model/dashboard.entity' +import { Button } from '@/components/ui' +import { cn } from '@/lib/client/utils' + +export const BinaryChart = ({ + isLoading, + dashboard, +}: PropswithWikiType<{ + isLoading?: boolean + dashboard: BinaryChartType +}>) => { + const { data } = useSession() + const { handle } = useDetailDrawer() + + const { inView, ref } = useInViewRef({ + once: true, + }) + + const myAvg = useMemo(() => { + const total = 100 + + return { + mine: (dashboard.percentage ?? 0) / total, + entire: (total - dashboard.percentage ?? 0) / total, + } + }, [dashboard]) + + const color = useMemo( + () => + MAIN_COLOR.BINARY[Math.floor(Math.random() * MAIN_COLOR.BINARY.length)], + [], + ) + + return ( + +
    + {isLoading || !dashboard ? ( + <> +
    +
    +
    +
    +
    +
    +
    + + ) : ( + <> +

    + +
    + + +
    + + )} +
    + +
    +
    + + ) +} + +interface BinaryBarProps { + active?: boolean + isMe?: boolean + value: number + positive?: boolean + color?: { from: string; to: string } +} + +function BinaryBarBar({ + active, + value, + positive, + color, + isMe = true, +}: BinaryBarProps) { + const id = useId() + return ( + +
    + {positive ? ( + + + + ) : ( + + + + )} + + {value}% + + +
    +
    + ) +} diff --git a/components/compositions/dashboard/bubble-chart/index.tsx b/components/compositions/dashboard/bubble-chart/index.tsx new file mode 100644 index 0000000..a75757f --- /dev/null +++ b/components/compositions/dashboard/bubble-chart/index.tsx @@ -0,0 +1,206 @@ +import { useMemo, useRef } from 'react' +import { useSession } from '@/provider/session-provider' +import { cn } from '@/lib/client/utils' +import { useInView } from 'framer-motion' +import { motion } from 'framer-motion' +import { WIKI_COLORS } from '@/pages/dashboard' + +import { RANK_COLOR } from '@/constants' +import { PropswithWikiType, WikiType } from '@/types' +import { BubbleChartType, Rank } from '@/model/dashboard.entity' +import { Button } from '@/components/ui' + +export const BubbleChart = ({ + dashboard, + + wikiType, +}: PropswithWikiType<{ + dashboard: BubbleChartType + isLoading?: boolean +}>) => { + const { data } = useSession() + + const orderByMaxValueList = useMemo(() => { + const arr = dashboard?.rank?.sort((a, b) => b.percentage - a.percentage) + + return arr?.map((item, index) => ({ + ...item, + percentage: item.percentage ?? 0, + color: + RANK_COLOR[wikiType][index] ?? + `rgb(${Math.floor(Math.random() * 255)},${Math.floor(Math.random() * 255)},${Math.floor(Math.random() * 255)})`, + })) + }, [dashboard?.rank, wikiType]) + return ( +
    +

    + {data?.user?.name}님에게 가장 중요한 것은 +

    + + +
    + ) +} + +/** + * 공이 1개일 경우 + * 공이 2개일 경우 + * 공이 3개일 경우 + */ + +type BubbleOption = { + left: number + top: number + mainColor: string | ((wikiType: WikiType) => string) + subColor: string +} + +type BALL_ONE = [BubbleOption] +type BALL_TWO = [BubbleOption, BubbleOption] +type BALL_THREE = [BubbleOption, BubbleOption, BubbleOption] + +type BubbleChartProps = { + data?: Rank[] +} + +const BUBBLE_OPTIONS: [BALL_ONE, BALL_TWO, BALL_THREE] = [ + [ + { + mainColor: (wikiType: WikiType) => WIKI_COLORS[wikiType].MAIN_COLOR, + subColor: '#BFF1CF', + left: 50, + top: 50, + }, + ], + [ + { + mainColor: (wikiType: WikiType) => WIKI_COLORS[wikiType].MAIN_COLOR, + subColor: '#BFF1CF', + left: 30, + top: 50, + }, + { + mainColor: '#199EF0', + subColor: '#B4E6FF', + left: 70, + top: 50, + }, + ], + [ + { + mainColor: (wikiType: WikiType) => WIKI_COLORS[wikiType].MAIN_COLOR, + subColor: '#BFF1CF', + left: 30, + top: 50, + }, + { + mainColor: '#199EF0', + subColor: '#B4E6FF', + left: 70, + top: 30, + }, + { + mainColor: '#FDD82E', + subColor: '#FFF59B', + left: 65, + top: 65, + }, + ], +] + +const GrowingCircles = ({ + data, + wikiType, +}: PropswithWikiType) => { + const containerRef = useRef(null) + const bubbles = useMemo(() => { + if (!data) return null + const lastIndex = data.findIndex((i) => i.percentage === 0) + if (lastIndex <= 0) return + const currentBubbleOptions = + BUBBLE_OPTIONS[lastIndex > 3 ? 2 : lastIndex - 1] + return currentBubbleOptions?.map((item, index) => ({ + ...item, + id: data[index].legend, + percentage: data[index].percentage, + label: data[index].legend, + })) + }, [data]) + + const totalPercentage = useMemo(() => { + if (!bubbles?.length) return 0 + return bubbles.reduce((acc, cur) => acc + cur.percentage, 0) + }, [bubbles]) + + const inview = useInView(containerRef, { + once: true, + margin: '-100px', + }) + + return ( +
    + {inview && + bubbles && + bubbles.map((bubble, index) => ( + +

    + {bubble.percentage}% +

    +

    + {bubble.label.split(' ')[1]} +

    +
    + ))} +
    + ) +} + +function mapValue( + value: number, + start1: number, + end1: number, + start2: number, + end2: number, +): number { + return start2 + ((value - start1) * (end2 - start2)) / (end1 - start1) +} diff --git a/components/compositions/dashboard/character/index.tsx b/components/compositions/dashboard/character/index.tsx index f5f97a8..b3c9001 100644 --- a/components/compositions/dashboard/character/index.tsx +++ b/components/compositions/dashboard/character/index.tsx @@ -1,252 +1,254 @@ -import { m, LazyMotion, domAnimation } from 'framer-motion' -import { fadeInProps } from '@/variants' -import { useInViewRef } from '@/hooks/use-in-view-ref' -import { useSession } from '@/provider/session-provider' -import { FilterType } from '@/hooks/use-filter' -import { useQuery } from '@tanstack/react-query' -import { getDashboardQuery } from '@/queries/dashboard' -import { CHARACTER_NAMES, CHARACTER_TYPE } from '@/model/dashboard.entity' -import { useMemo } from 'react' -import Link from 'next/link' -import { PropswithWikiType } from '@/types' +// import { useMemo } from 'react' +// import Link from 'next/link' +// import { useQuery } from '@tanstack/react-query' +// import { useSession } from '@/provider/session-provider' -const characterMap = { - busy: [ - { - emoji: '🛌', - top: '주말마다', - bottom: '집에서 쉬는 편', - }, - { - emoji: '🕐', - top: '주말마다', - bottom: '약속이 있는 편', - }, - ], - friendly: [ - { emoji: '🫢', top: '친해지는데', bottom: '시간이 걸리는 편' }, - { emoji: '🤗', top: '사람들과', bottom: '빨리 친해지는 편' }, - ], - mbti: [ - { - emoji: '🙅‍♂️', - top: 'MBTI에', - bottom: '몰입하지 않는 편', - }, - { - emoji: '🧐', - top: 'MBTI에 ', - bottom: '과몰입하는 편', - }, - ], - similar: [ - { - emoji: '🙅‍♂️', - top: '답변자들과', - bottom: '다른 성향', - }, - { - emoji: '🙆‍♂️', - top: '답변자들과', - bottom: '비슷한 성향', - }, - ], -} +// import { m, LazyMotion, domAnimation } from 'framer-motion' +// import { fadeInProps } from '@/variants' +// import { useInViewRef } from '@/hooks/use-in-view-ref' +// import { FilterType } from '@/hooks/use-filter' -const Character = ({ - filter, - wikiType, -}: PropswithWikiType<{ - filter: FilterType -}>) => { - const { data: statisics, isLoading } = useQuery({ - ...getDashboardQuery(wikiType, filter), - select(data) { - return data.data?.statistics.find( - (item) => item.dashboardType === 'CHARACTER', - ) as CHARACTER_TYPE - }, - }) +// import { getDashboardQuery } from '@/queries/dashboard' +// import { PropswithWikiType } from '@/types' +// import { CHARACTER_NAMES, CHARACTER_TYPE } from '@/model/dashboard.entity' - const parsedStatistics = useMemo(() => { - if (!statisics?.characters?.length) return null - return Object.fromEntries( - statisics.characters.map((item) => { - return [item.name, { value: item.value, questionId: item.questionId }] - }), - ) as { - [key in CHARACTER_NAMES]: { - value: boolean - questionId: string - } - } - }, [statisics]) +// const characterMap = { +// busy: [ +// { +// emoji: '🛌', +// top: '주말마다', +// bottom: '집에서 쉬는 편', +// }, +// { +// emoji: '🕐', +// top: '주말마다', +// bottom: '약속이 있는 편', +// }, +// ], +// friendly: [ +// { emoji: '🫢', top: '친해지는데', bottom: '시간이 걸리는 편' }, +// { emoji: '🤗', top: '사람들과', bottom: '빨리 친해지는 편' }, +// ], +// mbti: [ +// { +// emoji: '🙅‍♂️', +// top: 'MBTI에', +// bottom: '몰입하지 않는 편', +// }, +// { +// emoji: '🧐', +// top: 'MBTI에 ', +// bottom: '과몰입하는 편', +// }, +// ], +// similar: [ +// { +// emoji: '🙅‍♂️', +// top: '답변자들과', +// bottom: '다른 성향', +// }, +// { +// emoji: '🙆‍♂️', +// top: '답변자들과', +// bottom: '비슷한 성향', +// }, +// ], +// } - return ( - -
    - {isLoading || !parsedStatistics ? ( - <> -
    -
    -
    -
    -
    -
    -
    - - ) : ( - - )} -
    - - ) -} +// const Character = ({ +// filter, +// wikiType, +// }: PropswithWikiType<{ +// filter: FilterType +// }>) => { +// const { data: statisics, isLoading } = useQuery({ +// ...getDashboardQuery(wikiType, filter), +// select(data) { +// return data.data?.statistics.find( +// (item) => item.dashboardType === 'CHARACTER', +// ) as CHARACTER_TYPE +// }, +// }) -export default Character +// const parsedStatistics = useMemo(() => { +// if (!statisics?.characters?.length) return null +// return Object.fromEntries( +// statisics.characters.map((item) => { +// return [item.name, { value: item.value, questionId: item.questionId }] +// }), +// ) as { +// [key in CHARACTER_NAMES]: { +// value: boolean +// questionId: string +// } +// } +// }, [statisics]) -const cardPickingVariants = { - initial: { - rotateX: '40deg', - scale: 0.3, - }, - picking: { - rotateX: '0deg', - scale: 1, - transition: { - delay: 0.3, - duration: 0.2, - }, - }, -} -type ParsedStatistics = { - [key in CHARACTER_NAMES]: { - value: boolean - questionId: string - } -} +// return ( +// +//
    +// {isLoading || !parsedStatistics ? ( +// <> +//
    +//
    +//
    +//
    +//
    +//
    +//
    +// +// ) : ( +// +// )} +//
    +// +// ) +// } -function CharacterInfo({ statisics }: { statisics: ParsedStatistics }) { - const { data } = useSession() - const { inView, ref } = useInViewRef({ once: true }) +// export default Character - return ( - <> -

    - {data?.user?.name ?? ''}님은 이런사람이에요 -

    - - - - - - - - ) -} +// const cardPickingVariants = { +// initial: { +// rotateX: '40deg', +// scale: 0.3, +// }, +// picking: { +// rotateX: '0deg', +// scale: 1, +// transition: { +// delay: 0.3, +// duration: 0.2, +// }, +// }, +// } +// type ParsedStatistics = { +// [key in CHARACTER_NAMES]: { +// value: boolean +// questionId: string +// } +// } -function CharacterBlock({ - emoji, - bottomText, - href, - topText, -}: { - emoji: string - topText: string - bottomText: string - href: string -}) { - const { inView, ref } = useInViewRef({ once: true }) +// function CharacterInfo({ statisics }: { statisics: ParsedStatistics }) { +// const { data } = useSession() +// const { inView, ref } = useInViewRef({ once: true }) - return ( - -

    {emoji}

    -
    -

    - {topText} -
    - {bottomText} -

    - - 자세히 보기 - -
    -
    - ) -} +// return ( +// <> +//

    +// {data?.user?.name ?? ''}님은 이런사람이에요 +//

    +// +// +// +// +// +// +// +// ) +// } + +// function CharacterBlock({ +// emoji, +// bottomText, +// href, +// topText, +// }: { +// emoji: string +// topText: string +// bottomText: string +// href: string +// }) { +// const { inView, ref } = useInViewRef({ once: true }) + +// return ( +// +//

    {emoji}

    +//
    +//

    +// {topText} +//
    +// {bottomText} +//

    +// +// 자세히 보기 +// +//
    +//
    +// ) +// } diff --git a/components/compositions/dashboard/happy/index.tsx b/components/compositions/dashboard/happy/index.tsx index 4a5ec05..6b9bc65 100644 --- a/components/compositions/dashboard/happy/index.tsx +++ b/components/compositions/dashboard/happy/index.tsx @@ -1,161 +1,240 @@ -import { Button } from '@/components/ui' -import { RANK_COLOR } from '@/constants' -import useDetailDrawer from '@/hooks/use-detail-drawer' -import { FilterType } from '@/hooks/use-filter' -import { useInViewRef } from '@/hooks/use-in-view-ref' -import { cn } from '@/lib/client/utils' -import { HAPPY_OR_SAD } from '@/model/dashboard.entity' -import { getDashboardQuery } from '@/queries/dashboard' -import { PropswithWikiType } from '@/types' -import { useQuery } from '@tanstack/react-query' -import { HTMLMotionProps, m, LazyMotion, domAnimation } from 'framer-motion' -import React, { useMemo } from 'react' - -const Happy = ({ - wikiType, - filter, -}: PropswithWikiType<{ - filter: FilterType -}>) => { - const { handle } = useDetailDrawer() - const { data: statisics, isLoading } = useQuery({ - ...getDashboardQuery(wikiType, filter), - select(data) { - return data.data?.statistics.find( - (item) => item.dashboardType === 'HAPPY', - ) as HAPPY_OR_SAD - }, - }) - - const { inView, ref } = useInViewRef({ - once: true, - amount: 'all', - }) - - const orderByMaxValueList = useMemo(() => { - const arr = statisics?.rank?.sort((a, b) => b.percentage - a.percentage) - - return arr?.map((item, index) => ({ - ...item, - color: - RANK_COLOR[index] ?? - `rgb(${Math.floor(Math.random() * 255)},${Math.floor(Math.random() * 255)},${Math.floor(Math.random() * 255)})`, - text: item.legend.split(' ')[1], - })) - }, [statisics]) - - return ( - -
    - {isLoading ? ( - <> -
    -
    -
    -
    -
    -
    - - ) : ( - <> -

    - {orderByMaxValueList?.[0].text === '직접 입력' ? ( - 친구가 써준 답변을 확인해보세요 - ) : ( -

    - 기쁠 때
    - - {' '} - {orderByMaxValueList?.[0].text} - -

    - )} - -
    - {orderByMaxValueList?.slice(0, 3).map((item, index) => { - return ( - - ) - })} -
    -
    - -
    - - )} -
    - - ) -} - -export default Happy - -interface BarProps extends HTMLMotionProps<'div'> { - title: string - percent: number - color: string - active?: boolean - accent?: boolean -} - -function Bar({ - color, - title, - percent, - active = false, - accent = false, - ...rest -}: BarProps) { - const font = accent ? 'text-body1-bold' : 'title-body-medium' - const 최소바크기보정값 = (80 * percent) / 100 + 10 - return ( -
    -

    {title}

    -
    - -

    - {percent}% -

    -
    -
    - ) -} +// import React, { useEffect, useMemo, useRef } from 'react' +// import { useQuery } from '@tanstack/react-query' +// import { useSession } from '@/provider/session-provider' +// import { m, LazyMotion, domAnimation } from 'framer-motion' + +// import useDetailDrawer from '@/hooks/use-detail-drawer' +// import { FilterType } from '@/hooks/use-filter' +// import { useInViewRef } from '@/hooks/use-in-view-ref' + +// import { RANK_COLOR } from '@/constants' +// import { getDashboardQuery } from '@/queries/dashboard' +// import { PropswithWikiType } from '@/types' +// import { HAPPY_OR_SAD } from '@/model/dashboard.entity' + +// import { Button } from '@/components/ui' + +// const Happy = ({ +// wikiType, +// filter, +// }: PropswithWikiType<{ +// filter: FilterType +// }>) => { +// const { data } = useSession() +// const { handle } = useDetailDrawer() +// const { data: statisics, isLoading } = useQuery({ +// ...getDashboardQuery(wikiType, filter), +// select(data) { +// return data.data?.statistics.find( +// (item) => item.dashboardType === 'HAPPY', +// ) as HAPPY_OR_SAD +// }, +// }) + +// const { inView, ref } = useInViewRef({ +// once: true, +// amount: 'all', +// }) + +// data?.user?.name +// const orderByMaxValueList = useMemo(() => { +// const arr = statisics?.rank?.sort((a, b) => b.percentage - a.percentage) + +// return arr?.map((item, index) => ({ +// ...item, +// color: +// RANK_COLOR[index] ?? +// `rgb(${Math.floor(Math.random() * 255)},${Math.floor(Math.random() * 255)},${Math.floor(Math.random() * 255)})`, +// text: item.legend.split(' ')[1], +// })) +// }, [statisics]) + +// return ( +// +//
    +// {isLoading ? ( +// <> +//
    +//
    +//
    +//
    +//
    +//
    +// +// ) : ( +// <> +// {orderByMaxValueList?.[0].text === '직접 입력' ? ( +// 친구가 써준 답변을 확인해보세요 +// ) : ( +//

    +// )} +//
    +// {orderByMaxValueList +// ?.slice(0, 3) +// .map((rank) => ( +// +// ))} +//
    +//
      +// {orderByMaxValueList?.slice(0, 3).map((item) => { +// return ( +// +// ) +// })} +//
    +//
    +// +//
    +// +// )} +//
    +// +// ) +// } + +// export default Happy + +// interface BarProps { +// percent: number +// color: string +// active?: boolean +// } + +// function Bar({ color, percent, active = false }: BarProps) { +// return ( +// +// ) +// } +// interface IncreamentPercent { +// color: string +// percent: number +// title: string +// active?: boolean +// } +// function IncreamentPercent({ +// active, +// color, +// percent, +// title, +// }: IncreamentPercent) { +// const countRef = useRef(null) +// useEffect(() => { +// let animationId: number + +// const countAnimation = () => { +// if (countRef.current) { +// const startValue = 0 + +// const DURATION = 3500 +// const easeOutQuint = (x: number): number => { +// return 1 - Math.pow(1 - x, 5) +// } + +// const target = percent + +// // 최초 시작 시간 +// let start: number + +// const animate = () => { +// if (!start) start = new Date().getTime() +// // 현재시간 - 최초시작시간 +// const timestamp = new Date().getTime() +// const progress = timestamp - start +// if (progress >= DURATION) { +// if (countRef.current) { +// countRef.current.innerText = `${isNaN(target) ? 100 : target}%` +// } +// return cancelAnimationFrame(animationId) +// } + +// const p = progress / DURATION +// const value = easeOutQuint(p) +// if (countRef.current) { +// const dest = target - startValue +// countRef.current.innerText = `${(isNaN(startValue) ? 0 : startValue ?? 0) + Math.round(dest * value) ?? 0}%` +// } +// if (p < DURATION) { +// animationId = requestAnimationFrame(animate) +// } +// } + +// animationId = requestAnimationFrame(animate) +// } +// } + +// if (active) { +// countAnimation() +// } +// return () => { +// cancelAnimationFrame(animationId) +// } +// }, [active, percent]) +// return ( +//
  • +//
    +//
    +// {title} +//
    +// +// 0% +// +//
  • +// ) +// } diff --git a/components/compositions/dashboard/know-about/index.tsx b/components/compositions/dashboard/know-about/index.tsx index 7f1d5c1..71265a1 100644 --- a/components/compositions/dashboard/know-about/index.tsx +++ b/components/compositions/dashboard/know-about/index.tsx @@ -1,11 +1,11 @@ -import useDetailDrawer from '@/hooks/use-detail-drawer' -import { cn } from '@/lib/client/utils' -import { SHORT_TYPE_LIST } from '@/model/question.entity' +import React from 'react' +import { useQuery } from '@tanstack/react-query' import { useSession } from '@/provider/session-provider' +import { cn } from '@/lib/client/utils' +import useDetailDrawer from '@/hooks/use-detail-drawer' import { getQuestionByTypeQuery } from '@/queries/question' import { WikiType, PropswithWikiType } from '@/types' -import { useQuery } from '@tanstack/react-query' -import React from 'react' +import { SHORT_TYPE_LIST } from '@/model/question.entity' const SHORT_FILTER: { [wikiType in WikiType]: { @@ -21,12 +21,8 @@ const SHORT_FILTER: { CHARACTER_CELEBRITY_ASSOCIATION: '닮은 캐릭터(연예인)은?', }, ROMANCE: { - FIRST_IMPRESSION: '👀 나의 첫인상은?', - CHARACTER_CELEBRITY_ASSOCIATION: '🤔 나는 누구와 닮았나요?', - FIVE_LETTER_WORD: '🧐 나를 5글자로 표현한다면?', - LEARNING_ASPIRATION: '📚 나의 이런점은 꼭 배우고 싶어요!', - SECRET_PLEASURE: '😍 내가 혼자 몰래 좋아하고 있는 것은?', - MOST_USED_WORD: '💬 내가 가장 많이 사용하는 단어는?', + IDEAL_TYPE: '이상형은?', + FLIRTING_METHOD: '이성에게 하는 플러팅 방법은?', }, } export const KnowAbout = ({ wikiType }: PropswithWikiType) => { @@ -38,7 +34,6 @@ export const KnowAbout = ({ wikiType }: PropswithWikiType) => { return data.data }, }) - return (

    diff --git a/components/compositions/dashboard/money/index.tsx b/components/compositions/dashboard/money/index.tsx index b7b219f..933d1e5 100644 --- a/components/compositions/dashboard/money/index.tsx +++ b/components/compositions/dashboard/money/index.tsx @@ -1,49 +1,49 @@ -import { Button } from '@/components/ui' +import React, { useId, useMemo, useState } from 'react' + +import { useSession } from '@/provider/session-provider' +import { cn } from '@/lib/client/utils' +import { LazyMotion, domAnimation, m } from 'framer-motion' + import useDetailDrawer from '@/hooks/use-detail-drawer' -import { FilterType } from '@/hooks/use-filter' + import { useInViewRef } from '@/hooks/use-in-view-ref' -import { cn } from '@/lib/client/utils' -import { MONEY } from '@/model/dashboard.entity' -import { useSession } from '@/provider/session-provider' -import { getDashboardQuery } from '@/queries/dashboard' + +import { MAIN_COLOR } from '@/constants' + import { PropswithWikiType } from '@/types' -import { useQuery } from '@tanstack/react-query' -import { LazyMotion, domAnimation, m } from 'framer-motion' -import React, { useMemo, useState } from 'react' +import { MoneyChartType } from '@/model/dashboard.entity' + +import { Button } from '@/components/ui' const Money = ({ - wikiType, - filter, + isLoading, + dashboard, }: PropswithWikiType<{ - filter: FilterType + isLoading?: boolean + dashboard: MoneyChartType }>) => { const { handle } = useDetailDrawer() - - const { data: statisics, isLoading } = useQuery({ - ...getDashboardQuery(wikiType, filter), - select(data) { - return data.data?.statistics.find( - (item) => item.dashboardType === 'MONEY', - ) as MONEY - }, - }) + const { data } = useSession() const { ref, inView } = useInViewRef({ once: true, amount: 'all', }) const myAvg = useMemo(() => { - const total = (statisics?.average ?? 0) + (statisics?.entireAverage ?? 0) + const total = (dashboard?.average ?? 0) + (dashboard?.entireAverage ?? 0) return { - mine: (statisics?.average ?? 0) / total, - entire: (statisics?.entireAverage ?? 0) / total, + mine: (dashboard?.average ?? 0) / total, + entire: (dashboard?.entireAverage ?? 0) / total, } - }, [statisics]) + }, [dashboard]) return ( -
    - {isLoading || !statisics ? ( +
    + {isLoading || !dashboard ? ( <>
    @@ -55,16 +55,8 @@ const Money = ({ ) : ( <> -

    - - {statisics.peopleCount}명 - - 에게 -
    - - {statisics.average.toLocaleString()}원 - {' '} - 빌릴 수 있어요 +

    + {data?.user?.name}님에게 빌릴 수 있는 금액은

    {/*
    -
    - - -
    + {/*
    +
    */} +
    + +
    )}
    @@ -118,24 +110,35 @@ interface BarProps { function Bar({ active, value, price, isMe = true }: BarProps) { const { data } = useSession() const [isDone, setIsDone] = useState(false) + const id = useId() return ( -
    +
    {price.toLocaleString()}원
    { setIsDone(true) @@ -154,7 +158,7 @@ function Bar({ active, value, price, isMe = true }: BarProps) { active ? isDone ? { - height: [`${value}%`, `${value * 0.8}%`], + height: [`${value || 5}%`, `${value * 0.8}%`], transition: { repeat: Infinity, repeatType: 'mirror', @@ -172,20 +176,27 @@ function Bar({ active, value, price, isMe = true }: BarProps) { } className={cn( 'relative w-full origin-bottom rounded-md', - isMe ? 'bg-brand-sub1-yellow900' : 'bg-gray-gray100', + !isMe && 'bg-bg-regular', )} + style={{ + ...(isMe + ? { + background: `linear-gradient(to top, ${MAIN_COLOR.MONEY.from} 0%, ${MAIN_COLOR.MONEY.to} 100%)`, + } + : {}), + }} />

    - {isMe ? (data?.user?.name ?? '') + ' 님' : '이용자 평균'} + {isMe ? (data?.user?.name ?? '') + '님 평균' : '이용자 평균'}

    -
    + ) } diff --git a/components/compositions/dashboard/rank-chart/index.tsx b/components/compositions/dashboard/rank-chart/index.tsx new file mode 100644 index 0000000..206d75e --- /dev/null +++ b/components/compositions/dashboard/rank-chart/index.tsx @@ -0,0 +1,195 @@ +import { Button } from '@/components/ui' +import useDetailDrawer from '@/hooks/use-detail-drawer' +import { useInViewRef } from '@/hooks/use-in-view-ref' +import { cn } from '@/lib/client/utils' +import { RankChart as RankChartType } from '@/model/dashboard.entity' +import { useSession } from '@/provider/session-provider' +import { PropswithWikiType } from '@/types' +import { m, domAnimation, LazyMotion } from 'framer-motion' +import { useMemo } from 'react' + +interface RankChartProps { + isLoading?: boolean + dashboard: RankChartType +} + +export const RankChart = ({ + dashboard, + + isLoading, +}: PropswithWikiType) => { + const { data } = useSession() + const { handle } = useDetailDrawer() + + const { inView, ref } = useInViewRef({ + once: true, + amount: 'all', + }) + + const parsedDashboard = useMemo(() => { + const sorted = dashboard.rank.sort((a, b) => a.percentage - b.percentage) + return sorted + }, [dashboard.rank]) + + const medals = useMemo(() => { + return [ + + + + + + + , + + + + + + + , + + + + + + + , + ] + }, []) + + return ( + +
    + {isLoading || !dashboard ? ( + <> +
    +
    +
    +
    +
    +
    +
    + + ) : ( + <> +

    + +
    +
    + {parsedDashboard.slice(0, 3).map((data, index) => ( +
    +
    + {medals[index]} +
    +
    +

    + {data.text.replace(/\([^)]*\)/, '')} +

    +

    + {data.percentage}% +

    +
    + + + {[2, 1, 3][index]} + + +
    + ))} +
    +
    +
    + {parsedDashboard.slice(3, 5).map((item, index) => ( +
    + + {index + 4} + +
    + {item.text} + {item.percentage}% +
    +
    + ))} +
    + + )} +
    + +
    +
    + + ) +} diff --git a/components/compositions/dashboard/sad/index.tsx b/components/compositions/dashboard/sad/index.tsx index 9443da2..ad57302 100644 --- a/components/compositions/dashboard/sad/index.tsx +++ b/components/compositions/dashboard/sad/index.tsx @@ -1,158 +1,158 @@ -import { Button } from '@/components/ui' -import { RANK_COLOR } from '@/constants' -import useDetailDrawer from '@/hooks/use-detail-drawer' -import { FilterType } from '@/hooks/use-filter' -import { useInViewRef } from '@/hooks/use-in-view-ref' -import { cn } from '@/lib/client/utils' -import { HAPPY_OR_SAD } from '@/model/dashboard.entity' -import { getDashboardQuery } from '@/queries/dashboard' -import { PropswithWikiType } from '@/types' -import { useQuery } from '@tanstack/react-query' -import { HTMLMotionProps, m, LazyMotion, domAnimation } from 'framer-motion' -import React, { useMemo } from 'react' +// import { Button } from '@/components/ui' +// import { RANK_COLOR } from '@/constants' +// import useDetailDrawer from '@/hooks/use-detail-drawer' +// import { FilterType } from '@/hooks/use-filter' +// import { useInViewRef } from '@/hooks/use-in-view-ref' +// import { cn } from '@/lib/client/utils' +// import { HAPPY_OR_SAD } from '@/model/dashboard.entity' +// import { getDashboardQuery } from '@/queries/dashboard' +// import { PropswithWikiType } from '@/types' +// import { useQuery } from '@tanstack/react-query' +// import { HTMLMotionProps, m, LazyMotion, domAnimation } from 'framer-motion' +// import React, { useMemo } from 'react' -const Sad = ({ - wikiType, - filter, -}: PropswithWikiType<{ - filter: FilterType -}>) => { - const { handle } = useDetailDrawer() - const { data: statisics, isLoading } = useQuery({ - ...getDashboardQuery(wikiType, filter), - select(data) { - return data.data?.statistics.find( - (item) => item.dashboardType === 'SAD', - ) as HAPPY_OR_SAD - }, - }) - const { inView, ref } = useInViewRef({ - once: true, - amount: 'all', - }) - const orderByMaxValueList = useMemo(() => { - const arr = statisics?.rank?.sort((a, b) => b.percentage - a.percentage) +// const Sad = ({ +// wikiType, +// filter, +// }: PropswithWikiType<{ +// filter: FilterType +// }>) => { +// const { handle } = useDetailDrawer() +// const { data: statisics, isLoading } = useQuery({ +// ...getDashboardQuery(wikiType, filter), +// select(data) { +// return data.data?.statistics.find( +// (item) => item.dashboardType === 'SAD', +// ) as HAPPY_OR_SAD +// }, +// }) +// const { inView, ref } = useInViewRef({ +// once: true, +// amount: 'all', +// }) +// const orderByMaxValueList = useMemo(() => { +// const arr = statisics?.rank?.sort((a, b) => b.percentage - a.percentage) - return arr?.map((item, index) => ({ - ...item, - color: - RANK_COLOR[index] ?? - `rgb(${Math.floor(Math.random() * 255)},${Math.floor(Math.random() * 255)},${Math.floor(Math.random() * 255)})`, - text: item.legend.split(' ')[1], - })) - }, [statisics]) - return ( - -
    - {isLoading ? ( - <> -
    -
    -
    -
    -
    -
    - - ) : ( - <> -

    - {orderByMaxValueList?.[0].text === '직접 입력' ? ( - 친구가 써준 답변을 확인해보세요 - ) : ( -

    - 슬프거나 화날 때
    - - {' '} - {orderByMaxValueList?.[0].text} - -

    - )} -

    -
    - {orderByMaxValueList?.slice(0, 3).map((item, index) => { - return ( - - ) - })} -
    -
    - -
    - - )} -
    - - ) -} +// return arr?.map((item, index) => ({ +// ...item, +// color: +// RANK_COLOR[index] ?? +// `rgb(${Math.floor(Math.random() * 255)},${Math.floor(Math.random() * 255)},${Math.floor(Math.random() * 255)})`, +// text: item.legend.split(' ')[1], +// })) +// }, [statisics]) +// return ( +// +//
    +// {isLoading ? ( +// <> +//
    +//
    +//
    +//
    +//
    +//
    +// +// ) : ( +// <> +//

    +// {orderByMaxValueList?.[0].text === '직접 입력' ? ( +// 친구가 써준 답변을 확인해보세요 +// ) : ( +//

    +// 슬프거나 화날 때
    +// +// {' '} +// {orderByMaxValueList?.[0].text} +// +//

    +// )} +// +//
    +// {orderByMaxValueList?.slice(0, 3).map((item, index) => { +// return ( +// +// ) +// })} +//
    +//
    +// +//
    +// +// )} +//
    +// +// ) +// } -export default Sad +// export default Sad -interface BarProps extends HTMLMotionProps<'div'> { - title: string - percent: number - color: string - active?: boolean - accent?: boolean -} +// interface BarProps extends HTMLMotionProps<'div'> { +// title: string +// percent: number +// color: string +// active?: boolean +// accent?: boolean +// } -function Bar({ - color, - title, - percent, - active = false, - accent = false, - ...rest -}: BarProps) { - const font = accent ? 'text-body1-bold' : 'title-body-medium' - const 최소바크기보정값 = (80 * percent) / 100 + 10 - return ( -
    -

    {title}

    -
    - -

    - {percent}% -

    -
    -
    - ) -} +// function Bar({ +// color, +// title, +// percent, +// active = false, +// accent = false, +// ...rest +// }: BarProps) { +// const font = accent ? 'text-body1-bold' : 'title-body-medium' +// const 최소바크기보정값 = (80 * percent) / 100 + 10 +// return ( +//
    +//

    {title}

    +//
    +// +//

    +// {percent}% +//

    +//
    +//
    +// ) +// } diff --git a/components/compositions/dashboard/tree-info.tsx b/components/compositions/dashboard/tree-info.tsx index 9dc1c6b..eff536c 100644 --- a/components/compositions/dashboard/tree-info.tsx +++ b/components/compositions/dashboard/tree-info.tsx @@ -1,22 +1,25 @@ -import { Button } from '@/components/ui' -import { FilterType } from '@/hooks/use-filter' +import { useRouter } from 'next/router' import { useQuery } from '@tanstack/react-query' import { motion } from 'framer-motion' -import { GetSurveyResponse } from '@/model/survey.entity' -import { NamuiApi } from '@/lib/namui-api' import { AnimatePresence } from 'framer-motion' -import TreeCard from '../tree-card' -import { fadeInProps } from '@/variants' + +import { NamuiApi } from '@/lib/namui-api' import { cn } from '@/lib/client/utils' +import { FilterType } from '@/hooks/use-filter' + +import { fadeInProps } from '@/variants' import { PropswithWikiType } from '@/types' -import { useRouter } from 'next/router' +import { GetSurveyResponse } from '@/model/survey.entity' + +import { Button } from '@/components/ui' +import TreeCard from '../tree-card' const TreeInfo = ({ wikiType, wikiCount, }: PropswithWikiType<{ filter: FilterType; wikiCount: number }>) => { const { data: surveys, isLoading } = useQuery({ - queryKey: ['survey'], + queryKey: ['survey', wikiType], queryFn: ({ pageParam = 0 }) => { return NamuiApi.getSurveys(pageParam as number, wikiType) }, @@ -31,7 +34,7 @@ const TreeInfo = ({ {wikiCount}그루
    -
    +
    {!isLoading && surveys ? ( { setBottomSheetOpen(true) diff --git a/components/dashboard-container/detail-drawer.tsx b/components/dashboard-container/detail-drawer.tsx index 65a5e28..f37fa71 100644 --- a/components/dashboard-container/detail-drawer.tsx +++ b/components/dashboard-container/detail-drawer.tsx @@ -1,16 +1,17 @@ import React, { useContext, useEffect, useMemo, useRef } from 'react' - -import useFilter, { Filter } from '@/hooks/use-filter' import { InfiniteData, useInfiniteQuery } from '@tanstack/react-query' +import { useRouter } from 'next/router' +import { cn } from '@/lib/client/utils' +import { useSession } from '@/provider/session-provider' + import { NamuiApi } from '@/lib/namui-api' +import useFilter, { Filter } from '@/hooks/use-filter' import { useIntersectionObserver } from '@/hooks/use-observer' -import { useSession } from '@/provider/session-provider' + import { motion } from 'framer-motion' import { fadeInProps } from '@/variants' +import { Period, Relation, CardType, treeCardAsset } from '@/model/card.entity' -import { Period, Relation, TreeType, treeCardAsset } from '@/model/tree.entity' -import { useRouter } from 'next/router' -import { cn } from '@/lib/client/utils' import { QS_NAMES, ShareImageContext } from '../share-image' import { parseShareCardItems } from '../share-image/constants' import { useMount } from '@/hooks/use-mount' @@ -165,7 +166,7 @@ function Content({ id, type }: { id: string; type: DetailType }) { fetchNextPage, }) - const treeType = useRef(new TreeType(treeCardAsset)).current + const treeType = useRef(new CardType(treeCardAsset)).current return (
    @@ -350,7 +351,7 @@ function MultipleChoice({ }: { cardItem: Content summary: string - treeType: TreeType + treeType: CardType onShareClick?: () => void }) { return ( @@ -430,7 +431,7 @@ function TwoChoice({ }: { cardItem: Content summary: string - treeType: TreeType + treeType: CardType onShareClick?: () => void }) { const isPositiveAnswer = cardItem.answer.includes('🙆‍♂️') diff --git a/components/dashboard-container/index.tsx b/components/dashboard-container/index.tsx index 5ca6549..28b2417 100644 --- a/components/dashboard-container/index.tsx +++ b/components/dashboard-container/index.tsx @@ -1,20 +1,24 @@ -import useFilter, { Filter } from '@/hooks/use-filter' -import { getDashboardQuery } from '@/queries/dashboard' +import React, { HTMLAttributes, PropsWithChildren, useMemo } from 'react' import { useQuery } from '@tanstack/react-query' -import React, { HTMLAttributes, PropsWithChildren } from 'react' import { AnimatePresence, motion } from 'framer-motion' -import { fadeInProps } from '@/variants' import { cn } from '@/lib/client/utils' -import TripleTrees from '../svgs/triple-trees' -import ShareModal from '../share-modal' + +import useFilter, { Filter } from '@/hooks/use-filter' +import { getDashboardQuery } from '@/queries/dashboard' +import { PropswithWikiType } from '@/types' +import { fadeInProps } from '@/variants' + +import { BubbleChart } from '../compositions/dashboard/bubble-chart' +import { BarChart } from '../compositions/dashboard/bar-chart' import { Button } from '@/components/ui' -import BestWorth from '@/components/compositions/dashboard/best-worth' -import Character from '@/components/compositions/dashboard/character' -import Money from '@/components/compositions/dashboard/money' -import Happy from '@/components/compositions/dashboard/happy' -import Sad from '@/components/compositions/dashboard/sad' import TreeInfo from '@/components/compositions/dashboard/tree-info' -import { PropswithWikiType } from '@/types' +import TripleTrees from '../svgs/triple-trees' +import ShareModal from '../share-modal' +import { Statistic } from '@/model/dashboard.entity' +import { BinaryChart } from '../compositions/dashboard/binary-chart' +import Money from '../compositions/dashboard/money' + +import { RankChart } from '../compositions/dashboard/rank-chart' import { KnowAbout } from '../compositions/dashboard/know-about' const DashboardContainer = ({ @@ -30,6 +34,8 @@ const DashboardContainer = ({ getDashboardQuery(wikiType, selectedFilter), ) + const dashboardList = useMemo(() => statisics, [statisics]) + return ( {/* 내 정원에 심어진 나무는? */}
    @@ -54,24 +60,11 @@ const DashboardContainer = ({
    - {/* 가장 중요한 것 - 파이차트 */} -
    - -
    - {/* 이런사람이에요 - 박스 */} -
    - -
    -
    - -
    - {/* 기쁠 떄 */} -
    - -
    -
    - -
    + {dashboardList?.map((stat) => ( +
    + +
    + ))} ) : ( ) } + +interface RecursiveDashboardProps { + dashboard: Statistic +} + +const RecursiveDashboard = ({ + wikiType, + dashboard, +}: PropswithWikiType) => { + const dashboardChild = useMemo(() => { + switch (dashboard.dashboardType) { + case 'BAR_CHART': + return + case 'BINARY': + return + case 'BUBBLE_CHART': + return + case 'MONEY': + return + case 'RANK': + return + } + }, [dashboard, wikiType]) + return dashboardChild +} diff --git a/components/error-boundary.tsx b/components/error-boundary.tsx index e5e448d..d431042 100644 --- a/components/error-boundary.tsx +++ b/components/error-boundary.tsx @@ -1,9 +1,9 @@ import React, { ErrorInfo, PropsWithChildren } from 'react' -import { Button } from '@/components/ui' -import ErrorTree from './svgs/error-tree' + import { motion } from 'framer-motion' import { fadeInProps } from '@/variants' - +import { Button } from '@/components/ui' +import ErrorTree from './svgs/error-tree' class ErrorBoundary extends React.Component< PropsWithChildren, { hasError: boolean } @@ -18,7 +18,7 @@ class ErrorBoundary extends React.Component< } handleBack() { - window.location.pathname = '/garden' + window.location.pathname = '/main' } componentDidCatch(error: Error, _: ErrorInfo) { @@ -42,7 +42,7 @@ class ErrorBoundary extends React.Component<
    ) diff --git a/components/filter-button/index.tsx b/components/filter-button/index.tsx index 7be1b2c..f8b22ec 100644 --- a/components/filter-button/index.tsx +++ b/components/filter-button/index.tsx @@ -1,7 +1,7 @@ import React, { useEffect } from 'react' import { motion, useAnimate } from 'framer-motion' -import { fadeInProps } from '@/variants' import { cn } from '@/lib/client/utils' +import { fadeInProps } from '@/variants' interface FilterButtonProps { selected?: boolean diff --git a/components/filter-text/index.tsx b/components/filter-text/index.tsx index 67e38f6..d5561ee 100644 --- a/components/filter-text/index.tsx +++ b/components/filter-text/index.tsx @@ -1,5 +1,5 @@ -import { cn } from '@/lib/client/utils' import { HTMLAttributes } from 'react' +import { cn } from '@/lib/client/utils' interface FilterTextProps extends HTMLAttributes { active?: boolean diff --git a/components/header/edit-setting/index.tsx b/components/header/edit-setting/index.tsx index 883d57a..6c7d544 100644 --- a/components/header/edit-setting/index.tsx +++ b/components/header/edit-setting/index.tsx @@ -1,17 +1,16 @@ -import { Button } from '@/components/ui' - -import { Inputbox } from '@/components/ui' -import SideDrawer from '@/components/side-drawer' - +import React, { useId, useState } from 'react' +import { useForm } from 'react-hook-form' +import Image from 'next/image' +import * as z from 'zod' +import { zodResolver } from '@hookform/resolvers/zod' import { toastError } from '@/lib/client/alert' import { cn } from '@/lib/client/utils' import { NamuiApi } from '@/lib/namui-api' import { useSession } from '@/provider/session-provider' -import { zodResolver } from '@hookform/resolvers/zod' -import React, { useId, useState } from 'react' -import { useForm } from 'react-hook-form' -import * as z from 'zod' -import Image from 'next/image' + +import SideDrawer from '@/components/side-drawer' +import { Button } from '@/components/ui' +import { Inputbox } from '@/components/ui' import caution from '@/assets/icons/caution.svg' const scheme = z.object({ diff --git a/components/header/setting/index.tsx b/components/header/setting/index.tsx index 87e5ef6..c6f2dc6 100644 --- a/components/header/setting/index.tsx +++ b/components/header/setting/index.tsx @@ -1,12 +1,12 @@ import React, { useState } from 'react' -import Modal from '@/components/modal' - import { Close } from '@radix-ui/react-dialog' import { useSession } from '@/provider/session-provider' import { NamuiApi } from '@/lib/namui-api' import { toastError } from '@/lib/client/alert' -import { DeveloperInfo } from '@/components/header/developer-info' + +import Modal from '@/components/modal' import SideDrawer from '@/components/side-drawer' +import { DeveloperInfo } from '@/components/header/developer-info' import { EditProfile } from '@/components/header/edit-setting' export const Setting = () => { diff --git a/components/header/write-list/wirte-list-card.tsx b/components/header/write-list/wirte-list-card.tsx index cb37457..fad0a67 100644 --- a/components/header/write-list/wirte-list-card.tsx +++ b/components/header/write-list/wirte-list-card.tsx @@ -3,7 +3,7 @@ import { useAnimation } from 'framer-motion' import React, { useEffect, useMemo, useRef } from 'react' import { motion } from 'framer-motion' import { Writing } from '@/queries/surveys' -import { TreeType, treeCardAsset } from '@/model/tree.entity' +import { CardType, treeCardAsset } from '@/model/card.entity' import { PeriodBadge, RelationBadge } from '@/components/badge' const variants = { hidden: { @@ -45,7 +45,7 @@ const WriteListCard = ({ item }: { item: Writing }) => { const parsedCreatedAt = new Date(item.sentAt) return `${parsedCreatedAt.getFullYear()}.${parsedCreatedAt.getMonth() + 1}.${parsedCreatedAt.getDate()}` }, []) - const treeType = useRef(new TreeType(treeCardAsset)).current + const treeType = useRef(new CardType(treeCardAsset)).current useEffect(() => { if (inView) { controls.start('show') diff --git a/components/inputLabel/index.tsx b/components/inputLabel/index.tsx index fa55b1e..97dfb31 100644 --- a/components/inputLabel/index.tsx +++ b/components/inputLabel/index.tsx @@ -16,13 +16,13 @@ const InputLabel = forwardRef<

    {label}

    {required && ( - 필수 + 필수 )}
    {children} {errorMessage && ( -

    {errorMessage}

    +

    {errorMessage}

    )}
    diff --git a/components/modal/index.tsx b/components/modal/index.tsx index 8774332..dd8a1d6 100644 --- a/components/modal/index.tsx +++ b/components/modal/index.tsx @@ -73,17 +73,15 @@ export const Modal = forwardRef>( } > - {description && ( - - {title} - - {description} - - - )} + + {title} + + {description} + + {children} diff --git a/components/radio-button/index.tsx b/components/radio-button/index.tsx index ee39263..b804892 100644 --- a/components/radio-button/index.tsx +++ b/components/radio-button/index.tsx @@ -36,10 +36,10 @@ const RadioButton = forwardRef( duration: 0.3, }} className={cn( - 'flex w-full items-center justify-start rounded-sm border border-[#E5E5EC] p-4 transition-all duration-200', - 'focus-within:border-brand-main-green400', + 'flex w-full items-center justify-start rounded-md border border-[#E5E5EC] p-4 transition-all duration-200 ', + 'focus-within:border-brand-main', 'disabled:cursor-not-allowed disabled:opacity-50', - selected && 'border-brand-main-green400 border bg-main-green-green50', + selected && 'border border-brand-main bg-main-green-green50', )} > { const { children, maxWidth = 0, minWidth = 0 } = props const ref = useRef(null) - const [textWidth, setTextWidth] = useState(clamp(0, minWidth, maxWidth)) + const [textWidth, setTextWidth] = useState(() => clamp(0, minWidth, maxWidth)) useBrowserLayoutEffect(() => { if (!ref.current) return diff --git a/components/share-image/index.tsx b/components/share-image/index.tsx index 33b5026..2235a9c 100644 --- a/components/share-image/index.tsx +++ b/components/share-image/index.tsx @@ -6,7 +6,7 @@ import React, { useRef, useState, } from 'react' -import { Period, Relation, treeCardAsset, TreeType } from '@/model/tree.entity' +import { Period, Relation, treeCardAsset, CardType } from '@/model/card.entity' import { useSession } from '@/provider/session-provider' import { parseShareCardItems } from './constants' @@ -99,7 +99,7 @@ export const ShareImage = ({ } })() - const treeType = useRef(new TreeType(treeCardAsset)).current + const treeType = useRef(new CardType(treeCardAsset)).current const handleShare = (type: ShareType) => () => { if (ref.current === null) { diff --git a/components/share-modal/index.tsx b/components/share-modal/index.tsx index c34cbb7..a8a5ced 100644 --- a/components/share-modal/index.tsx +++ b/components/share-modal/index.tsx @@ -7,22 +7,31 @@ import { Button } from '@/components/ui' import { useRouter } from 'next/router' import { PropswithWikiType } from '@/types' -interface ShareModalProps {} +interface ShareModalProps { + open?: boolean + onOpenChange?: (state: boolean) => void +} const ShareModal = ({ wikiType, children, + open, + onOpenChange, }: PropswithWikiType>) => { const { data } = useSession() - const [shareModalOpen, setShareModalOpen] = useState(false) + const [shareModalOpen, setShareModalOpen] = useState(open) const [copyModalOpen, setCopyModalOpen] = useState(false) const router = useRouter() + const onStateChange = (state: boolean) => { + setShareModalOpen(state) + onOpenChange?.(state) + } + const handleCopyLink = useCallback(async () => { if (data?.user?.wikiId) { const url = new URL(window.location.origin) url.pathname = '/surveys' - console.log(wikiType, '<< { - setShareModalOpen(state) - }} + open={open ?? shareModalOpen} + onOpenChange={onStateChange} key="selectShareModal" trigger={children} title={ @@ -110,9 +117,8 @@ const ShareModal = ({ onOpenChange={setCopyModalOpen} key="copyLinkModal" title="링크가 복사되었어요" - className="text-black " + className="text-center text-b2-kr-b text-black" footer={{ - // TODO: variant 적용 :confirm item: [ -
    - -
    - ) -} +// return ( +//
    +// <> +//

    +// 가장 중요한 것은{' '} +// +// {orderByMaxValueList?.[0].legend} +// +// 이네요 +//

    +//
    +//
    +// {inView && ( +// +// +// +// {orderByMaxValueList?.map((entry, index) => ( +// +// ))} +// +// +// +// )} +//
    +//
    +// {orderByMaxValueList?.slice(0, 3).map((item) => { +// return ( +//
    +//
    +//

    +// {item.legend} +//

    +// +// {item.percentage}% +// +//
    +// ) +// })} +//
    +//
    +//
    +// +//
    +// +//
    +// ) +// } -export default Step3BestWorth +// export default Step3BestWorth diff --git a/components/situations/onboard/onboard-step3/step3-happy.tsx b/components/situations/onboard/onboard-step3/step3-happy.tsx index 59ae3c3..23cee7d 100644 --- a/components/situations/onboard/onboard-step3/step3-happy.tsx +++ b/components/situations/onboard/onboard-step3/step3-happy.tsx @@ -1,149 +1,149 @@ -import { Button } from '@/components/ui' -import { RANK_COLOR } from '@/constants' -import { FilterType } from '@/hooks/use-filter' -import { useInViewRef } from '@/hooks/use-in-view-ref' -import { cn } from '@/lib/client/utils' -import { HTMLMotionProps, m, LazyMotion, domAnimation } from 'framer-motion' -import React, { useMemo } from 'react' +// import { Button } from '@/components/ui' +// import { RANK_COLOR } from '@/constants' +// import { FilterType } from '@/hooks/use-filter' +// import { useInViewRef } from '@/hooks/use-in-view-ref' +// import { cn } from '@/lib/client/utils' +// import { HTMLMotionProps, m, LazyMotion, domAnimation } from 'framer-motion' +// import React, { useMemo } from 'react' -const statisics = { - dashboardType: 'HAPPY', - questionId: '65d8f7b8c934b525dd04755e', - rank: [ - { - legend: '🏄🏼 취미생활을 즐겨요', - percentage: 11, - }, - { - legend: '👏 혼자 조용히 즐겨요', - percentage: 11, - }, - { - legend: '🎉 사람들에게 알리고 축하받아요', - percentage: 44, - }, - { - legend: '🍱 맛있는 음식을 먹어요', - percentage: 33, - }, - { - legend: '✍️ 직접 입력', - percentage: 0, - }, - ], -} +// const statisics = { +// dashboardType: 'HAPPY', +// questionId: '65d8f7b8c934b525dd04755e', +// rank: [ +// { +// legend: '🏄🏼 취미생활을 즐겨요', +// percentage: 11, +// }, +// { +// legend: '👏 혼자 조용히 즐겨요', +// percentage: 11, +// }, +// { +// legend: '🎉 사람들에게 알리고 축하받아요', +// percentage: 44, +// }, +// { +// legend: '🍱 맛있는 음식을 먹어요', +// percentage: 33, +// }, +// { +// legend: '✍️ 직접 입력', +// percentage: 0, +// }, +// ], +// } -const Step3Happy = ({}: { filter: FilterType }) => { - const { inView, ref } = useInViewRef({ - once: true, - amount: 'all', - }) +// const Step3Happy = ({}: { filter: FilterType }) => { +// const { inView, ref } = useInViewRef({ +// once: true, +// amount: 'all', +// }) - const orderByMaxValueList = useMemo(() => { - const arr = statisics?.rank?.sort((a, b) => b.percentage - a.percentage) +// const orderByMaxValueList = useMemo(() => { +// const arr = statisics?.rank?.sort((a, b) => b.percentage - a.percentage) - return arr?.map((item, index) => ({ - ...item, - color: - RANK_COLOR[index] ?? - `rgb(${Math.floor(Math.random() * 255)},${Math.floor(Math.random() * 255)},${Math.floor(Math.random() * 255)})`, - text: item.legend.split(' ')[1], - })) - }, [statisics]) +// return arr?.map((item, index) => ({ +// ...item, +// color: +// RANK_COLOR[index] ?? +// `rgb(${Math.floor(Math.random() * 255)},${Math.floor(Math.random() * 255)},${Math.floor(Math.random() * 255)})`, +// text: item.legend.split(' ')[1], +// })) +// }, [statisics]) - return ( - -
    - <> -

    - 기쁠 때 -
    - - {orderByMaxValueList?.[0].text} - -

    -
    - {orderByMaxValueList?.slice(0, 3).map((item, index) => { - return ( - - ) - })} -
    -
    - -
    - -
    -
    - ) -} +// return ( +// +//
    +// <> +//

    +// 기쁠 때 +//
    +// +// {orderByMaxValueList?.[0].text} +// +//

    +//
    +// {orderByMaxValueList?.slice(0, 3).map((item, index) => { +// return ( +// +// ) +// })} +//
    +//
    +// +//
    +// +//
    +//
    +// ) +// } -export default Step3Happy +// export default Step3Happy -interface BarProps extends HTMLMotionProps<'div'> { - title: string - percent: number - color: string - active?: boolean - accent?: boolean -} +// interface BarProps extends HTMLMotionProps<'div'> { +// title: string +// percent: number +// color: string +// active?: boolean +// accent?: boolean +// } -function Bar({ - color, - title, - percent, - active = false, - accent = false, - ...rest -}: BarProps) { - const font = accent ? 'text-[1vb] font-bold' : 'text-[1vb] font-medium' - const 최소바크기보정값 = (80 * percent) / 100 + 10 - return ( -
    -

    {title}

    -
    - -

    - {percent}% -

    -
    -
    - ) -} +// function Bar({ +// color, +// title, +// percent, +// active = false, +// accent = false, +// ...rest +// }: BarProps) { +// const font = accent ? 'text-[1vb] font-bold' : 'text-[1vb] font-medium' +// const 최소바크기보정값 = (80 * percent) / 100 + 10 +// return ( +//
    +//

    {title}

    +//
    +// +//

    +// {percent}% +//

    +//
    +//
    +// ) +// } diff --git a/components/situations/onboard/onboard-step3/step3-sad.tsx b/components/situations/onboard/onboard-step3/step3-sad.tsx index ece83a0..88fa856 100644 --- a/components/situations/onboard/onboard-step3/step3-sad.tsx +++ b/components/situations/onboard/onboard-step3/step3-sad.tsx @@ -1,149 +1,149 @@ -import { Button } from '@/components/ui' -import { RANK_COLOR } from '@/constants' -import { FilterType } from '@/hooks/use-filter' -import { useInViewRef } from '@/hooks/use-in-view-ref' -import { cn } from '@/lib/client/utils' -import { HTMLMotionProps, m, LazyMotion, domAnimation } from 'framer-motion' -import React, { useMemo } from 'react' +// import { Button } from '@/components/ui' +// import { RANK_COLOR } from '@/constants' +// import { FilterType } from '@/hooks/use-filter' +// import { useInViewRef } from '@/hooks/use-in-view-ref' +// import { cn } from '@/lib/client/utils' +// import { HTMLMotionProps, m, LazyMotion, domAnimation } from 'framer-motion' +// import React, { useMemo } from 'react' -const statisics = { - dashboardType: 'SAD', - questionId: '65d8f7b8c934b525dd04755f', - rank: [ - { - legend: '🙌 사람들의 위로와 공감을 원해요', - percentage: 0, - }, - { - legend: '🚴🏼 스트레스를 풀기 위해 여가생활을 즐겨요', - percentage: 30, - }, - { - legend: '✍️ 직접 입력', - percentage: 0, - }, - { - legend: '😭 혼자 끙끙 앓아요', - percentage: 50, - }, - { - legend: '🙏 사람들에게 조언을 구해요', - percentage: 20, - }, - ], -} +// const statisics = { +// dashboardType: 'SAD', +// questionId: '65d8f7b8c934b525dd04755f', +// rank: [ +// { +// legend: '🙌 사람들의 위로와 공감을 원해요', +// percentage: 0, +// }, +// { +// legend: '🚴🏼 스트레스를 풀기 위해 여가생활을 즐겨요', +// percentage: 30, +// }, +// { +// legend: '✍️ 직접 입력', +// percentage: 0, +// }, +// { +// legend: '😭 혼자 끙끙 앓아요', +// percentage: 50, +// }, +// { +// legend: '🙏 사람들에게 조언을 구해요', +// percentage: 20, +// }, +// ], +// } -const Step3Sad = ({}: { filter: FilterType }) => { - const { inView, ref } = useInViewRef({ - once: true, - amount: 'all', - }) +// const Step3Sad = ({}: { filter: FilterType }) => { +// const { inView, ref } = useInViewRef({ +// once: true, +// amount: 'all', +// }) - const orderByMaxValueList = useMemo(() => { - const arr = statisics?.rank?.sort((a, b) => b.percentage - a.percentage) +// const orderByMaxValueList = useMemo(() => { +// const arr = statisics?.rank?.sort((a, b) => b.percentage - a.percentage) - return arr?.map((item, index) => ({ - ...item, - color: - RANK_COLOR[index] ?? - `rgb(${Math.floor(Math.random() * 255)},${Math.floor(Math.random() * 255)},${Math.floor(Math.random() * 255)})`, - text: item.legend.split(' ')[1], - })) - }, [statisics]) +// return arr?.map((item, index) => ({ +// ...item, +// color: +// RANK_COLOR[index] ?? +// `rgb(${Math.floor(Math.random() * 255)},${Math.floor(Math.random() * 255)},${Math.floor(Math.random() * 255)})`, +// text: item.legend.split(' ')[1], +// })) +// }, [statisics]) - return ( - -
    - <> -

    - 슬프거나 화날 때 -
    - - {orderByMaxValueList?.[0].text} - -

    -
    - {orderByMaxValueList?.slice(0, 3).map((item, index) => { - return ( - - ) - })} -
    -
    - -
    - -
    -
    - ) -} +// return ( +// +//
    +// <> +//

    +// 슬프거나 화날 때 +//
    +// +// {orderByMaxValueList?.[0].text} +// +//

    +//
    +// {orderByMaxValueList?.slice(0, 3).map((item, index) => { +// return ( +// +// ) +// })} +//
    +//
    +// +//
    +// +//
    +//
    +// ) +// } -export default Step3Sad +// export default Step3Sad -interface BarProps extends HTMLMotionProps<'div'> { - title: string - percent: number - color: string - active?: boolean - accent?: boolean -} +// interface BarProps extends HTMLMotionProps<'div'> { +// title: string +// percent: number +// color: string +// active?: boolean +// accent?: boolean +// } -function Bar({ - color, - title, - percent, - active = false, - accent = false, - ...rest -}: BarProps) { - const font = accent ? 'text-[1vb] font-bold' : 'text-[1vb] font-medium' - const 최소바크기보정값 = (80 * percent) / 100 + 10 - return ( -
    -

    {title}

    -
    - -

    - {percent}% -

    -
    -
    - ) -} +// function Bar({ +// color, +// title, +// percent, +// active = false, +// accent = false, +// ...rest +// }: BarProps) { +// const font = accent ? 'text-[1vb] font-bold' : 'text-[1vb] font-medium' +// const 최소바크기보정값 = (80 * percent) / 100 + 10 +// return ( +//
    +//

    {title}

    +//
    +// +//

    +// {percent}% +//

    +//
    +//
    +// ) +// } diff --git a/components/situations/onboard/onboard-step5/index.tsx b/components/situations/onboard/onboard-step5/index.tsx new file mode 100644 index 0000000..d059cd2 --- /dev/null +++ b/components/situations/onboard/onboard-step5/index.tsx @@ -0,0 +1,97 @@ +import React from 'react' + +const OnboardStep5 = () => { + return ( +
    +

    + 친구가 작성해준 답변을 +
    + SNS에 공유해보세요 +

    + + + + + + + + + + + + + + + + + + + + + + +
    + ) +} + +export default OnboardStep5 diff --git a/components/situations/onboard/onobard-step4/index.tsx b/components/situations/onboard/onobard-step4/index.tsx new file mode 100644 index 0000000..b2b7664 --- /dev/null +++ b/components/situations/onboard/onobard-step4/index.tsx @@ -0,0 +1,97 @@ +import React from 'react' + +const OnboardStep4 = () => { + return ( +
    +

    + 답변 상세 보기에서 +
    + 내가 원하는 답변을 공유할 수 있어요 +

    + + + + + + + + + + + + + + + + + + + + + + +
    + ) +} + +export default OnboardStep4 diff --git a/components/survey/survey-form.tsx b/components/survey/survey-form.tsx index 6567158..b699902 100644 --- a/components/survey/survey-form.tsx +++ b/components/survey/survey-form.tsx @@ -18,12 +18,16 @@ import { fadeInProps } from '@/variants' import { cn, useBrowserLayoutEffect } from '@/lib/client/utils' import InputLabel from '../inputLabel' import * as z from 'zod' +import Image from 'next/image' import { zodResolver } from '@hookform/resolvers/zod' import { Button, Inputbox } from '@/components/ui' -import { TreeSvg } from '../questionTrees' import { useRaisedShadow } from '@/hooks/use-raised-shadow' import { ANSWER_TYPE } from '@/constants/enum' import UpDownSheet from '../ui/updownSheet' +import questionTree from '@/assets/characters/question-tree.svg' +import questionFlower from '@/assets/characters/question-flower.svg' +import { useSearchParams } from 'next/navigation' +import { WikiType } from '@/types' const surveyScheme = z.object({ answer: z.string().min(1).or(z.number()).or(z.array(z.string())), @@ -152,7 +156,7 @@ const ReorderOptions = ({ options, id }: ReorderOptionsProps) => { setOptionsState(state) }} values={optionsState} - className="flex-1 space-y-2 overflow-y-auto" + className="w-full flex-1 space-y-2 overflow-y-auto " > {optionsState.map((option, index) => ( { + switch (wikiType) { + case 'NAMUI': + return questionTree + case 'ROMANCE': + return questionFlower + default: + return questionTree // 기본값 설정 + } + })() + return (
    {type === 'OX' ? ( // OX 타입 -
    +
    + questionAssets
    @@ -356,9 +373,10 @@ const SurveyForm = ({
    ) : type === 'MULTIPLE_CHOICE' ? ( // 다중선택 -
    +
    + questionAssets
    @@ -448,9 +466,10 @@ const SurveyForm = ({
    ) : type === 'NUMERIC_CHOICE' ? ( // 숫자 선택 -
    +
    + questionAssets
    @@ -559,17 +578,19 @@ const SurveyForm = ({ />
    ) : type === 'RANK' ? ( -
    +
    + questionAssets
    ) : ( -
    +
    + questionAssets
    ( -
    +