From 3936a09113ef1feb9e90500e5358a2006d14eb95 Mon Sep 17 00:00:00 2001 From: baegyeong Date: Mon, 2 Dec 2024 03:23:04 +0900 Subject: [PATCH 1/7] =?UTF-8?q?=E2=9C=A8=20feat:=20patch=20=EC=9C=A0?= =?UTF-8?q?=ED=8B=B8=20=ED=95=A8=EC=88=98=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/frontend/src/apis/utils/patch.ts | 25 +++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 packages/frontend/src/apis/utils/patch.ts diff --git a/packages/frontend/src/apis/utils/patch.ts b/packages/frontend/src/apis/utils/patch.ts new file mode 100644 index 00000000..9b535e6c --- /dev/null +++ b/packages/frontend/src/apis/utils/patch.ts @@ -0,0 +1,25 @@ +import { AxiosRequestConfig } from 'axios'; +import { z } from 'zod'; +import { instance } from '../config'; +import { formatZodError } from './formatZodError'; + +interface PatchParams { + params?: AxiosRequestConfig['params']; + schema: z.ZodType; + url: string; +} + +export const patch = async ({ + params, + schema, + url, +}: PatchParams): Promise => { + const { data } = await instance.patch(url, params); + const result = schema.safeParse(data); + + if (!result.success) { + throw new Error(formatZodError(result.error)); + } + + return data; +}; From b5147a32775176ff0c8b33144d3968f03f830367 Mon Sep 17 00:00:00 2001 From: baegyeong Date: Mon, 2 Dec 2024 03:23:38 +0900 Subject: [PATCH 2/7] =?UTF-8?q?=E2=9C=A8=20feat:=20=EB=8B=A4=ED=81=AC?= =?UTF-8?q?=EB=AA=A8=EB=93=9C=20get,=20patch=20=EC=8A=A4=ED=82=A4=EB=A7=88?= =?UTF-8?q?=20=EB=B0=8F=20api=20=EC=A0=95=EC=9D=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../frontend/src/apis/queries/user/index.ts | 2 ++ .../frontend/src/apis/queries/user/schema.ts | 13 ++++++++-- .../src/apis/queries/user/useGetUserTheme.ts | 17 ++++++++++++ .../apis/queries/user/usePatchUserTheme.ts | 26 +++++++++++++++++++ 4 files changed, 56 insertions(+), 2 deletions(-) create mode 100644 packages/frontend/src/apis/queries/user/useGetUserTheme.ts create mode 100644 packages/frontend/src/apis/queries/user/usePatchUserTheme.ts diff --git a/packages/frontend/src/apis/queries/user/index.ts b/packages/frontend/src/apis/queries/user/index.ts index 9e26a7fd..185cd442 100644 --- a/packages/frontend/src/apis/queries/user/index.ts +++ b/packages/frontend/src/apis/queries/user/index.ts @@ -2,3 +2,5 @@ export * from './schema'; export * from './useGetUserInfo'; export * from './useGetUserStock'; export * from './usePostUserNickname'; +export * from './useGetUserTheme'; +export * from './usePatchUserTheme'; diff --git a/packages/frontend/src/apis/queries/user/schema.ts b/packages/frontend/src/apis/queries/user/schema.ts index bc716011..6bd06f87 100644 --- a/packages/frontend/src/apis/queries/user/schema.ts +++ b/packages/frontend/src/apis/queries/user/schema.ts @@ -34,8 +34,17 @@ export const PostUserNicknameSchema = z.object({ export type PostUserNickname = z.infer; -export const GetUserThemeSchema = z.object({ +export const UserThemeSchema = z.object({ theme: z.enum(['light', 'dark']), }); -export type GetUserTheme = z.infer; +export type GetUserTheme = z.infer; + +export type PatchUserThemeRequest = z.infer; + +export const PatchUserThemeSchema = z.object({ + theme: z.enum(['light', 'dark']), + updatedAt: z.string().datetime(), +}); + +export type PatchUserTheme = z.infer; diff --git a/packages/frontend/src/apis/queries/user/useGetUserTheme.ts b/packages/frontend/src/apis/queries/user/useGetUserTheme.ts new file mode 100644 index 00000000..31291a65 --- /dev/null +++ b/packages/frontend/src/apis/queries/user/useGetUserTheme.ts @@ -0,0 +1,17 @@ +import { useQuery } from '@tanstack/react-query'; +import { UserThemeSchema, type GetUserTheme } from './schema'; +import { get } from '@/apis/utils/get'; + +const getUserTheme = () => + get({ + schema: UserThemeSchema, + url: '/api/user/theme', + }); + +export const useGetUserTheme = () => { + return useQuery({ + queryKey: ['userTheme'], + queryFn: getUserTheme, + staleTime: 1000 * 60 * 5, + }); +}; diff --git a/packages/frontend/src/apis/queries/user/usePatchUserTheme.ts b/packages/frontend/src/apis/queries/user/usePatchUserTheme.ts new file mode 100644 index 00000000..fe7daf12 --- /dev/null +++ b/packages/frontend/src/apis/queries/user/usePatchUserTheme.ts @@ -0,0 +1,26 @@ +import { useMutation, useQueryClient } from '@tanstack/react-query'; +import { + type PatchUserTheme, + type PatchUserThemeRequest, + UserThemeSchema, +} from './schema'; +import { patch } from '@/apis/utils/patch'; + +const patchUserTheme = ({ theme }: PatchUserThemeRequest) => + patch({ + params: { theme }, + schema: UserThemeSchema, + url: '/api/user/theme', + }); + +export const usePatchUserTheme = () => { + const queryClient = useQueryClient(); + + return useMutation({ + mutationKey: ['patchTheme'], + mutationFn: ({ theme }: PatchUserThemeRequest) => patchUserTheme({ theme }), + onSuccess: () => { + queryClient.invalidateQueries({ queryKey: ['userTheme'] }); + }, + }); +}; From d366d397e3add4ff7fc9e9eddbc04d54ec5563c2 Mon Sep 17 00:00:00 2001 From: baegyeong Date: Mon, 2 Dec 2024 03:24:17 +0900 Subject: [PATCH 3/7] =?UTF-8?q?=E2=9C=A8=20feat:=20=EB=8B=A4=ED=81=AC?= =?UTF-8?q?=EB=AA=A8=EB=93=9C=20=EC=84=9C=EB=B2=84=20=EC=83=81=ED=83=9C?= =?UTF-8?q?=EB=A5=BC=20=ED=99=9C=EC=9A=A9=ED=95=B4=EC=84=9C=20=EC=A0=81?= =?UTF-8?q?=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/components/layouts/Sidebar.tsx | 23 +++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/packages/frontend/src/components/layouts/Sidebar.tsx b/packages/frontend/src/components/layouts/Sidebar.tsx index 2a166981..9bc06d9d 100644 --- a/packages/frontend/src/components/layouts/Sidebar.tsx +++ b/packages/frontend/src/components/layouts/Sidebar.tsx @@ -1,10 +1,12 @@ -import { useState } from 'react'; +import { useEffect, useState } from 'react'; import { useNavigate } from 'react-router-dom'; import logoCharacter from '/logoCharacter.png'; import logoTitle from '/logoTitle.png'; import { Alarm } from './alarm'; import { MenuList } from './MenuList'; import { Search } from './search'; +import { useGetUserTheme } from '@/apis/queries/user/useGetUserTheme'; +import { usePatchUserTheme } from '@/apis/queries/user/usePatchUserTheme'; import { BOTTOM_MENU_ITEMS, TOP_MENU_ITEMS } from '@/constants/menuItems'; import { useOutsideClick } from '@/hooks/useOutsideClick'; import { type MenuSection } from '@/types/menu'; @@ -20,6 +22,17 @@ export const Sidebar = () => { alarm: false, }); + const { data } = useGetUserTheme(); + const { mutate } = usePatchUserTheme(); + + useEffect(() => { + if (data?.theme === 'light') { + document.body.classList.remove('dark'); + return; + } + document.body.classList.add('dark'); + }, [data]); + const ref = useOutsideClick(() => { setShowTabs({ search: false, alarm: false }); }); @@ -44,7 +57,13 @@ export const Sidebar = () => { } if (item.text === '다크모드') { - document.body.classList.toggle('dark'); + if (data?.theme === 'dark') { + mutate({ theme: 'light' }); + } + + if (data?.theme === 'light') { + mutate({ theme: 'dark' }); + } } }; From 7e776e44cfbee8dfeec2a29fad7f3db7092c15e1 Mon Sep 17 00:00:00 2001 From: baegyeong Date: Mon, 2 Dec 2024 03:24:33 +0900 Subject: [PATCH 4/7] =?UTF-8?q?=E2=9C=A8=20feat:=20=EA=B7=B8=EB=9E=98?= =?UTF-8?q?=ED=94=84=EC=97=90=20=EB=8B=A4=ED=81=AC=EB=AA=A8=EB=93=9C=20?= =?UTF-8?q?=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/pages/stock-detail/TradingChart.tsx | 8 +------- .../src/pages/stock-detail/hooks/useChart.ts | 14 ++++++++------ 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/packages/frontend/src/pages/stock-detail/TradingChart.tsx b/packages/frontend/src/pages/stock-detail/TradingChart.tsx index f0aa7ac2..537c1456 100644 --- a/packages/frontend/src/pages/stock-detail/TradingChart.tsx +++ b/packages/frontend/src/pages/stock-detail/TradingChart.tsx @@ -8,13 +8,8 @@ import { useGetStocksPriceSeries, } from '@/apis/queries/stocks'; import { TIME_UNIT } from '@/constants/timeUnit'; -import { ChartTheme, lightTheme } from '@/styles/theme'; -interface TradingChartProps { - theme?: ChartTheme; -} - -export const TradingChart = ({ theme = lightTheme }: TradingChartProps) => { +export const TradingChart = () => { const { stockId } = useParams(); const [timeunit, setTimeunit] = useState('day'); @@ -29,7 +24,6 @@ export const TradingChart = ({ theme = lightTheme }: TradingChartProps) => { priceData: data?.priceDtoList ?? [], volumeData: data?.volumeDtoList ?? [], containerRef, - theme, }); useChartResize({ containerRef, chart }); diff --git a/packages/frontend/src/pages/stock-detail/hooks/useChart.ts b/packages/frontend/src/pages/stock-detail/hooks/useChart.ts index 16ec9c90..c461c090 100644 --- a/packages/frontend/src/pages/stock-detail/hooks/useChart.ts +++ b/packages/frontend/src/pages/stock-detail/hooks/useChart.ts @@ -1,4 +1,3 @@ -import type { ChartTheme } from '@/styles/theme'; import { createChart, type IChartApi } from 'lightweight-charts'; import { useEffect, useRef, RefObject } from 'react'; import { @@ -6,6 +5,8 @@ import { StockTimeSeriesResponse, VolumeSchema, } from '@/apis/queries/stocks'; +import { useGetUserTheme } from '@/apis/queries/user'; +import { darkTheme, lightTheme } from '@/styles/theme'; import { createCandlestickOptions, createChartOptions, @@ -15,7 +16,6 @@ import { getHistogramColorData } from '@/utils/getHistogramColorData'; interface UseChartProps { containerRef: RefObject; - theme: ChartTheme; priceData: StockTimeSeriesResponse['priceDtoList']; volumeData: StockTimeSeriesResponse['volumeDtoList']; } @@ -35,19 +35,21 @@ const TransformVolumeData = VolumeSchema.transform((item) => ({ export const useChart = ({ containerRef, - theme, priceData, volumeData, }: UseChartProps) => { const chart = useRef(); + const { data } = useGetUserTheme(); + const graphTheme = data?.theme === 'light' ? lightTheme : darkTheme; + useEffect(() => { if (!containerRef.current) return; chart.current = createChart(containerRef.current, { width: containerRef.current.clientWidth, height: containerRef.current.clientHeight, - ...createChartOptions(theme), + ...createChartOptions(graphTheme), handleScroll: { mouseWheel: false, pressedMouseMove: false, @@ -74,7 +76,7 @@ export const useChart = ({ volumeSeries.setData(histogramData); const candleSeries = chart.current.addCandlestickSeries( - createCandlestickOptions(theme), + createCandlestickOptions(graphTheme), ); const transformedPriceData = priceData.map((item) => TransformPriceData.parse(item), @@ -84,7 +86,7 @@ export const useChart = ({ return () => { chart.current?.remove(); }; - }, [containerRef, theme, priceData, volumeData]); + }, [containerRef, graphTheme, priceData, volumeData]); return chart; }; From 42b4aaf1ad4ea1c81abb16c31ba3a70db10647aa Mon Sep 17 00:00:00 2001 From: baegyeong Date: Mon, 2 Dec 2024 11:58:18 +0900 Subject: [PATCH 5/7] =?UTF-8?q?=F0=9F=90=9B=20fix:=20=EB=A1=9C=EA=B7=B8?= =?UTF-8?q?=EC=9D=B8=20backdrop=EC=9D=B4=20=EC=A0=81=EC=9A=A9=EB=90=98?= =?UTF-8?q?=EC=A7=80=20=EC=95=8A=EB=8A=94=20=EB=AC=B8=EC=A0=9C=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/frontend/src/pages/login/Login.tsx | 4 ++-- packages/frontend/tailwind.config.ts | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/frontend/src/pages/login/Login.tsx b/packages/frontend/src/pages/login/Login.tsx index 6b6f1793..a2e515ea 100644 --- a/packages/frontend/src/pages/login/Login.tsx +++ b/packages/frontend/src/pages/login/Login.tsx @@ -9,8 +9,8 @@ export const Login = () => { return (
-
-
+
+

스마트한 투자의 첫걸음,

주춤주춤과 함께해요!

diff --git a/packages/frontend/tailwind.config.ts b/packages/frontend/tailwind.config.ts index fdc77a65..38c7637e 100644 --- a/packages/frontend/tailwind.config.ts +++ b/packages/frontend/tailwind.config.ts @@ -7,6 +7,7 @@ const config: Config = { extend: { backgroundColor: { 'black/4': 'rgba(0, 0, 0, 0.4)', + 'white/4': 'rgba(255,255,255,0.4)', }, }, colors: { From 886a5b7fe86df98486513cdb4cbb4086ace50f8f Mon Sep 17 00:00:00 2001 From: baegyeong Date: Mon, 2 Dec 2024 13:35:07 +0900 Subject: [PATCH 6/7] =?UTF-8?q?=F0=9F=90=9B=20fix:=20isRising=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/frontend/src/apis/queries/stocks/schema.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/frontend/src/apis/queries/stocks/schema.ts b/packages/frontend/src/apis/queries/stocks/schema.ts index 4e14cb54..8b486e95 100644 --- a/packages/frontend/src/apis/queries/stocks/schema.ts +++ b/packages/frontend/src/apis/queries/stocks/schema.ts @@ -15,6 +15,7 @@ export const GetStockSchema = z.object({ volume: z.number(), marketCap: z.string(), rank: z.number(), + isRising: z.boolean(), }); export const GetStockListResponseSchema = z.object({ From a9bb13098c864592ec1fab4310aa02d62fece0ab Mon Sep 17 00:00:00 2001 From: baegyeong Date: Mon, 2 Dec 2024 13:35:31 +0900 Subject: [PATCH 7/7] =?UTF-8?q?=F0=9F=90=9B=20fix:=20=EA=B2=80=EC=83=89,?= =?UTF-8?q?=20=EB=B2=84=ED=8A=BC=20=EC=8A=A4=ED=83=80=EC=9D=BC=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/frontend/src/components/layouts/search/Search.tsx | 1 + packages/frontend/src/components/ui/button/Button.tsx | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/frontend/src/components/layouts/search/Search.tsx b/packages/frontend/src/components/layouts/search/Search.tsx index a82b3b5b..d5485406 100644 --- a/packages/frontend/src/components/layouts/search/Search.tsx +++ b/packages/frontend/src/components/layouts/search/Search.tsx @@ -26,6 +26,7 @@ export const Search = ({ className }: SearchProps) => {

setStockName(e.target.value)} autoFocus diff --git a/packages/frontend/src/components/ui/button/Button.tsx b/packages/frontend/src/components/ui/button/Button.tsx index 056a8c4b..e5f68527 100644 --- a/packages/frontend/src/components/ui/button/Button.tsx +++ b/packages/frontend/src/components/ui/button/Button.tsx @@ -3,7 +3,7 @@ import { cva, VariantProps } from 'class-variance-authority'; import { cn } from '@/utils/cn'; export const ButtonVariants = cva( - `display-bold12 border rounded shadow-black py-1 border-orange`, + `display-bold14 border rounded shadow-black py-1 border-orange`, { variants: { backgroundColor: {