12 Commits

Author SHA1 Message Date
c0a0ea66a6 eslint now receives the glob itself 2022-08-08 14:48:59 +02:00
4b61b4a370 Added styled components
- also removed existing css
  - left the capabilities included
2022-08-08 14:08:16 +02:00
e733c4a9f6 Merge pull request #2 from Inforitnl/master
Sync back to private stuff
2022-07-26 11:18:17 +02:00
b9d3025163 Added react-oidc (use demo/demo)
Added an example of an authentication protected page (tenders)
Added an example with the built in proxy (to combat CORS) (tendersguru)
2022-07-26 11:15:36 +02:00
8496f5cfbe Moved examples into example directory
Moved routes to separate file
Used route constants
2022-07-26 10:32:11 +02:00
de1484e9a1 Merge branch 'Mastermindzh:master' into master 2022-07-25 12:44:35 +02:00
2728820b71 Merge branch 'Mastermindzh:master' into master 2022-07-25 11:22:28 +02:00
ca0f973d07 Merge branch 'Mastermindzh:master' into master 2022-07-25 11:20:50 +02:00
126c80c7c4 Merge pull request #2 from Inforitnl/update/from-upstream
Update/from upstream
2022-07-25 11:16:50 +02:00
3d5e41ec42 Merge branch 'master' of github.com:Mastermindzh/react-starter-kit into update/from-upstream 2022-07-25 11:15:48 +02:00
dc81451685 Merge branch 'Mastermindzh:master' into master 2022-07-19 12:22:54 +02:00
d41e9d3af4 forking outside of github instructions 2022-07-19 11:17:38 +02:00
42 changed files with 888 additions and 575 deletions

View File

@@ -2,5 +2,6 @@
. "$(dirname -- "$0")/_/husky.sh"
npm run lint-staged
npm run lint
npm run test-ci
npm run e2e-ci

View File

@@ -5,13 +5,16 @@
"deepmerge",
"flexbugs",
"Immer",
"Keycloak",
"languagedetector",
"luxon",
"oidc",
"pmmmwh",
"preinstall",
"reduxjs",
"SVGR",
"tailwindcss",
"tendersguru",
"testid",
"typeahead",
"uncompiled"

View File

@@ -4,7 +4,7 @@
"body": [
"import { FunctionComponent } from \"react\";",
"",
"type Props = {}",
"type Props = {};",
"",
"export const ${1:${TM_FILENAME_BASE}}: FunctionComponent<Props> = () => {",
" return <h1>${1:${TM_FILENAME_BASE}}</h1>;",
@@ -68,5 +68,27 @@
"",
"export default ${1:${TM_FILENAME_BASE}}Slice.reducer;"
]
},
"react-i18next useTranslate hook": {
"prefix": ["useTranslation", "translate", "i18-trans"],
"body": ["const [translate] = useTranslation();"]
},
"react-styled-component": {
"prefix": ["rsfc", "rsc", "react-styled-component"],
"body": [
"import { FunctionComponent } from \"react\";",
"import styled from \"styled-components\";",
"",
"type Props = { className?: string };",
"",
"const ${1:${TM_FILENAME_BASE}}: FunctionComponent<Props> = ({className}) => {",
" return <h1 className={className}>${1:${TM_FILENAME_BASE}}</h1>;",
"};",
"",
"const Styled${1:${TM_FILENAME_BASE}} = styled(${1:${TM_FILENAME_BASE}})``;",
"",
"export { Styled${1:${TM_FILENAME_BASE}} as ${1:${TM_FILENAME_BASE}} };",
""
]
}
}

View File

@@ -4,6 +4,28 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [0.6.1] - 2022-08-08
- eslint now receives the glob itself
## [0.6.0] - 2022-08-08
- Added styled components
- also removed existing css
- left the capabilities included
## [0.5.0] - 2022-06-26
- Added react-oidc (use demo/demo)
- Added an example of an authentication protected page (tenders)
- Added an example with the built in proxy (to combat CORS) (tendersguru)
## [0.4.1] - 2022-06-26
- Moved examples into example directory
- Moved routes to separate file
- Used route constants
## [0.4.0] - 2022-07-25
- Added the possibility to override partial configs during deployments

View File

@@ -17,6 +17,7 @@ Includes:
- [Getting started](#getting-started)
- [Project structure](#project-structure)
- ["Forking" outside of Github](#forking-outside-of-github)
- [Configuration](#configuration)
- [Using the `config.ts` file](#using-the-configts-file)
- [adding values](#adding-values)
@@ -56,6 +57,17 @@ Only the important files are shown
└── tsconfig.json
```
## "Forking" outside of Github
To use this base in other git software (not Github) you will have to manually manage the upstream.
Go into your existing repo and execute the following commands:
1. `git remote add upstream <clone-url>`
2. `git pull upstream master` # or other branchname
3. `git push`
Then, when you need to sync again you can repeat step 2 and 3
## Configuration
This starter kit comes with runtime configuration out-of-the-box.

928
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
{
"name": "react-starter-kit",
"version": "0.4.0",
"version": "0.6.1",
"description": "A modern, create-react-app-based, starter kit for React projects",
"keywords": [
"react",
@@ -30,14 +30,14 @@
"e2e": "cypress open -d --e2e",
"e2e-ci": "start-server-and-test start http://localhost:3000 cypress-run",
"postinstall": "husky install",
"lint": "GLOBIGNORE='src/types' && eslint src/**",
"lint": "eslint \"src/**\"",
"lint-staged": "lint-staged --relative",
"organize-package-json": "npx format-package -w && npx sort-package-json",
"pretty-quick": "pretty-quick --staged",
"start": "node scripts/start.js",
"test": "node scripts/test.js --verbose",
"test-ci": "node scripts/test.js --ci --coverage",
"test-live-coverage": " concurrently --kill-others \"npm run test-with-coverage\" \"npx http-server -c-1 coverage/lcov-report\"",
"test-live-coverage": "concurrently --kill-others \"npm run test-with-coverage\" \"npx http-server -c-1 coverage/lcov-report\"",
"test-with-coverage": "node scripts/test.js --coverage",
"test:prod": "npm run test-ci && npm run e2e-ci"
},
@@ -45,6 +45,7 @@
"*.{ts,js,jsx,tsx,css,scss,json,md}": "prettier --write"
},
"dependencies": {
"@axa-fr/react-oidc": "^6.0.0-beta10",
"@reduxjs/toolkit": "^1.8.3",
"deepmerge": "^4.2.2",
"i18next-http-backend": "^1.4.1",
@@ -55,7 +56,7 @@
"react-dom": "^18.2.0",
"react-redux": "^8.0.2",
"react-router-dom": "^6.3.0",
"tailwindcss": "^3.1.6"
"styled-components": "^5.3.5"
},
"devDependencies": {
"@babel/core": "^7.18.9",
@@ -70,6 +71,7 @@
"@types/node": "^18.6.1",
"@types/react": "^18.0.15",
"@types/react-dom": "^18.0.6",
"@types/styled-components": "^5.1.25",
"babel-jest": "^27.4.2",
"babel-loader": "^8.2.5",
"babel-plugin-named-asset-import": "^0.3.8",
@@ -95,6 +97,7 @@
"file-loader": "^6.2.0",
"fs-extra": "^10.1.0",
"html-webpack-plugin": "^5.5.0",
"http-proxy-middleware": "^2.0.6",
"husky": "^8.0.1",
"i18next": "^21.8.14",
"i18next-browser-languagedetector": "^6.1.4",
@@ -110,7 +113,7 @@
"mocha-junit-reporter": "^2.0.2",
"postcss": "^8.4.14",
"postcss-flexbugs-fixes": "^5.0.2",
"postcss-loader": "^6.2.1",
"postcss-loader": "^7.0.1",
"postcss-normalize": "^10.0.1",
"postcss-preset-env": "^7.7.2",
"prettier": "^2.7.1",

View File

@@ -1,6 +1,24 @@
const defaultConfig = {
version: "0.1.0",
name: "React-starter-kit",
// oidc: {
// url: "private_url",
// realm: "inforit",
// clientId: "react-base",
// scope: "openid profile email",
// redirectUri: "http://localhost:3000/authentication/callback",
// silentRedirectUri: "http://localhost:3000/authentication/silent-callback",
// serviceWorkerOnly: false,
// },
oidc: {
url: "https://sso.mastermindzh.tech/realms/public-tests",
realm: "public-tests",
clientId: "react-starter-kit",
scope: "openid profile email",
redirectUri: "http://localhost:3000/authentication/callback",
silentRedirectUri: "http://localhost:3000/authentication/silent-callback",
serviceWorkerOnly: false,
},
};
// ignore this :)

View File

@@ -10,7 +10,8 @@
"nav": {
"home": "home",
"about": "about",
"counter": "counter"
"counter": "counter",
"tenders": "tenders (with auth)"
},
"about": {
"title": "About"

View File

@@ -10,7 +10,8 @@
"nav": {
"home": "home",
"about": "over ons",
"counter": "teller"
"counter": "teller",
"tenders": "aanbestedingen (met auth)"
},
"about": {
"title": "Over ons"

View File

@@ -1,26 +1,13 @@
import { BrowserRouter, Route, Routes } from "react-router-dom";
import { AboutContainer } from "./features/about/About";
import { CounterContainer } from "./features/counter/Counter";
import { HomeContainer } from "./features/home/Home";
import { BrowserRouter } from "react-router-dom";
import { Navbar } from "./infrastructure/navbar/Navbar";
import { AppRoutes } from "./Routes";
function App() {
return (
<BrowserRouter>
<div className="App">
<Navbar />
<Routes>
<Route path="/" element={<HomeContainer />} />
<Route path="/about" element={<AboutContainer />} />
<Route path="/counter" element={<CounterContainer />} />
{/* <Route index element={<Home />} /> */}
{/* <Route path="teams" element={<Teams />}>
<Route path=":teamId" element={<Team />} />
<Route path="new" element={<NewTeamForm />} />
<Route index element={<LeagueStandings />} />
</Route> */}
{/* </Route> */}
</Routes>
<AppRoutes />
</div>
</BrowserRouter>
);

42
src/Routes.tsx Normal file
View File

@@ -0,0 +1,42 @@
import { OidcSecure } from "@axa-fr/react-oidc";
import { FunctionComponent } from "react";
import { Route, Routes } from "react-router-dom";
import { AboutContainer } from "./features/about/About";
import { CounterContainer } from "./features/examples/counter/Counter";
import { Tenders } from "./features/examples/tenders/Tenders";
import { HomeContainer } from "./features/home/Home";
type Props = {};
export const ROUTE_KEYS = {
home: "",
about: "about",
counter: "counter",
tenders: "tenders",
};
export const AppRoutes: FunctionComponent<Props> = () => {
const { home, about, counter, tenders } = ROUTE_KEYS;
return (
<Routes>
<Route path={home} element={<HomeContainer />} />
<Route path={about} element={<AboutContainer />} />
<Route path={counter} element={<CounterContainer />} />
{/* a route with authentication */}
<Route
path={tenders}
element={
<OidcSecure>
<Tenders />
</OidcSecure>
}
/>
{/* <Route index element={<Home />} /> */}
{/* <Route path="teams" element={<Teams />}>
<Route path=":teamId" element={<Team />} />
<Route path="new" element={<NewTeamForm />} />
<Route index element={<LeagueStandings />} />
</Route> */}
{/* </Route> */}
</Routes>
);
};

View File

@@ -1,5 +1,5 @@
import { configureStore, ThunkAction, Action } from "@reduxjs/toolkit";
import counterReducer from "../features/counter/state/counterSlice";
import counterReducer from "../features/examples/counter/state/counterSlice";
export const store = configureStore({
reducer: {

View File

@@ -2,7 +2,14 @@ import { FunctionComponent, ReactNode } from "react";
import { I18nextProvider, useTranslation } from "react-i18next";
import i18n from "./i18n";
type Props = { children?: ReactNode; keysOnly?: boolean };
type Props = {
children?: ReactNode;
/**
* Whether to show the translation keys instead of translated text
* Can be useful to test languages that don't have full translations
*/
keysOnly?: boolean;
};
const ProvidedComponent: FunctionComponent<Props> = ({ children, keysOnly }) => {
const [_translate, i18nSettings] = useTranslation();

View File

@@ -1,4 +0,0 @@
// A mock function to mimic making an async request for data
export function fetchCount(amount = 1) {
return new Promise<{ data: number }>((resolve) => setTimeout(() => resolve({ data: amount }), 500));
}

View File

@@ -18,7 +18,7 @@
padding-left: 16px;
padding-right: 16px;
margin-top: 2px;
font-family: 'Courier New', Courier, monospace;
font-family: "Courier New", Courier, monospace;
}
.button {
@@ -60,7 +60,7 @@
}
.asyncButton:after {
content: '';
content: "";
background-color: rgba(112, 76, 182, 0.15);
display: block;
position: absolute;

View File

@@ -1,7 +1,7 @@
import { useState } from "react";
import { useTranslation } from "react-i18next";
import { useAppDispatch, useAppSelector } from "../../app/hooks";
import { useAppDispatch, useAppSelector } from "../../../app/hooks";
import styles from "./Counter.module.css";
import { incrementAsync } from "./state/actions/incrementAsync";
import {

View File

@@ -0,0 +1,6 @@
// A mock function to mimic making an async request for data
export function fetchCount(amount = 1) {
return new Promise<{ data: number }>((resolve) =>
setTimeout(() => resolve({ data: amount }), 500),
);
}

View File

@@ -1,8 +1,4 @@
import counterReducer, {
increment,
decrement,
incrementByAmount,
} from "./counterSlice";
import counterReducer, { increment, decrement, incrementByAmount } from "./counterSlice";
import { CounterState } from "../models/CounterState";
describe("counter reducer", () => {

View File

@@ -1,5 +1,5 @@
import { createSlice, PayloadAction } from "@reduxjs/toolkit";
import { AppThunk, RootState } from "../../../app/store";
import { AppThunk, RootState } from "../../../../app/store";
import { CounterState } from "../models/CounterState";
import { incrementAsync } from "./actions/incrementAsync";

View File

@@ -0,0 +1,33 @@
import { useOidcAccessToken } from "@axa-fr/react-oidc";
import { FunctionComponent, useEffect, useState } from "react";
import { useTranslation } from "react-i18next";
type Props = {};
export const Tenders: FunctionComponent<Props> = () => {
const [tenders, setTenders] = useState(null);
const [translate] = useTranslation();
const { accessToken } = useOidcAccessToken();
useEffect(() => {
// this uses the CORS proxy in our webpack setup
// tendersguru is mapped to "https://tenders.guru" in setupProxy.js
// it will strip the tendersguru part, so the full url will be: https://tenders.guru/api/ro/tenders
fetch("tendersguru/api/ro/tenders", {
// fetch's way of adding headers. Not required to access the api... but :shrug:
headers: new Headers({
Authorization: `Bearer ${accessToken}`,
}),
})
.then((response) => response.json())
.then((data) => {
setTenders(data);
});
}, [accessToken]);
return (
<>
<h1>{translate("nav.tenders")}</h1>
{tenders ? <pre>{JSON.stringify(tenders, null, 2)}</pre> : <h2>loading...</h2>}
</>
);
};

View File

@@ -8,19 +8,39 @@ export const HomeContainer: FunctionComponent<Props> = () => {
<p>This is the react base app :)</p>
<span>
<span>Learn </span>
<a className="App-link" href="https://reactjs.org/" target="_blank" rel="noopener noreferrer">
<a
className="App-link"
href="https://reactjs.org/"
target="_blank"
rel="noopener noreferrer"
>
React
</a>
<span>, </span>
<a className="App-link" href="https://redux.js.org/" target="_blank" rel="noopener noreferrer">
<a
className="App-link"
href="https://redux.js.org/"
target="_blank"
rel="noopener noreferrer"
>
Redux
</a>
<span>, </span>
<a className="App-link" href="https://redux-toolkit.js.org/" target="_blank" rel="noopener noreferrer">
<a
className="App-link"
href="https://redux-toolkit.js.org/"
target="_blank"
rel="noopener noreferrer"
>
Redux Toolkit
</a>
,<span> and </span>
<a className="App-link" href="https://react-redux.js.org/" target="_blank" rel="noopener noreferrer">
<a
className="App-link"
href="https://react-redux.js.org/"
target="_blank"
rel="noopener noreferrer"
>
React Redux
</a>
</span>

View File

@@ -1,11 +0,0 @@
body {
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans",
"Droid Sans", "Helvetica Neue", sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
code {
font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New", monospace;
}

View File

@@ -1,22 +1,40 @@
import React from "react";
import { createRoot } from "react-dom/client";
import { Provider } from "react-redux";
import { createGlobalStyle } from "styled-components";
import App from "./App";
import { store } from "./app/store";
import "./index.css";
import "./infrastructure/i18n/init";
import { OidcProvider } from "./infrastructure/sso/OidcProvider";
import { Loader } from "./infrastructure/wrappers/WithPageSuspense";
import reportWebVitals from "./reportWebVitals";
const container = document.getElementById("root")!;
const root = createRoot(container);
const GlobalStyle = createGlobalStyle`
body {
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans",
"Droid Sans", "Helvetica Neue", sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
code {
font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New", monospace;
}
`;
root.render(
<React.StrictMode>
<GlobalStyle />
<Provider store={store}>
<Loader>
<App />
</Loader>
<OidcProvider>
<Loader>
<App />
</Loader>
</OidcProvider>
</Provider>
</React.StrictMode>,
);

View File

@@ -1,4 +1,11 @@
import { OIDCConfig } from "../sso/models/OIDCConfig";
export interface RunTimeConfig {
version: number;
name: string;
/**
* Settings for the OIDC connection
*/
oidc: OIDCConfig;
}

View File

@@ -1,4 +1,5 @@
import deepmerge from "deepmerge";
import { RunTimeConfig } from "./RunTimeConfig";
/**
* gets and merges both the regular config and the override config from the window
@@ -12,4 +13,4 @@ export const mergeConfigs = () => {
mergeConfigs();
export const Config = window.mergedConfig;
export const Config: RunTimeConfig = window.mergedConfig;

View File

@@ -1,3 +0,0 @@
nav a {
padding-right: 10px;
}

View File

@@ -1,18 +1,25 @@
import { render, screen } from "@testing-library/react";
import { render, screen, waitFor } from "@testing-library/react";
import { WithTestTranslations } from "../../app/tests/mocks/i18n/WithTestTranslations";
import { OidcProvider } from "../sso/OidcProvider";
import { WithRouter } from "../wrappers/WithRouter";
import { Navbar } from "./Navbar";
describe("Navbar container", () => {
it.only("renders a navigation section identified by the nav test-id", () => {
it.only("renders a navigation section identified by the nav test-id", async () => {
render(
<WithTestTranslations>
<WithRouter>
<Navbar />
</WithRouter>
{/* for simple tests where we don't need auth we don't actually have to mock responses */}
<OidcProvider>
<WithRouter>
<Navbar />
</WithRouter>
</OidcProvider>
</WithTestTranslations>,
);
expect(screen.getAllByTestId("nav")?.length).toBeGreaterThan(0);
// because of the extra loaders we wait for a result just to be sure
// see: https://testing-library.com/docs/guide-disappearance/
await waitFor(() => {
expect(screen.getAllByTestId("nav")?.length).toBeGreaterThan(0);
});
});
});

View File

@@ -1,38 +1,61 @@
import { useOidc, useOidcAccessToken } from "@axa-fr/react-oidc";
import { DateTime } from "luxon";
import { FunctionComponent } from "react";
import { Trans, useTranslation } from "react-i18next";
import { Link } from "react-router-dom";
import styled from "styled-components";
import { ROUTE_KEYS } from "../../Routes";
import { Config } from "../config";
import "./Navbar.css";
type Props = {};
type Props = { className?: string };
export const Navbar: FunctionComponent<Props> = () => {
const Navbar: FunctionComponent<Props> = ({ className }) => {
const [translate, i18n] = useTranslation();
const { login, logout, isAuthenticated } = useOidc();
const { accessTokenPayload } = useOidcAccessToken();
const { home, about, counter } = ROUTE_KEYS;
return (
<>
<div className={className}>
<h1>{translate("navBar.intro")}</h1>
<p>
{/* trans can also be used to translate */}
{Config.name} <Trans i18nKey="navBar.version">version:</Trans>
{JSON.stringify(Config.version)}
<button
onClick={() => {
isAuthenticated ? logout() : login("/");
}}
>
{isAuthenticated ? `logout (${accessTokenPayload.email})` : "login"}
</button>
</p>
{/* This translation uses a formatter in the translation files */}
<p>{translate("navBar.currentDate", { date: DateTime.now().toJSDate() })}</p>
<nav data-testid="nav">
<Link to="/" data-testid="nav.home">
<Link to={home} data-testid="nav.home">
{translate("nav.home")}
</Link>
<Link to="/about" data-testid="nav.about">
<Link to={about} data-testid="nav.about">
{translate("nav.about")}
</Link>
<Link to="/counter" data-testid="nav.counter">
<Link to={counter} data-testid="nav.counter">
{translate("nav.counter")}
</Link>
<Link to="/tenders" data-testid="nav.tenders">
{translate("nav.tenders")}
</Link>
<button onClick={() => i18n.changeLanguage("en")}>en</button>
<button onClick={() => i18n.changeLanguage("nl")}>nl</button>
<hr />
</nav>
</>
</div>
);
};
const StyledNavBar = styled(Navbar)`
nav a {
padding-right: 10px;
}
`;
export { StyledNavBar as Navbar };

View File

@@ -0,0 +1,12 @@
import { FunctionComponent } from "react";
import styled from "styled-components";
type Props = {};
const TestComponent: FunctionComponent<Props> = () => {
return <h1>TestComponent</h1>;
};
const StyledTestComponent = styled(TestComponent)``;
export { StyledTestComponent as TestComponent };

View File

@@ -0,0 +1,14 @@
import { OidcConfiguration } from "@axa-fr/react-oidc/dist/vanilla/oidc";
import { Config } from "../config";
const { clientId, redirectUri, silentRedirectUri, scope, url } = Config.oidc;
/* eslint-disable camelcase */
export const SSOConfiguration: OidcConfiguration = {
client_id: clientId,
redirect_uri: redirectUri,
silent_redirect_uri: silentRedirectUri,
scope,
authority: url,
service_worker_only: false,
};

View File

@@ -0,0 +1,28 @@
import { OidcProvider as ReactOidcProvider } from "@axa-fr/react-oidc";
import { FunctionComponent, ReactNode } from "react";
import { AppLoader } from "../loader/appLoader";
import { SSOConfiguration } from "./Configuration";
import { Authenticating } from "./overrides/Authenticating";
import { AuthenticatingError } from "./overrides/AuthenticatingError";
import { CallBackSuccess } from "./overrides/CallBackSuccess";
import { ServiceWorkerNotSupported } from "./overrides/ServiceWorkerNotSupported";
import { SessionLost } from "./overrides/SessionLost";
type Props = { children?: ReactNode; [x: string]: any };
export const OidcProvider: FunctionComponent<Props> = ({ children, ...rest }) => {
return (
<ReactOidcProvider
loadingComponent={AppLoader}
authenticatingErrorComponent={AuthenticatingError}
authenticatingComponent={Authenticating}
sessionLostComponent={SessionLost}
serviceWorkerNotSupportedComponent={ServiceWorkerNotSupported}
callbackSuccessComponent={CallBackSuccess}
configuration={SSOConfiguration}
{...rest}
>
{children}
</ReactOidcProvider>
);
};

View File

@@ -0,0 +1,31 @@
export interface OIDCConfig {
/**
* Authority URL
*/
url: string;
/**
* Realm to authenticate against
*/
realm: string;
/**
* Id of this client
*/
clientId: string;
/**
* Scope(s) that you want to request
*/
scope: string;
/**
* URI to redirect to after successful login
*/
redirectUri: string;
/**
* redirect uri for the silent refresh
*/
silentRedirectUri: string;
}

View File

@@ -0,0 +1,3 @@
export interface SSOResult {
configurationName: string;
}

View File

@@ -0,0 +1,9 @@
import { FunctionComponent } from "react";
import { SSOResult } from "../models/SSOResult";
export const Authenticating: FunctionComponent<SSOResult> = ({ configurationName }) => (
<>
<h1>Authentication in progress for {configurationName}</h1>
<p>You will be redirected to the login page.</p>
</>
);

View File

@@ -0,0 +1,9 @@
import { FunctionComponent } from "react";
import { SSOResult } from "../models/SSOResult";
export const AuthenticatingError: FunctionComponent<SSOResult> = ({ configurationName }) => (
<>
<h1>Error for {configurationName}</h1>
<p>An error occurred during authentication.</p>
</>
);

View File

@@ -0,0 +1,9 @@
import { FunctionComponent } from "react";
import { SSOResult } from "../models/SSOResult";
export const CallBackSuccess: FunctionComponent<SSOResult> = ({ configurationName }) => (
<>
<h1>Authentication complete for {configurationName}</h1>
<p>You will be redirected...</p>
</>
);

View File

@@ -0,0 +1,9 @@
import { FunctionComponent } from "react";
import { SSOResult } from "../models/SSOResult";
export const ServiceWorkerNotSupported: FunctionComponent<SSOResult> = ({ configurationName }) => (
<>
<h1>Unable to authenticate on this browser for {configurationName}</h1>
<p>Your browser is not configured to support Service Workers.</p>
</>
);

View File

@@ -0,0 +1,17 @@
import { useOidc } from "@axa-fr/react-oidc";
import { FunctionComponent } from "react";
import { SSOResult } from "../models/SSOResult";
export const SessionLost: FunctionComponent<SSOResult> = ({ configurationName }) => {
const { login } = useOidc(configurationName);
return (
<>
<h1>Session timed out for {configurationName}</h1>
<p>Your session has expired. Please re-authenticate.</p>
<button type="button" onClick={() => login("/")}>
Login
</button>
</>
);
};

28
src/setupProxy.js Normal file
View File

@@ -0,0 +1,28 @@
const { createProxyMiddleware } = require("http-proxy-middleware");
/**
* Create a simple proxy that automatically removes the prefix endpoint
* @param {*} app app to configure proxy on
* @param {*} endpoint endpoint you want to use for the proxy
* @param {*} target proxy target
*/
const createSimpleProxy = (app, endpoint, target) => {
app.use(
endpoint,
createProxyMiddleware({
target,
changeOrigin: true,
pathRewrite: {
[`^${endpoint}`]: "",
},
}),
);
};
/**
* Actual proxy configuration
* @param {*} app app to configure proxy on
*/
module.exports = function (app) {
createSimpleProxy(app, "/tendersguru", "https://tenders.guru");
};