Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

tRPC : ready for production ✨ #3437

Merged
merged 11 commits into from
Nov 25, 2024
4 changes: 2 additions & 2 deletions Earthfile
Original file line number Diff line number Diff line change
Expand Up @@ -449,7 +449,7 @@ app-run: ## construit et lance l'image de l'app en local
app-test-build: ## construit une image pour exécuter les tests unitaires de l'app
FROM +front-deps
ENV NEXT_PUBLIC_SUPABASE_URL
ENV NEXT_PUBLIC_SUPABASE_KEY
ENV NEXT_PUBLIC_SUPABASE_ANON_KEY
# copie les sources du module à tester
COPY $APP_DIR $APP_DIR
COPY $API_DIR $API_DIR
Expand All @@ -467,7 +467,7 @@ app-test: ## lance les tests unitaires de l'app
--name app-test_tet \
--env CI=true \ # désactive le mode watch quand on lance la commande en local
--env NEXT_PUBLIC_SUPABASE_URL='http://fake' \
--env NEXT_PUBLIC_SUPABASE_KEY='fake' \
--env NEXT_PUBLIC_SUPABASE_ANON_KEY='fake' \
app-test:latest

package-api-test-build: ## construit une image pour exécuter les tests d'intégration de l'api
Expand Down
2 changes: 1 addition & 1 deletion app.territoiresentransitions.react/.env.sample
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
NEXT_PUBLIC_SUPABASE_KEY=${ANON_KEY}
NEXT_PUBLIC_SUPABASE_ANON_KEY=${ANON_KEY}
NEXT_PUBLIC_SUPABASE_URL=${API_URL}
NEXT_PUBLIC_CRISP_WEBSITE_ID="// Crisp integration (warning: use different ID by deployment env.)"
NEXT_PUBLIC_SENTRY_DSN=
Expand Down
4 changes: 2 additions & 2 deletions app.territoiresentransitions.react/Earthfile
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ build:
# Disable telemetry during build
ENV NEXT_TELEMETRY_DISABLED=1

ENV NEXT_PUBLIC_SUPABASE_KEY=$ANON_KEY
ENV NEXT_PUBLIC_SUPABASE_ANON_KEY=$ANON_KEY
ENV NEXT_PUBLIC_SUPABASE_URL=$API_URL
ENV NEXT_PUBLIC_AUTH_URL=$AUTH_URL
ENV NEXT_PUBLIC_PANIER_URL=$PANIER_URL
Expand Down Expand Up @@ -48,7 +48,7 @@ docker:
ARG CRISP_WEBSITE_ID
ARG SENTRY_DSN

ENV NEXT_PUBLIC_SUPABASE_KEY=$ANON_KEY
ENV NEXT_PUBLIC_SUPABASE_ANON_KEY=$ANON_KEY
ENV NEXT_PUBLIC_SUPABASE_URL=$API_URL
ENV NEXT_PUBLIC_AUTH_URL=$AUTH_URL
ENV NEXT_PUBLIC_PANIER_URL=$PANIER_URL
Expand Down
31 changes: 12 additions & 19 deletions app.territoiresentransitions.react/src/app/app-providers.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,12 @@
'use client';

import { createTheme, ThemeProvider } from '@mui/material/styles';
import {
QueryClient as TanstackQueryClient,
QueryClientProvider as TanstackQueryClientProvider,
} from '@tanstack/react-query';
import { TRPCProvider } from '@tet/api/utils/trpc/client';
import { createTrackingClient, TrackingProvider } from '@tet/ui';
import { ENV } from 'environmentVariables';
import { QueryClient, QueryClientProvider } from 'react-query';
import { ReactQueryDevtools } from 'react-query/devtools';
import { AuthProvider } from '../core-logic/api/auth/AuthProvider';
import { ENV } from 'environmentVariables';
import { trpc, trpcClient } from '../utils/trpc';

const theme = createTheme({
palette: {
Expand All @@ -22,7 +18,6 @@ const theme = createTheme({

const trackingClient = createTrackingClient(ENV.posthog);
const queryClient = new QueryClient();
const tanstackQueryClient = new TanstackQueryClient();

export default function AppProviders({
children,
Expand All @@ -31,18 +26,16 @@ export default function AppProviders({
}) {
return (
<TrackingProvider client={trackingClient}>
<trpc.Provider client={trpcClient} queryClient={tanstackQueryClient}>
<TanstackQueryClientProvider client={tanstackQueryClient}>
<QueryClientProvider client={queryClient}>
<AuthProvider>
<ThemeProvider theme={theme}>
<ReactQueryDevtools initialIsOpen={false} />
{children}
</ThemeProvider>
</AuthProvider>
</QueryClientProvider>
</TanstackQueryClientProvider>
</trpc.Provider>
<TRPCProvider>
<QueryClientProvider client={queryClient}>
<AuthProvider>
<ThemeProvider theme={theme}>
<ReactQueryDevtools initialIsOpen={false} />
{children}
</ThemeProvider>
</AuthProvider>
</QueryClientProvider>
</TRPCProvider>
</TrackingProvider>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,10 @@ const PlanActionCard = ({
openInNewTab,
display = 'row',
}: Props) => {
const { data } = useFichesActionStatuts({
const { data: countByStatut } = useFichesActionStatuts({
plan_ids: plan.id.toString(),
});

const statuts = data?.par_statut;

const axesCount = plan.axes?.reduce(
(acc: { axe: number; sousAxe: number }, axe: Axe) => {
if (axe.parent === plan.id) {
Expand All @@ -42,8 +40,8 @@ const PlanActionCard = ({
{ axe: 0, sousAxe: 0 }
);

const fichesCount = statuts
? Object.values(statuts).reduce((acc, curr) => acc + curr.count, 0)
const fichesCount = countByStatut
? Object.values(countByStatut).reduce((acc, curr) => acc + curr.count, 0)
: 0;

return (
Expand All @@ -65,9 +63,9 @@ const PlanActionCard = ({
)}
</div>
{/** Statuts de fiches */}
{statuts && (
{countByStatut && (
<Statuts
statuts={statuts}
statuts={countByStatut}
fichesCount={fichesCount}
display={display}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ type Props = {
statuts: {
[key: string]: {
count: number;
valeur: Statut;
valeur: Statut | 'Sans statut';
};
};
fichesCount: number;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ const ModuleAvancementFichesAction = ({ module }: Props) => {

const filtres = module.options.filtre;

const { data, isLoading } = useFichesActionStatuts(
const { data: countByStatut, isLoading } = useFichesActionStatuts(
Object.fromEntries(
// Map les champs entre le type API et celui Backend
Object.entries({
Expand All @@ -52,10 +52,8 @@ const ModuleAvancementFichesAction = ({ module }: Props) => {
)
);

const statutFiches = data?.par_statut;

const fichesCount = statutFiches
? Object.values(statutFiches).reduce((acc, curr) => acc + curr.count, 0)
const fichesCount = countByStatut
? Object.values(countByStatut).reduce((acc, curr) => acc + curr.count, 0)
: 0;

if (!collectiviteId) {
Expand Down Expand Up @@ -99,8 +97,8 @@ const ModuleAvancementFichesAction = ({ module }: Props) => {
<Chart
donut={{
chart: {
data: statutFiches
? Object.entries(statutFiches)
data: countByStatut
? Object.entries(countByStatut)
.map(([statut, { count, valeur }]) => ({
id: statut,
value: count,
Expand Down Expand Up @@ -134,21 +132,25 @@ const ModuleAvancementFichesAction = ({ module }: Props) => {
)}
{display === 'row' && (
<div className="flex flex-wrap gap-2">
{statutFiches &&
Object.entries(statutFiches).map(([statut, { valeur }], index) =>
{countByStatut &&
Object.entries(countByStatut).map(([statut, { valeur }], index) =>
statut === 'Sans statut' ? (
<Card statut={valeur} count={statutFiches[statut].count} />
<Card
key={index}
statut={valeur}
count={countByStatut[statut].count}
/>
) : (
<Link
key={index}
href={makeFichesActionUrlWithParams(
collectiviteId,
filtres,
valeur
valeur as Statut
)}
className="bg-none rounded-xl hover:shadow"
>
<Card statut={valeur} count={statutFiches[statut].count} />
<Card statut={valeur} count={countByStatut[statut].count} />
</Link>
)
)}
Expand All @@ -161,7 +163,7 @@ const ModuleAvancementFichesAction = ({ module }: Props) => {
export default ModuleAvancementFichesAction;

type CardProps = {
statut: Statut;
statut: Statut | 'Sans statut';
count: number;
};

Expand Down
Original file line number Diff line number Diff line change
@@ -1,44 +1,15 @@
import { useQuery } from 'react-query';

import { useApiClient } from 'core-logic/api/useApiClient';
import { useCollectiviteId } from 'core-logic/hooks/params';
import { Statut } from '@tet/api/plan-actions';
import { RouterInput, trpc } from '@tet/api/utils/trpc/client';

export type GetFichesActionStatutsParams = {
cibles?: string;
partenaire_tag_ids?: string;
pilote_tag_ids?: string;
pilote_user_ids?: string;
service_tag_ids?: string;
plan_ids?: string;
modified_since?: string;
};

type GetIndicateursValeursResponse = {
par_statut: {
[key: string]: {
count: number;
valeur: Statut;
};
};
};
type CountByStatutFilter =
RouterInput['plans']['fiches']['countByStatut']['filter'];

/** Charge toutes les valeurs associées à un indicateur id (ou à un ou plusieurs identifiants d'indicateurs prédéfinis) */
export const useFichesActionStatuts = (
params: GetFichesActionStatutsParams
) => {
const collectivite_id = useCollectiviteId();
const api = useApiClient();

return useQuery(
['fiches_action_statuts', collectivite_id, params],
async () => {
if (!collectivite_id) return;
export const useFichesActionStatuts = (params: CountByStatutFilter) => {
const collectiviteId = useCollectiviteId()!;

return api.get<GetIndicateursValeursResponse>({
route: `/collectivites/${collectivite_id}/fiches-action/synthese`,
params: { collectivite_id, ...params },
});
}
);
return trpc.plans.fiches.countByStatut.useQuery({
collectiviteId,
filter: params,
});
};
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ import {
import {
clearAuthTokens,
getRootDomain,
getSession,
MaCollectivite,
restoreSessionFromAuthTokens,
setAuthTokens,
} from '@tet/api';
import { Tables } from '@tet/api/database.types';
Expand Down Expand Up @@ -227,24 +227,6 @@ const clearCrispUserData = () => {
}
};

export async function getSession() {
const { data, error } = await supabaseClient.auth.getSession();
if (data?.session) {
return data.session;
}
if (error) throw error;

// restaure une éventuelle session précédente
const ret = await restoreSessionFromAuthTokens(supabaseClient);
if (ret) {
const { data, error } = ret;
if (data?.session) {
return data.session;
}
if (error) throw error;
}
}

const useCurrentSession = () => {
const { data, error } = useQuery(['session'], async () => {
return getSession();
Expand All @@ -256,13 +238,3 @@ const useCurrentSession = () => {

return data;
};

export async function getAuthHeaders() {
const session = await getSession();
return session?.access_token
? {
authorization: `Bearer ${session.access_token}`,
apikey: `${ENV.supabase_anon_key}`,
}
: null;
}
40 changes: 2 additions & 38 deletions app.territoiresentransitions.react/src/core-logic/api/supabase.ts
Original file line number Diff line number Diff line change
@@ -1,42 +1,6 @@
import { createClient } from '@supabase/supabase-js';
import * as Sentry from '@sentry/nextjs';
import { ENV } from 'environmentVariables';
import { Database } from '@tet/api';
import { supabaseClient } from '@tet/api/utils/supabase-client';

/**
* Supabase client
*/
export const supabaseClient = createClient<Database>(
ENV.supabase_url!,
ENV.supabase_anon_key!,
{
global: {
// intercepte les requêtes pour traiter les erreurs globalement
fetch: (input, init) => {
return fetch(input as RequestInfo | URL, init).then((res) => {
// en cas d'erreur
if (res.status >= 400) {
res
// clone la réponse avant de la consommer
.clone()
.json()
// et log l'erreur dans sentry
.then(({ code, message }) => {
Sentry.captureException(
new Error(`Supabase error ${code}: ${message}`)
);
});
}
// renvoi la réponse originale
return res;
});
},
},
db: {
schema: 'public',
},
}
);
export { supabaseClient };

// options pour `useQuery` lorsqu'il s'agit de données qui ne changent pas trop
// souvent (définitions du référentiel etc.)
Expand Down
25 changes: 0 additions & 25 deletions app.territoiresentransitions.react/src/utils/trpc.ts

This file was deleted.

Loading
Loading