Adding: themes, predictions, match reporting, ui fixes, sse fixes, badge fixes, match flow, i18n, match edits, perf, auth fix #22
@@ -17,6 +17,7 @@ interface AuthData {
|
||||
colorScheme: MantineColorScheme;
|
||||
theme?: string;
|
||||
locale?: string;
|
||||
seenThemesHint?: boolean;
|
||||
};
|
||||
roles: string[];
|
||||
phone: string;
|
||||
|
||||
@@ -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 (
|
||||
<UnstyledButton
|
||||
aria-label={t`Settings`}
|
||||
style={{ cursor: 'pointer', zIndex: 1000, display: 'flex' }}
|
||||
onClick={() => navigate({ to })}
|
||||
pos='absolute'
|
||||
right={20}
|
||||
top={6}
|
||||
<Tooltip
|
||||
label={t`Try the new themes`}
|
||||
opened={hintOpen}
|
||||
withArrow
|
||||
position="bottom-end"
|
||||
offset={8}
|
||||
transitionProps={{ transition: "fade-down", duration: 250 }}
|
||||
>
|
||||
<GearIcon weight='bold' size={20} />
|
||||
</UnstyledButton>
|
||||
<UnstyledButton
|
||||
aria-label={t`Settings`}
|
||||
style={{ cursor: 'pointer', zIndex: 1000, display: 'flex' }}
|
||||
onClick={() => navigate({ to })}
|
||||
pos='absolute'
|
||||
right={20}
|
||||
top={6}
|
||||
>
|
||||
<GearIcon weight='bold' size={20} />
|
||||
</UnstyledButton>
|
||||
</Tooltip>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -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 };
|
||||
};
|
||||
@@ -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])
|
||||
|
||||
@@ -2152,7 +2152,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"
|
||||
|
||||
@@ -2515,6 +2515,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"
|
||||
|
||||
@@ -2152,7 +2152,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"
|
||||
|
||||
@@ -2515,6 +2515,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"
|
||||
|
||||
@@ -2152,7 +2152,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"
|
||||
|
||||
@@ -2515,6 +2515,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"
|
||||
|
||||
@@ -2152,7 +2152,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 "設定"
|
||||
|
||||
@@ -2515,6 +2515,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"
|
||||
|
||||
Reference in New Issue
Block a user