Fixup ssr fetch

This commit is contained in:
Zoe Roux 2025-02-07 18:51:50 +01:00
parent 13cc334785
commit cd519998a7
No known key found for this signature in database
8 changed files with 45 additions and 38 deletions

View File

@ -1,6 +1,5 @@
import { HydrationBoundary } from "@tanstack/react-query";
import { ReactQueryDevtools } from "@tanstack/react-query-devtools";
import { Slot, getServerData } from "one";
import { Slot } from "one";
import { useServerHeadInsertion } from "one";
import { StyleRegistryProvider, createStyleRegistry, useTheme } from "yoshiki/web";
import { Providers } from "~/providers";
@ -63,8 +62,6 @@ export default function Layout() {
const registry = createStyleRegistry();
useServerHeadInsertion(() => registry.flushToComponent());
const queryState = getServerData("queryState");
// TODO: change this lang attr
return (
<html lang="en-US">
@ -82,12 +79,10 @@ export default function Layout() {
<body className="hoverEnabled">
<StyleRegistryProvider registry={registry}>
<HydrationBoundary state={queryState}>
<Providers>
<Slot />
<ReactQueryDevtools initialIsOpen={false} />
</Providers>
</HydrationBoundary>
<Providers>
<Slot />
<ReactQueryDevtools initialIsOpen={false} />
</Providers>
</StyleRegistryProvider>
</body>
</html>

7
front/app/_middleware.ts Normal file
View File

@ -0,0 +1,7 @@
import { createMiddleware, setServerData } from "one";
export default createMiddleware(({ request, next }) => {
console.log(request);
setServerData("cookies", request.headers.get("Cookies") ?? "");
return next();
});

View File

@ -8,12 +8,14 @@ import { removeAccounts, updateAccount } from "./account-store";
import { useSetError } from "./error-provider";
import { useStoreValue } from "./settings";
export const ssrApiUrl = process.env.KYOO_URL ?? "http://back/api";
export const AccountContext = createContext<{
apiUrl: string;
authToken: Token | null;
selectedAccount?: Account;
selectedAccount: Account | null;
accounts: (Account & { select: () => void; remove: () => void })[];
}>(undefined!);
}>({ apiUrl: ssrApiUrl, authToken: null, selectedAccount: null, accounts: [] });
export const AccountProvider = ({ children }: { children: ReactNode }) => {
const [setError, clearError] = useSetError("account");

View File

@ -39,7 +39,8 @@ export const ErrorConsumer = ({ children, scope }: { children: ReactNode; scope:
};
export const useSetError = (key: string) => {
const { error, setError } = useContext(ErrorContext);
const set = (obj: Omit<Error, "key">) => setError({ key, ...obj });
const set = ({ key: nKey, ...obj }: Error & { key?: Error["key"] }) =>
setError({ key: nKey ?? key, ...obj });
const clearError = () => {
if (error?.key === key) setError(null);
};

View File

@ -1,4 +1,5 @@
import { QueryClientProvider } from "@tanstack/react-query";
import { HydrationBoundary, QueryClientProvider } from "@tanstack/react-query";
import { getServerData } from "one";
import { type ReactNode, useState } from "react";
// import { useUserTheme } from "@kyoo/models";
import { ThemeSelector } from "~/primitives/theme";
@ -8,7 +9,11 @@ import { ErrorConsumer, ErrorProvider } from "./error-provider";
const QueryProvider = ({ children }: { children: ReactNode }) => {
const [queryClient] = useState(() => createQueryClient());
return <QueryClientProvider client={queryClient}>{children}</QueryClientProvider>;
return (
<QueryClientProvider client={queryClient}>
<HydrationBoundary state={getServerData("queryState")}>{children}</HydrationBoundary>
</QueryClientProvider>
);
};
const ThemeProvider = ({ children }: { children: ReactNode }) => {

View File

@ -1,3 +1,5 @@
import { getServerData } from "one";
import { Platform } from "react-native";
import { MMKV, useMMKVString } from "react-native-mmkv";
import type { ZodTypeAny, z } from "zod";
@ -22,12 +24,9 @@ export const setCookie = (key: string, val?: unknown) => {
document.cookie = `${key}=${value};${expires};path=/;samesite=strict`;
};
export const readCookie = <T extends ZodTypeAny>(
cookies: string | undefined,
key: string,
parser?: T,
) => {
if (!cookies) return undefined;
export const readCookie = <T extends ZodTypeAny>(key: string, parser: T) => {
const cookies = getServerData("cookies");
console.log("cookies", cookies);
const decodedCookie = decodeURIComponent(cookies);
const ca = decodedCookie.split(";");
@ -35,10 +34,13 @@ export const readCookie = <T extends ZodTypeAny>(
const ret = ca.find((x) => x.trimStart().startsWith(name));
if (ret === undefined) return undefined;
const str = fromBase64(ret.substring(name.length));
return parser ? (parser.parse(JSON.parse(str)) as z.infer<T>) : str;
return parser.parse(JSON.parse(str)) as z.infer<T>;
};
export const useStoreValue = <T extends ZodTypeAny>(key: string, parser: T) => {
if (Platform.OS === "web" && typeof window === "undefined") {
return readCookie(key, parser);
}
const [val] = useMMKVString(key);
if (val === undefined) return val;
return parser.parse(JSON.parse(val)) as z.infer<T>;
@ -49,6 +51,9 @@ export const storeValue = (key: string, value: unknown) => {
};
export const readValue = <T extends ZodTypeAny>(key: string, parser: T) => {
if (Platform.OS === "web" && typeof window === "undefined") {
return readCookie(key, parser);
}
const val = storage.getString(key);
if (val === undefined) return val;
return parser.parse(JSON.parse(val)) as z.infer<T>;

View File

@ -13,7 +13,7 @@ export const Fetch = <Data,>({
Loader: () => ReactElement;
}): JSX.Element | null => {
const { data, isPaused, error } = useFetch(query);
const setError = useSetError();
const [setError] = useSetError("fetch");
if (error) {
if (error.status === 401 || error.status === 403) {

View File

@ -1,9 +1,9 @@
import { QueryClient, dehydrate, useInfiniteQuery, useQuery } from "@tanstack/react-query";
import { setServerData } from "one";
import { type ComponentType, type ReactElement, useContext } from "react";
import { useContext } from "react";
import type { z } from "zod";
import { type KyooError, type Page, Paged } from "~/models";
import { AccountContext } from "~/providers/account-provider";
import { AccountContext, ssrApiUrl } from "~/providers/account-provider";
const cleanSlash = (str: string | null, keepFirst = false) => {
if (!str) return null;
@ -129,18 +129,6 @@ export type QueryIdentifier<T = unknown, Ret = T> = {
};
};
export type QueryPage<Props = {}, Items = unknown> = ComponentType<
Props & { randomItems: Items[] }
> & {
getFetchUrls?: (route: { [key: string]: string }, randomItems: Items[]) => QueryIdentifier<any>[];
getLayout?:
| QueryPage<{ page: ReactElement }>
| { Layout: QueryPage<{ page: ReactElement }>; props: object };
requiredPermissions?: string[];
randomItems?: Items[];
isPublic?: boolean;
};
export const toQueryKey = (query: {
apiUrl: string;
path: (string | undefined)[];
@ -212,7 +200,11 @@ export const prefetch = async (...queries: QueryIdentifier[]) => {
await Promise.all(
queries.map((query) => {
const key = toQueryKey({ apiUrl: "/api", path: query.path, params: query.params });
const key = toQueryKey({
apiUrl: ssrApiUrl,
path: query.path,
params: query.params,
});
if (query.infinite) {
return client.prefetchInfiniteQuery({