Skip to content

Commit

Permalink
Add base path support
Browse files Browse the repository at this point in the history
  • Loading branch information
floo51 committed Mar 24, 2024
1 parent 62de9e7 commit 5b62b30
Show file tree
Hide file tree
Showing 13 changed files with 166 additions and 128 deletions.
8 changes: 7 additions & 1 deletion .deployment/DEPLOYMENT.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,12 +86,18 @@ Address where the app is hosted.

Example: `https://chuto.talm.fr/collector`

#### BASE_PATH
#### NEXT_PUBLIC_BASE_PATH

Subpath where the app is hosted, leave blank if it's hosted on root domain.

Example: `/collector`

#### NEXT_PUBLIC_API_URL

Subpath where the api is hosted, leave blank if it's hosted on root domain.

Example: `/collector/api`

#### MAIL_HOST

Host for the SMTP server.
Expand Down
2 changes: 2 additions & 0 deletions .env
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,6 @@ MAIL_URL=smtp://localhost:1025
MAIL_FROM=xxxxxxxxxxxxxx@xxxxxxxxx

NEXT_PUBLIC_CALCULATOR_URL=http://localhost:4001
NEXT_PUBLIC_BASE_PATH=/scrrap-lab
NEXT_PUBLIC_API_URL=/scrrap-lab/api
NEXT_PUBLIC_CALCULATOR_PROJECT_TYPE=activity
1 change: 1 addition & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
ENV NEXT_TELEMETRY_DISABLED 1
ENV NEXT_PUBLIC_BASE_PATH /scrrap-lab
RUN yarn add sharp --ignore-engines
RUN yarn build

Expand Down
4 changes: 2 additions & 2 deletions next.config.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
/** @type {import('next').NextConfig} */
const nextConfig = {
output: "standalone",
basePath: process.env.BASE_PATH || "",
assetPrefix: process.env.BASE_PATH || "",
basePath: process.env.NEXT_PUBLIC_BASE_PATH || "",
assetPrefix: process.env.NEXT_PUBLIC_BASE_PATH || "",
experimental: {
instrumentationHook: true,
},
Expand Down
7 changes: 4 additions & 3 deletions src/app/admin/Admin.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import roles from "./roles";
import theme from "./theme";
import transports from "./transports";
import users from "./users";
import { env } from "next-runtime-env";

frenchMessages.ra.auth.username = "Adresse email";

Expand All @@ -34,12 +35,12 @@ const i18nProvider = polyglotI18nProvider(() => frenchMessages);
const AdminApp = () => {
return (
<LocalizationProvider dateAdapter={AdapterDayjs}>
<BrowserRouter>
<BrowserRouter basename={env("NEXT_PUBLIC_BASE_PATH")}>
<Admin
i18nProvider={i18nProvider}
loginPage={LoginPage}
authProvider={authProvider}
dataProvider={dataProvider}
authProvider={authProvider(env("NEXT_PUBLIC_API_URL") || "/api")}
dataProvider={dataProvider(env("NEXT_PUBLIC_API_URL") || "/api")}
layout={AppLayout}
title="SCRRAP-LAB - Administration"
disableTelemetry
Expand Down
105 changes: 54 additions & 51 deletions src/app/admin/authProvider.ts
Original file line number Diff line number Diff line change
@@ -1,58 +1,61 @@
import { AuthProvider } from "react-admin";

const AUTH_API_URL = "/api/authentication";
export const PREFIX = "scrapp-lab";

const authProvider: AuthProvider = {
login: async ({ username, password }) => {
const request = new Request(`${AUTH_API_URL}/login`, {
method: "POST",
body: JSON.stringify({ email: username, password }),
credentials: "include",
headers: new Headers({ "Content-Type": "application/json" }),
});
const response = await fetch(request);
if (response.status < 200 || response.status >= 300) {
throw new Error("Utilisateur ou mot de passe incorrect");
}
const auth = await response.json();
localStorage.setItem(`${PREFIX}-auth`, JSON.stringify(auth));
},
logout: () => {
localStorage.removeItem(`${PREFIX}-auth`);
return Promise.resolve();
},
checkAuth: () => {
return localStorage.getItem(`${PREFIX}-auth`)
? Promise.resolve()
: Promise.reject();
},
checkError: (error) => {
if (error?.status === 401) {
const authProviderFactory: (endpoint: string | undefined) => AuthProvider = (
endpoint: string | undefined
) => {
const AUTH_API_URL = `${endpoint || "/api"}/authentication`;
return {
login: async ({ username, password }) => {
const request = new Request(`${AUTH_API_URL}/login`, {
method: "POST",
body: JSON.stringify({ email: username, password }),
credentials: "include",
headers: new Headers({ "Content-Type": "application/json" }),
});
const response = await fetch(request);
if (response.status < 200 || response.status >= 300) {
throw new Error("Utilisateur ou mot de passe incorrect");
}
const auth = await response.json();
localStorage.setItem(`${PREFIX}-auth`, JSON.stringify(auth));
},
logout: () => {
localStorage.removeItem(`${PREFIX}-auth`);
return Promise.reject();
}
return Promise.resolve();
},
getIdentity: async () => {
const auth = JSON.parse(localStorage.getItem(`${PREFIX}-auth`) || "null");
if (!auth) {
return Promise.reject({
status: 401,
return Promise.resolve();
},
checkAuth: () => {
return localStorage.getItem(`${PREFIX}-auth`)
? Promise.resolve()
: Promise.reject();
},
checkError: (error) => {
if (error?.status === 401) {
localStorage.removeItem(`${PREFIX}-auth`);
return Promise.reject();
}
return Promise.resolve();
},
getIdentity: async () => {
const auth = JSON.parse(localStorage.getItem(`${PREFIX}-auth`) || "null");
if (!auth) {
return Promise.reject({
status: 401,
});
}
return Promise.resolve({
...auth,
fullName: `${auth.firstName} ${auth.lastName}`,
});
}
return Promise.resolve({
...auth,
fullName: `${auth.firstName} ${auth.lastName}`,
});
},
getPermissions: () => {
const auth = JSON.parse(localStorage.getItem(`${PREFIX}-auth`) || "null");
if (!auth) {
return Promise.resolve([]);
}
return Promise.resolve(auth.permissions);
},
},
getPermissions: () => {
const auth = JSON.parse(localStorage.getItem(`${PREFIX}-auth`) || "null");
if (!auth) {
return Promise.resolve([]);
}
return Promise.resolve(auth.permissions);
},
};
};

export default authProvider;
export default authProviderFactory;
24 changes: 14 additions & 10 deletions src/app/admin/authentication/Activate.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { Link, useLogin, useNotify } from "react-admin";
import PasswordStrengthBar from "react-password-strength-bar";
import { useParams } from "react-router-dom";
import Root from "./Root";
import { env } from "next-runtime-env";

interface ResetProps extends HtmlHTMLAttributes<HTMLDivElement> {
className?: string;
Expand All @@ -40,16 +41,19 @@ const Reset = (props: ResetProps) => {
}
setLoading(true);
try {
const response = await fetch("/api/authentication/reset", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
token,
password: event.target.password.value,
}),
});
const response = await fetch(
`${env("NEXT_PUBLIC_API_URL") || "/api"}/authentication/reset`,
{
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
token,
password: event.target.password.value,
}),
}
);

if (response.ok) {
const data = await response.json();
Expand Down
22 changes: 13 additions & 9 deletions src/app/admin/authentication/Recover.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
import { HtmlHTMLAttributes, useState } from "react";
import { Link, useNotify } from "react-admin";
import Root from "./Root";
import { env } from "next-runtime-env";

interface ResetProps extends HtmlHTMLAttributes<HTMLDivElement> {
className?: string;
Expand All @@ -28,15 +29,18 @@ const Reset = (props: ResetProps) => {
event.preventDefault();
setLoading(true);
try {
const response = await fetch("/api/authentication/recover", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
email: event.target.elements.email.value,
}),
});
const response = await fetch(
`${env("NEXT_PUBLIC_API_URL") || "/api"}/authentication/recover`,
{
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
email: event.target.elements.email.value,
}),
}
);

if (response.ok) {
notify("Un email a été envoyé à l'adresse indiquée.", {
Expand Down
24 changes: 14 additions & 10 deletions src/app/admin/authentication/Reset.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { Link, useLogin, useNotify } from "react-admin";
import Root from "./Root";
import { useParams } from "react-router-dom";
import PasswordStrengthBar from "react-password-strength-bar";
import { env } from "next-runtime-env";

interface ResetProps extends HtmlHTMLAttributes<HTMLDivElement> {
className?: string;
Expand All @@ -40,16 +41,19 @@ const Reset = (props: ResetProps) => {
}
setLoading(true);
try {
const response = await fetch("/api/authentication/reset", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
token,
password: event.target.password.value,
}),
});
const response = await fetch(
`${env("NEXT_PUBLIC_API_URL") || "/api"}/authentication/reset`,
{
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
token,
password: event.target.password.value,
}),
}
);

if (response.ok) {
const data = await response.json();
Expand Down
66 changes: 36 additions & 30 deletions src/app/admin/dataProvider.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import jsonServerProvider from "ra-data-json-server";
import {
CreateParams,
DataProvider,
DataProvider as BaseDataProvider,
UpdateParams,
fetchUtils,
} from "react-admin";
import httpClient from "./httpClient";

export const endpoint = "/api";

const baseDataProvider = jsonServerProvider(endpoint, httpClient);
export interface DataProvider extends BaseDataProvider {
endpoint: string | undefined;
}

type PostParams = {
id: string;
Expand Down Expand Up @@ -70,33 +70,39 @@ const createOffcutsPostData = (
return formData;
};

export const dataProvider: DataProvider = {
...baseDataProvider,
create: (resource, params) => {
if (resource === "offcuts") {
const formData = createOffcutsPostData(params);
return httpClient(`${endpoint}/${resource}`, {
method: "POST",
body: formData,
headers: new Headers({}),
}).then(({ json }) => ({ data: json }));
}
export const dataProviderFactory: (
endpoint: string | undefined
) => DataProvider = (endpoint: string | undefined) => {
const baseDataProvider = jsonServerProvider(endpoint, httpClient);
return {
...baseDataProvider,
endpoint,
create: (resource, params) => {
if (resource === "offcuts") {
const formData = createOffcutsPostData(params);
return httpClient(`${endpoint}/${resource}`, {
method: "POST",
body: formData,
headers: new Headers({}),
}).then(({ json }) => ({ data: json }));
}

return baseDataProvider.create(resource, params);
},
update: (resource, params) => {
if (resource === "offcuts") {
const formData = createOffcutsPostData(params);
formData.append("id", params.id);
return httpClient(`${endpoint}/${resource}/${params.id}`, {
method: "PUT",
body: formData,
headers: new Headers({}),
}).then(({ json }) => ({ data: json }));
}
return baseDataProvider.create(resource, params);
},
update: (resource, params) => {
if (resource === "offcuts") {
const formData = createOffcutsPostData(params);
formData.append("id", params.id);
return httpClient(`${endpoint}/${resource}/${params.id}`, {
method: "PUT",
body: formData,
headers: new Headers({}),
}).then(({ json }) => ({ data: json }));
}

return baseDataProvider.update(resource, params);
},
return baseDataProvider.update(resource, params);
},
};
};

export default dataProvider;
export default dataProviderFactory;
Loading

0 comments on commit 5b62b30

Please sign in to comment.