Add trust center v2

Signed-off-by: Jonathan <contact@grafikart.fr>
This commit is contained in:
Jonathan
2025-09-26 16:42:52 +02:00
committed by Sacha Al Himdani
parent 44898be9d3
commit 55e85e5f67
182 changed files with 4609 additions and 425 deletions

View File

@@ -0,0 +1,13 @@
import { createContext, useMemo } from "react";
export const AuthContext = createContext({ isAuthenticated: false });
type Props = {
children: React.ReactNode;
isAuthenticated: boolean;
};
export function AuthProvider({ children, isAuthenticated }: Props) {
const value = useMemo(() => ({ isAuthenticated }), [isAuthenticated]);
return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>;
}

View File

@@ -0,0 +1,146 @@
import {
Environment,
type FetchFunction,
Network,
RecordSource,
Store,
} from "relay-runtime";
import { GraphQLError } from "graphql";
import type { PropsWithChildren } from "react";
import { RelayEnvironmentProvider } from "react-relay";
export class UnAuthenticatedError extends Error {
constructor() {
super("UNAUTHENTICATED");
this.name = "UnAuthenticatedError";
}
}
export class InternalServerError extends Error {
constructor() {
super("INTERNAL_SERVER_ERROR");
this.name = "InternalServerError";
}
}
export function buildEndpoint(path: string): string {
const host = import.meta.env.VITE_API_URL;
if (!host) {
return path;
}
const formattedHost =
host.startsWith("http://") || host.startsWith("https://")
? host
: `https://${host}`;
const url = new URL(formattedHost);
if (path) {
url.pathname = path.startsWith("/") ? path : `/${path}`;
}
return url.toString();
}
const hasUnauthenticatedError = (error: GraphQLError) =>
error.extensions?.code == "UNAUTHENTICATED";
const fetchRelay: FetchFunction = async (
request,
variables,
_,
uploadables,
) => {
const requestInit: RequestInit = {
method: "POST",
credentials: "include",
headers: {},
};
if (uploadables) {
const formData = new FormData();
formData.append(
"operations",
JSON.stringify({
operationName: request.name,
query: request.text,
variables: variables,
}),
);
const uploadableMap: {
[key: string]: string[];
} = {};
Object.keys(uploadables).forEach((key, index) => {
uploadableMap[index] = [`variables.${key}`];
});
formData.append("map", JSON.stringify(uploadableMap));
Object.keys(uploadables).forEach((key, index) => {
formData.append(index.toString(), uploadables[key]);
});
requestInit.body = formData;
} else {
requestInit.headers = {
Accept:
"application/graphql-response+json; charset=utf-8, application/json; charset=utf-8",
"Content-Type": "application/json",
};
requestInit.body = JSON.stringify({
operationName: request.name,
query: request.text,
variables,
});
}
const response = await fetch(
buildEndpoint("/api/trust/v1/graphql"),
requestInit,
);
if (response.status === 500) {
throw new InternalServerError();
}
const json = await response.json();
if (json.errors) {
const errors = json.errors as GraphQLError[];
if (errors.find(hasUnauthenticatedError)) {
throw new UnAuthenticatedError();
}
throw new Error(`Error fetching GraphQL query '${request.name}'`);
}
return json;
};
const source = new RecordSource();
const store = new Store(source, {
queryCacheExpirationTime: 1 * 60 * 1000,
gcReleaseBufferSize: 20,
});
export const relayEnvironment = new Environment({
network: Network.create(fetchRelay),
store,
});
/**
* Provider for relay with the probo environment
*/
export function RelayProvider({ children }: PropsWithChildren) {
return (
<RelayEnvironmentProvider environment={relayEnvironment}>
{children}
</RelayEnvironmentProvider>
);
}

View File

@@ -0,0 +1,18 @@
import type { PropsWithChildren } from "react";
import { TranslatorProvider as ProboTranslatorProvider } from "../../../../packages/i18n/TranslatorProvider";
// TODO : implement a way to retrieve translations strings
const loader = () => {
return Promise.resolve({} as Record<string, string>);
};
/**
* Provider for the translator
*/
export function TranslatorProvider({ children }: PropsWithChildren) {
return (
<ProboTranslatorProvider lang="en" loader={loader}>
{children}
</ProboTranslatorProvider>
);
}

View File

@@ -0,0 +1,20 @@
import { createContext, type ReactNode } from "react";
import type { TrustGraphQuery$data } from "/queries/__generated__/TrustGraphQuery.graphql";
export const TrustCenterContext = createContext<
TrustGraphQuery$data["trustCenterBySlug"] | null
>(null);
export const TrustCenterProvider = ({
children,
trustCenter,
}: {
children: ReactNode;
trustCenter: TrustGraphQuery$data["trustCenterBySlug"];
}) => {
return (
<TrustCenterContext.Provider value={trustCenter}>
{children}
</TrustCenterContext.Provider>
);
};