mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-12 06:06:10 +00:00
refactor(query-keys): expand factory and migrate auth, notifications, about
Routes the registration-status, auth invalidation, notifications preferences, and Settings about-section api-version reads through the centralised queryKeys factory. Adds factory entries for the remaining settings/admin surfaces a follow-up will migrate, and extends the walker test to fail on any future bare-literal queryKey in src/app/auth, src/app/notifications, and the about-section. Also swaps the dashboard tile Suspense fallback from null to a layout-stable card placeholder so a future RSC hoist of any tile slot can't trigger CLS.
This commit is contained in:
1 parent
59befdca73
commit
0bf07abd9d
7 files changed
+106
-14
No files matched your search
@@ -85,7 +85,7 @@ export default function LoginPage() {
|
||||
return;
|
||||
}
|
||||
|
||||
await queryClient.invalidateQueries({ queryKey: ["auth"] });
|
||||
await queryClient.invalidateQueries({ queryKey: queryKeys.auth() });
|
||||
router.push(getRedirectTarget());
|
||||
} catch (err) {
|
||||
const { key, params } = describePasskeyError(err);
|
||||
@@ -114,7 +114,7 @@ export default function LoginPage() {
|
||||
return;
|
||||
}
|
||||
|
||||
await queryClient.invalidateQueries({ queryKey: ["auth"] });
|
||||
await queryClient.invalidateQueries({ queryKey: queryKeys.auth() });
|
||||
router.push(getRedirectTarget());
|
||||
} catch {
|
||||
setError(t("auth.loginFailed"));
|
||||
|
||||
@@ -12,6 +12,7 @@ import { Label } from "@/components/ui/label";
|
||||
import { PasswordStrength } from "@/components/ui/password-strength";
|
||||
import { useTranslations } from "@/lib/i18n/context";
|
||||
import { detectBrowserTimezone } from "@/lib/tz/format";
|
||||
import { queryKeys } from "@/lib/query-keys";
|
||||
|
||||
export default function RegisterPage() {
|
||||
const router = useRouter();
|
||||
@@ -54,7 +55,7 @@ export default function RegisterPage() {
|
||||
return;
|
||||
}
|
||||
|
||||
await queryClient.invalidateQueries({ queryKey: ["auth"] });
|
||||
await queryClient.invalidateQueries({ queryKey: queryKeys.auth() });
|
||||
router.push("/");
|
||||
} catch {
|
||||
setError(t("auth.registerFailed"));
|
||||
|
||||
@@ -12,6 +12,7 @@ import {
|
||||
EVENT_DEFAULT_ENABLED,
|
||||
type EventType,
|
||||
} from "@/lib/notifications/types";
|
||||
import { queryKeys } from "@/lib/query-keys";
|
||||
|
||||
interface ChannelInfo {
|
||||
id: string;
|
||||
@@ -86,7 +87,7 @@ export default function NotificationsPage() {
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
const { data, isLoading, isError } = useQuery({
|
||||
queryKey: ["notifications", "preferences"],
|
||||
queryKey: queryKeys.notificationsPreferences(),
|
||||
queryFn: async () => {
|
||||
const res = await fetch("/api/notifications/preferences");
|
||||
if (!res.ok) throw new Error("Failed to load preferences");
|
||||
@@ -112,12 +113,11 @@ export default function NotificationsPage() {
|
||||
},
|
||||
onMutate: async ({ channelId, eventType, enabled }) => {
|
||||
await queryClient.cancelQueries({
|
||||
queryKey: ["notifications", "preferences"],
|
||||
queryKey: queryKeys.notificationsPreferences(),
|
||||
});
|
||||
const prev = queryClient.getQueryData<PreferencesData>([
|
||||
"notifications",
|
||||
"preferences",
|
||||
]);
|
||||
const prev = queryClient.getQueryData<PreferencesData>(
|
||||
queryKeys.notificationsPreferences(),
|
||||
);
|
||||
if (prev) {
|
||||
const existing = prev.preferences.find(
|
||||
(p) => p.channelId === channelId && p.eventType === eventType,
|
||||
@@ -130,7 +130,7 @@ export default function NotificationsPage() {
|
||||
)
|
||||
: [...prev.preferences, { channelId, eventType, enabled }];
|
||||
queryClient.setQueryData<PreferencesData>(
|
||||
["notifications", "preferences"],
|
||||
queryKeys.notificationsPreferences(),
|
||||
{ ...prev, preferences: newPreferences },
|
||||
);
|
||||
}
|
||||
@@ -139,14 +139,14 @@ export default function NotificationsPage() {
|
||||
onError: (_err, _vars, context) => {
|
||||
if (context?.prev) {
|
||||
queryClient.setQueryData(
|
||||
["notifications", "preferences"],
|
||||
queryKeys.notificationsPreferences(),
|
||||
context.prev,
|
||||
);
|
||||
}
|
||||
},
|
||||
onSettled: () => {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: ["notifications", "preferences"],
|
||||
queryKey: queryKeys.notificationsPreferences(),
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
+19
-1
@@ -1413,7 +1413,25 @@ export default function DashboardPage() {
|
||||
* future RSC hoists of any tile slot won't need a
|
||||
* second pass to add the fallback infrastructure.
|
||||
*/}
|
||||
<Suspense fallback={null}>{entry.node}</Suspense>
|
||||
{/*
|
||||
* v1.4.41 W-FRONTEND-FACTORY (UX M1) — swap the
|
||||
* `null` fallback for a layout-stable placeholder
|
||||
* that mirrors the trend-card chrome. The body
|
||||
* stays synchronous today so the fallback rarely
|
||||
* paints, but a future RSC hoist of any tile slot
|
||||
* would otherwise leave the grid track empty and
|
||||
* trigger CLS as the cell paints in.
|
||||
*/}
|
||||
<Suspense
|
||||
fallback={
|
||||
<div
|
||||
aria-hidden="true"
|
||||
className="bg-card border-border h-full w-full rounded-xl border p-4 md:p-6"
|
||||
/>
|
||||
}
|
||||
>
|
||||
{entry.node}
|
||||
</Suspense>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
Reference in new issue
Block a user