diff --git a/src/contexts/auth-context.tsx b/src/contexts/auth-context.tsx index fa8fca7..a7e0e07 100644 --- a/src/contexts/auth-context.tsx +++ b/src/contexts/auth-context.tsx @@ -17,6 +17,7 @@ interface AuthData { colorScheme: MantineColorScheme; theme?: string; locale?: string; + seenThemesHint?: boolean; }; roles: string[]; phone: string; diff --git a/src/features/core/components/settings-button.tsx b/src/features/core/components/settings-button.tsx index a5f8faa..96162b7 100644 --- a/src/features/core/components/settings-button.tsx +++ b/src/features/core/components/settings-button.tsx @@ -1,8 +1,9 @@ -import { UnstyledButton } from "@mantine/core" +import { Tooltip, UnstyledButton } from "@mantine/core" import { GearIcon } from "@phosphor-icons/react" import { useNavigate } from "@tanstack/react-router" import { useLingui } from "@lingui/react/macro" -import { memo } from "react"; +import { memo, useEffect, useState } from "react"; +import { useThemeDiscovery } from "@/features/settings/hooks/use-theme-discovery"; interface SettingButtonProps { to: string; @@ -10,21 +11,48 @@ interface SettingButtonProps { right?: number; } +const HINT_SHOW_DELAY_MS = 900; +const HINT_VISIBLE_MS = 4000; + const SettingsButton = ({ to }: SettingButtonProps) => { const navigate = useNavigate(); const { t } = useLingui(); + const { showHint, markSeen } = useThemeDiscovery(); + const [hintOpen, setHintOpen] = useState(false); + + useEffect(() => { + if (!showHint) return; + const show = setTimeout(() => setHintOpen(true), HINT_SHOW_DELAY_MS); + const hide = setTimeout(() => { + setHintOpen(false); + markSeen(); + }, HINT_SHOW_DELAY_MS + HINT_VISIBLE_MS); + return () => { + clearTimeout(show); + clearTimeout(hide); + }; + }, [showHint, markSeen]); return ( - navigate({ to })} - pos='absolute' - right={20} - top={6} + - - + navigate({ to })} + pos='absolute' + right={20} + top={6} + > + + + ); } diff --git a/src/features/settings/hooks/use-theme-discovery.ts b/src/features/settings/hooks/use-theme-discovery.ts new file mode 100644 index 0000000..0ca1408 --- /dev/null +++ b/src/features/settings/hooks/use-theme-discovery.ts @@ -0,0 +1,18 @@ +import { useCallback } from "react"; +import { useAuth } from "@/contexts/auth-context"; +import { updateUserSeenThemesHint } from "@/features/settings/server"; + +/** Drives the one-time "new themes" tooltip on the profile settings gear. + * markSeen persists the flag, so each account sees the hint only once. */ +export const useThemeDiscovery = () => { + const { metadata, user, set } = useAuth(); + const showHint = !!user && !metadata.seenThemesHint; + + const markSeen = useCallback(() => { + if (!user || metadata.seenThemesHint) return; + set({ metadata: { ...metadata, seenThemesHint: true } }); + void updateUserSeenThemesHint(); + }, [user, metadata, set]); + + return { showHint, markSeen }; +}; diff --git a/src/features/settings/server.ts b/src/features/settings/server.ts index d60a582..32df0eb 100644 --- a/src/features/settings/server.ts +++ b/src/features/settings/server.ts @@ -95,6 +95,28 @@ export const updateUserTheme = createServerFn({ method: "POST" }) }; }); +export const updateUserSeenThemesHint = createServerFn({ method: "POST" }) + .middleware([superTokensFunctionMiddleware, serverFnLoggingMiddleware]) + .handler(async ({ context }) => { + const { userAuthId, metadata } = context; + if (!userAuthId) return; + + const { updateUserMetadataFields } = await import( + "@/utils/supertokens-core.server" + ); + + await updateUserMetadataFields(userAuthId, { + seenThemesHint: true, + }); + + return { + metadata: { + ...metadata, + seenThemesHint: true, + }, + }; + }); + export const updateUserAccentColor = createServerFn({ method: "POST" }) .validator((data: string) => data) .middleware([superTokensFunctionMiddleware, serverFnLoggingMiddleware]) diff --git a/src/locales/de/messages.po b/src/locales/de/messages.po index 55883f3..b9433ca 100644 --- a/src/locales/de/messages.po +++ b/src/locales/de/messages.po @@ -2154,7 +2154,7 @@ msgid "serverFn name" msgstr "serverFn-Name" #: src/app/routes/_authed/settings.tsx:16 -#: src/features/core/components/settings-button.tsx:19 +#: src/features/core/components/settings-button.tsx:46 msgid "Settings" msgstr "Einstellungen" @@ -2513,6 +2513,10 @@ msgstr "Turniere" msgid "trackId is required for playTrack action" msgstr "trackId ist für die playTrack-Aktion erforderlich" +#: src/features/core/components/settings-button.tsx:38 +msgid "Try the new themes" +msgstr "Probier die neuen Designs aus" + #: src/features/tournaments/components/upcoming-tournament/unenroll-free-agent.tsx:26 #: src/features/tournaments/components/upcoming-tournament/unenroll-team.tsx:34 msgid "Unenroll" diff --git a/src/locales/en/messages.po b/src/locales/en/messages.po index 7aa802a..37d3743 100644 --- a/src/locales/en/messages.po +++ b/src/locales/en/messages.po @@ -2154,7 +2154,7 @@ msgid "serverFn name" msgstr "serverFn name" #: src/app/routes/_authed/settings.tsx:16 -#: src/features/core/components/settings-button.tsx:19 +#: src/features/core/components/settings-button.tsx:46 msgid "Settings" msgstr "Settings" @@ -2513,6 +2513,10 @@ msgstr "Tournaments" msgid "trackId is required for playTrack action" msgstr "trackId is required for playTrack action" +#: src/features/core/components/settings-button.tsx:38 +msgid "Try the new themes" +msgstr "Try the new themes" + #: src/features/tournaments/components/upcoming-tournament/unenroll-free-agent.tsx:26 #: src/features/tournaments/components/upcoming-tournament/unenroll-team.tsx:34 msgid "Unenroll" diff --git a/src/locales/es/messages.po b/src/locales/es/messages.po index f40c3ae..0884172 100644 --- a/src/locales/es/messages.po +++ b/src/locales/es/messages.po @@ -2154,7 +2154,7 @@ msgid "serverFn name" msgstr "nombre de serverFn" #: src/app/routes/_authed/settings.tsx:16 -#: src/features/core/components/settings-button.tsx:19 +#: src/features/core/components/settings-button.tsx:46 msgid "Settings" msgstr "Configuración" @@ -2513,6 +2513,10 @@ msgstr "Torneos" msgid "trackId is required for playTrack action" msgstr "Se requiere trackId para la acción playTrack" +#: src/features/core/components/settings-button.tsx:38 +msgid "Try the new themes" +msgstr "Prueba los nuevos temas" + #: src/features/tournaments/components/upcoming-tournament/unenroll-free-agent.tsx:26 #: src/features/tournaments/components/upcoming-tournament/unenroll-team.tsx:34 msgid "Unenroll" diff --git a/src/locales/ja/messages.po b/src/locales/ja/messages.po index cc62b4d..bdddcff 100644 --- a/src/locales/ja/messages.po +++ b/src/locales/ja/messages.po @@ -2154,7 +2154,7 @@ msgid "serverFn name" msgstr "serverFn名" #: src/app/routes/_authed/settings.tsx:16 -#: src/features/core/components/settings-button.tsx:19 +#: src/features/core/components/settings-button.tsx:46 msgid "Settings" msgstr "設定" @@ -2513,6 +2513,10 @@ msgstr "トーナメント" msgid "trackId is required for playTrack action" msgstr "playTrackアクションにはtrackIdが必要です" +#: src/features/core/components/settings-button.tsx:38 +msgid "Try the new themes" +msgstr "新しいテーマを試してみましょう" + #: src/features/tournaments/components/upcoming-tournament/unenroll-free-agent.tsx:26 #: src/features/tournaments/components/upcoming-tournament/unenroll-team.tsx:34 msgid "Unenroll"