Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
45 lines
1.6 KiB
TypeScript
45 lines
1.6 KiB
TypeScript
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
|
|
import { useEffect, useState } from 'react';
|
|
import { api, ApiError, type Me } from './api.ts';
|
|
|
|
export const ME_KEY = ['me'] as const;
|
|
|
|
/** Текущий пользователь; null — не вошёл. */
|
|
export function useMe() {
|
|
return useQuery({
|
|
queryKey: ME_KEY,
|
|
queryFn: async (): Promise<Me | null> => {
|
|
try {
|
|
return await api<Me>('/me');
|
|
} catch (e) {
|
|
if (e instanceof ApiError && e.status === 401) return null;
|
|
throw e;
|
|
}
|
|
},
|
|
});
|
|
}
|
|
|
|
/** Мутация, после которой перечитываются указанные запросы (по умолчанию — все). */
|
|
export function useAction<TArgs = void, TResult = unknown>(
|
|
fn: (args: TArgs) => Promise<TResult>,
|
|
invalidate?: readonly unknown[],
|
|
) {
|
|
const qc = useQueryClient();
|
|
return useMutation({
|
|
mutationFn: fn,
|
|
onSuccess: () => qc.invalidateQueries(invalidate ? { queryKey: invalidate } : undefined),
|
|
});
|
|
}
|
|
|
|
export type Theme = 'dark' | 'light';
|
|
|
|
export function useTheme(): [Theme, () => void] {
|
|
const [theme, setTheme] = useState<Theme>(() => (localStorage.getItem('lr_theme') === 'light' ? 'light' : 'dark'));
|
|
useEffect(() => {
|
|
document.documentElement.dataset.theme = theme;
|
|
localStorage.setItem('lr_theme', theme);
|
|
document.querySelector('meta[name="theme-color"]')?.setAttribute('content', theme === 'light' ? '#f6f8fb' : '#020617');
|
|
}, [theme]);
|
|
return [theme, () => setTheme((v) => (v === 'dark' ? 'light' : 'dark'))];
|
|
}
|