praktika pilot→expired role in roles.yaml (paths:[], deny:/**); RouteGuard short-circuits on role=expired with a dedicated trial-ended screen (not the generic path-deny path). NoAccessScreen gains variant="trial" with title «Пробный доступ закончился» and a Telegram link to @ArtemKopylov87. Backend Role Literal and frontend Role type extended to include "expired". kopylov (pilot) unaffected.
52 lines
1.7 KiB
TypeScript
52 lines
1.7 KiB
TypeScript
"use client";
|
||
|
||
/**
|
||
* MIRROR of main frontend `frontend/src/lib/useMe.ts` — keep in sync manually.
|
||
*
|
||
* Tradein-mvp — отдельный Next.js bundle с basePath=/trade-in. `apiFetch`
|
||
* автоматически префиксит `API_BASE_URL` (= `/trade-in` в проде, "" в dev),
|
||
* поэтому путь `/api/v1/me` в проде превращается в `/trade-in/api/v1/me` →
|
||
* Caddy `uri strip_prefix /trade-in` → tradein-backend `/api/v1/me`.
|
||
* Tradein-backend имеет mirror endpoint `/me` (см. `tradein-mvp/backend/app/api/v1/me.py`).
|
||
*/
|
||
|
||
import { useQuery } from "@tanstack/react-query";
|
||
|
||
import { apiFetchWithStatus, HTTPError } from "@/lib/api";
|
||
|
||
export type Role = "admin" | "pilot" | "expired";
|
||
|
||
export interface UserScope {
|
||
username: string;
|
||
role: Role;
|
||
allowed_paths: string[];
|
||
deny_paths: string[];
|
||
// #657 brand-by-account: slug бренда, привязанный к аккаунту (praktika→"praktika").
|
||
// null/undefined = generic UI. useBrand применяет его автоматически на login.
|
||
brand?: string | null;
|
||
}
|
||
|
||
export const ME_QUERY_KEY = ["auth", "me"] as const;
|
||
|
||
async function fetchMe(): Promise<UserScope> {
|
||
const { body } = await apiFetchWithStatus<UserScope>("/api/v1/me");
|
||
return body;
|
||
}
|
||
|
||
export function useMe() {
|
||
return useQuery<UserScope, Error>({
|
||
queryKey: ME_QUERY_KEY,
|
||
queryFn: fetchMe,
|
||
staleTime: Infinity,
|
||
gcTime: Infinity,
|
||
refetchOnWindowFocus: false,
|
||
refetchOnReconnect: false,
|
||
refetchOnMount: false,
|
||
retry: (failureCount, error) => {
|
||
if (error instanceof HTTPError && (error.status === 401 || error.status === 403)) {
|
||
return false;
|
||
}
|
||
return failureCount < 2;
|
||
},
|
||
});
|
||
}
|