diff --git a/package.json b/package.json
index 7a11bd6..052a87b 100644
--- a/package.json
+++ b/package.json
@@ -1,8 +1,9 @@
{
"name": "sonor",
- "version": "0.5.33",
+ "version": "0.5.35",
"private": true,
"dependencies": {
+ "@tanstack/react-query": "4.0.5",
"@testing-library/jest-dom": "^4.2.4",
"async-wait-until": "^2.0.5",
"awesome-debounce-promise": "^2.1.0",
@@ -12,8 +13,8 @@
"cypress-multi-reporters": "^1.2.4",
"font-awesome": "^4.7.0",
"history": "^5.0.0",
- "keycloak-js": "4.0.0-beta.2",
"mocha-junit-reporter": "^1.23.3",
+ "oidc-spa": "4.5.1",
"prop-types": "^15.7.2",
"react": "^16.13.1",
"react-bootstrap": "^1.0.1",
diff --git a/public/configuration.json b/public/configuration.json
index 2274d68..916a5f6 100644
--- a/public/configuration.json
+++ b/public/configuration.json
@@ -2,8 +2,9 @@
"PEARL_JAM_URL": "http://localhost:7777",
"QUEEN_URL_BACK_END": "http://localhost:7777",
"QUEEN_URL_FRONT_END": "http://localhost:7777",
-
+ "ISSUER_URI": "http://localhost:7777",
+ "OIDC_CLIENT_ID": "clientId",
"AUTHENTICATION_MODE": "anonymous",
- "_AUTHENTICATION_MODE_COMMENT_": "Use 'keycloak' or 'anonymous'"
+ "_AUTHENTICATION_MODE_COMMENT_": "Use 'oidc' or 'anonymous'"
}
diff --git a/public/silent-sso.html b/public/silent-sso.html
new file mode 100644
index 0000000..d5759a1
--- /dev/null
+++ b/public/silent-sso.html
@@ -0,0 +1,7 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Authentication/useAuth.js b/src/Authentication/useAuth.js
new file mode 100644
index 0000000..2dd0975
--- /dev/null
+++ b/src/Authentication/useAuth.js
@@ -0,0 +1,51 @@
+import { useEffect } from "react";
+import { createReactOidc } from "oidc-spa/react";
+
+/**
+ * By default, without initialization we use a mock as a return of "useOidc"
+ *
+ * This object will be used for testing purpose to simulate authentication status
+ */
+const mockOidc = { login: () => {}, isUserLoggedIn: false, oidcTokens: {} }
+// Global method that will be replaced when oidc is initialized
+let useOidc = ({assertUserLoggedIn}) => mockOidc;
+
+/**
+ * Helper method used for tests, set a fake Oidc authentication state
+ */
+export const mockOidcForUser = () => {
+ window.localStorage.setItem("AUTHENTICATION_MODE", "oidc")
+ mockOidc.isUserLoggedIn = true
+ mockOidc.oidcTokens = {accessToken: '12031203'}
+}
+export const mockOidcFailed = () => {
+ mockOidc.isUserLoggedIn = false
+ mockOidc.oidcTokens = {}
+}
+
+/**
+ * Initialize oidc
+ */
+export function initializeOidc (config) {
+ const oidc = createReactOidc(config)
+ useOidc = oidc.useOidc
+ return oidc;
+}
+
+/**
+ * Retrieve authentication status based of Oidc
+ */
+export function useIsAuthenticated() {
+ const { login, isUserLoggedIn, oidcTokens, renewTokens} = useOidc({ assertUserLoggedIn: false });
+
+ useEffect(() => {
+ if (!login) {
+ return;
+ }
+ login({
+ doesCurrentHrefRequiresAuth: true,
+ });
+ }, [login]);
+
+ return { isAuthenticated: isUserLoggedIn, tokens: oidcTokens, renewTokens };
+}
diff --git a/src/components/App/App.jsx b/src/components/App/App.jsx
index 6ee0550..48659a2 100644
--- a/src/components/App/App.jsx
+++ b/src/components/App/App.jsx
@@ -1,87 +1,88 @@
-import React from 'react';
-import Keycloak from 'keycloak-js';
-import View from '../View/View';
-import DataFormatter from '../../utils/DataFormatter';
-import { KEYCLOAK, ANONYMOUS } from '../../utils/constants.json';
-import initConfiguration from '../../initConfiguration';
-import D from '../../i18n';
+import React, { useEffect, useState, useRef } from "react";
+import { useIsAuthenticated } from "../../Authentication/useAuth";
+import D from "../../i18n";
+import View from "../View/View";
+import DataFormatter from "../../utils/DataFormatter";
+import { OIDC, ANONYMOUS } from "../../utils/constants.json";
-class App extends React.Component {
- constructor(props) {
- super(props);
- this.state = {
- keycloak: null,
- authenticated: false,
- contactFailed: false,
- initialisationFailed: false,
- data: null,
+export const App = () => {
+ const [authenticated, setAuthenticated] = useState(false);
+ const [contactFailed, setContactFailed] = useState(false);
+ const [data, setData] = useState(null);
+ const timeoutIdRef = useRef(null);
+
+ const { tokens, renewTokens } = useIsAuthenticated();
+
+ useEffect(() => {
+ const resetInactivityTimeout = () => {
+ if (timeoutIdRef.current) {
+ clearTimeout(timeoutIdRef.current);
+ }
+ timeoutIdRef.current = setTimeout(renewTokens, 5 * 60 * 1000);
};
- }
- async componentDidMount() {
- try {
- await initConfiguration();
- } catch (e) {
- this.setState({ initialisationFailed: true });
- }
- if (window.localStorage.getItem('AUTHENTICATION_MODE') === ANONYMOUS) {
+ const events = [
+ "mousemove",
+ "mousedown",
+ "keypress",
+ "touchstart",
+ "click",
+ ];
+
+ events.forEach((event) => {
+ window.addEventListener(event, resetInactivityTimeout);
+ });
+
+ resetInactivityTimeout();
+
+ return () => {
+ if (timeoutIdRef.current) {
+ clearTimeout(timeoutIdRef.current);
+ }
+ events.forEach((event) => {
+ window.removeEventListener(event, resetInactivityTimeout);
+ });
+ };
+ }, [renewTokens]);
+
+ useEffect(() => {
+ if (window.localStorage.getItem("AUTHENTICATION_MODE") === ANONYMOUS) {
const dataRetreiver = new DataFormatter();
dataRetreiver.getUserInfo((data) => {
if (data.error) {
- this.setState({ contactFailed: true });
+ setContactFailed(true);
} else {
- this.setState({ authenticated: true, data });
+ setAuthenticated(true);
+ setData(data);
}
});
- } else if (window.localStorage.getItem('AUTHENTICATION_MODE') === KEYCLOAK) {
- const keycloak = Keycloak('/keycloak.json');
- keycloak.init({ onLoad: 'login-required', checkLoginIframe: false }).then((authenticated) => {
- const dataRetreiver = new DataFormatter(keycloak);
- dataRetreiver.getUserInfo((data) => {
- this.setState({ keycloak, authenticated, data });
- });
- // Update 20 seconds before expiracy
- const updateInterval = (keycloak.tokenParsed.exp + keycloak.timeSkew)
- * 1000
- - new Date().getTime()
- - 20000;
- setInterval(() => {
- keycloak.updateToken(100).error(() => {
- throw new Error('Failed to refresh token');
- });
- }, updateInterval);
+ } else if (
+ window.localStorage.getItem("AUTHENTICATION_MODE") === OIDC &&
+ tokens?.accessToken
+ ) {
+ const dataRetreiver = new DataFormatter(tokens.accessToken);
+ dataRetreiver.getUserInfo((data) => {
+ setAuthenticated(data !== undefined);
+ setData(data);
});
}
- }
+ }, [tokens]);
- render() {
- const {
- keycloak, authenticated, data, contactFailed, initialisationFailed,
- } = this.state;
- if (keycloak || authenticated) {
- if (authenticated) {
- return (
-
+ if (!tokens?.accessToken) {
+ return
{D.initializationFailed}
;
+ }
-
-
- );
- }
- return ({D.unableToAuthenticate}
);
- }
- if (initialisationFailed) {
- return ({D.initializationFailed}
);
- }
- if (contactFailed) {
- return ({D.cannotContactServer}
);
- }
+ if (authenticated && tokens?.accessToken && data) {
return (
- {D.initializing}
+
+
+
);
}
-}
-export default App;
+ if (contactFailed) {
+ return {D.cannotContactServer}
;
+ }
+
+ return {D.initializing}
;
+};
diff --git a/src/components/App/App.test.jsx b/src/components/App/App.test.jsx
index 1ada40c..93a2c5a 100644
--- a/src/components/App/App.test.jsx
+++ b/src/components/App/App.test.jsx
@@ -1,14 +1,12 @@
// Link.react.test.js
import React from 'react';
-import {
- render, screen, cleanup, waitForElement,
-} from '@testing-library/react';
-import Keycloak from 'keycloak-js';
+import { render, screen, cleanup } from "@testing-library/react";
import { NotificationManager } from 'react-notifications';
import DataFormatter from '../../utils/DataFormatter';
-import App from './App';
+import { App } from "./App";
import mocks from '../../tests/mocks';
import C from '../../utils/constants.json';
+import { mockOidcForUser, mockOidcFailed } from "../../Authentication/useAuth";
jest.mock(
"../../../package.json",
@@ -29,7 +27,6 @@ Date.now = jest.fn(() => 1597916474000);
afterEach(cleanup);
-jest.mock('keycloak-js');
jest.mock('react-notifications');
jest.mock('../../utils/DataFormatter');
jest.mock('../../initConfiguration');
@@ -53,15 +50,6 @@ const mockError = jest.fn();
NotificationManager.success = mockSuccess;
NotificationManager.error = mockError;
-Keycloak.init = jest.fn(() => (Promise.resolve({ token: 'abc' })));
-
-Keycloak.mockImplementation(() => ({
- init: jest.fn(() => (Promise.resolve({ token: 'abc' }))),
- updateToken: (() => ({ error: (() => {}) })),
- tokenParsed: { exp: 300 },
- timeSkew: 0,
-}));
-
const updatePreferences = jest.fn((newPrefs, cb) => {
if (newPrefs.includes('simpsonkgs2020x00')) {
cb({ status: 500 });
@@ -104,52 +92,15 @@ DataFormatter.mockImplementation(() => ({
updatePreferences,
}));
-it('Component is displayed (initializing)', async () => {
- const component = render(
- ,
- );
- // Should match snapshot
- expect(component).toMatchSnapshot();
-});
-
-it('Component is displayed (anonymous mode)', async () => {
- Object.getPrototypeOf(window.localStorage).getItem = jest.fn(() => ('anonymous'));
- const component = render(
- ,
- );
-
- await waitForElement(() => screen.getByTestId('pagination-nav'));
-
- // Should match snapshot
+it("Component is displayed ", async () => {
+ mockOidcForUser();
+ const component = render();
+ await screen.findByText("List of surveys");
expect(component).toMatchSnapshot();
});
-it('Component is displayed (keycloak mode)', async () => {
- Object.getPrototypeOf(window.localStorage).getItem = jest.fn(() => ('keycloak'));
- const component = render(
- ,
- );
-
- await waitForElement(() => screen.getByTestId('pagination-nav'));
-
- // Should match snapshot
- expect(component).toMatchSnapshot();
-});
-
-it('Could not authenticate with keycloak', async () => {
- Object.getPrototypeOf(window.localStorage).getItem = jest.fn(() => ('keycloak'));
-
- Keycloak.mockImplementation(() => ({
- init: jest.fn(() => (Promise.resolve(false))),
- updateToken: (() => ({ error: (() => {}) })),
- tokenParsed: { exp: 300 },
- timeSkew: 0,
- }));
-
- const component = render(
- ,
- );
-
- // Should match snapshot
+it("Component is not displayed ", async () => {
+ mockOidcFailed();
+ const component = render();
expect(component).toMatchSnapshot();
});
diff --git a/src/components/App/__snapshots__/App.test.jsx.snap b/src/components/App/__snapshots__/App.test.jsx.snap
index beafead..6d307da 100644
--- a/src/components/App/__snapshots__/App.test.jsx.snap
+++ b/src/components/App/__snapshots__/App.test.jsx.snap
@@ -1,6 +1,6 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
-exports[`Component is displayed (anonymous mode) 1`] = `
+exports[`Component is displayed 1`] = `
Object {
"asFragment": [Function],
"baseElement":
@@ -2309,2397 +2309,19 @@ Object {
}
`;
-exports[`Component is displayed (initializing) 1`] = `
+exports[`Component is not displayed 1`] = `
Object {
"asFragment": [Function],
"baseElement":
- Initializing...
+ Could not load settings
,
"container": ,
- "debug": [Function],
- "findAllByAltText": [Function],
- "findAllByDisplayValue": [Function],
- "findAllByLabelText": [Function],
- "findAllByPlaceholderText": [Function],
- "findAllByRole": [Function],
- "findAllByTestId": [Function],
- "findAllByText": [Function],
- "findAllByTitle": [Function],
- "findByAltText": [Function],
- "findByDisplayValue": [Function],
- "findByLabelText": [Function],
- "findByPlaceholderText": [Function],
- "findByRole": [Function],
- "findByTestId": [Function],
- "findByText": [Function],
- "findByTitle": [Function],
- "getAllByAltText": [Function],
- "getAllByDisplayValue": [Function],
- "getAllByLabelText": [Function],
- "getAllByPlaceholderText": [Function],
- "getAllByRole": [Function],
- "getAllByTestId": [Function],
- "getAllByText": [Function],
- "getAllByTitle": [Function],
- "getByAltText": [Function],
- "getByDisplayValue": [Function],
- "getByLabelText": [Function],
- "getByPlaceholderText": [Function],
- "getByRole": [Function],
- "getByTestId": [Function],
- "getByText": [Function],
- "getByTitle": [Function],
- "queryAllByAltText": [Function],
- "queryAllByDisplayValue": [Function],
- "queryAllByLabelText": [Function],
- "queryAllByPlaceholderText": [Function],
- "queryAllByRole": [Function],
- "queryAllByTestId": [Function],
- "queryAllByText": [Function],
- "queryAllByTitle": [Function],
- "queryByAltText": [Function],
- "queryByDisplayValue": [Function],
- "queryByLabelText": [Function],
- "queryByPlaceholderText": [Function],
- "queryByRole": [Function],
- "queryByTestId": [Function],
- "queryByText": [Function],
- "queryByTitle": [Function],
- "rerender": [Function],
- "unmount": [Function],
-}
-`;
-
-exports[`Component is displayed (keycloak mode) 1`] = `
-Object {
- "asFragment": [Function],
- "baseElement":
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Bienvenue
- Chloé
-
- Dupont
-
-
- 8/20/2020
-
-
-
-
-
-
-
-
-
-
- List of surveys
-
-
-
- Display
-
-
-
- elements
-
-
-
-
-
-
-
-
-
-
-
- ,
- "container":
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Bienvenue
- Chloé
-
- Dupont
-
-
- 8/20/2020
-
-
-
-
-
-
-
-
-
-
- List of surveys
-
-
-
- Display
-
-
-
- elements
-
-
-
-
-
-
-
-
-
-
-
,
- "debug": [Function],
- "findAllByAltText": [Function],
- "findAllByDisplayValue": [Function],
- "findAllByLabelText": [Function],
- "findAllByPlaceholderText": [Function],
- "findAllByRole": [Function],
- "findAllByTestId": [Function],
- "findAllByText": [Function],
- "findAllByTitle": [Function],
- "findByAltText": [Function],
- "findByDisplayValue": [Function],
- "findByLabelText": [Function],
- "findByPlaceholderText": [Function],
- "findByRole": [Function],
- "findByTestId": [Function],
- "findByText": [Function],
- "findByTitle": [Function],
- "getAllByAltText": [Function],
- "getAllByDisplayValue": [Function],
- "getAllByLabelText": [Function],
- "getAllByPlaceholderText": [Function],
- "getAllByRole": [Function],
- "getAllByTestId": [Function],
- "getAllByText": [Function],
- "getAllByTitle": [Function],
- "getByAltText": [Function],
- "getByDisplayValue": [Function],
- "getByLabelText": [Function],
- "getByPlaceholderText": [Function],
- "getByRole": [Function],
- "getByTestId": [Function],
- "getByText": [Function],
- "getByTitle": [Function],
- "queryAllByAltText": [Function],
- "queryAllByDisplayValue": [Function],
- "queryAllByLabelText": [Function],
- "queryAllByPlaceholderText": [Function],
- "queryAllByRole": [Function],
- "queryAllByTestId": [Function],
- "queryAllByText": [Function],
- "queryAllByTitle": [Function],
- "queryByAltText": [Function],
- "queryByDisplayValue": [Function],
- "queryByLabelText": [Function],
- "queryByPlaceholderText": [Function],
- "queryByRole": [Function],
- "queryByTestId": [Function],
- "queryByText": [Function],
- "queryByTitle": [Function],
- "rerender": [Function],
- "unmount": [Function],
-}
-`;
-
-exports[`Could not authenticate with keycloak 1`] = `
-Object {
- "asFragment": [Function],
- "baseElement":
-
- ,
- "container":
-
- Initializing...
+ Could not load settings
,
"debug": [Function],
diff --git a/src/components/CollectionTable/CollectionTableDisplay.jsx b/src/components/CollectionTable/CollectionTableDisplay.jsx
index 98906da..62fdcde 100644
--- a/src/components/CollectionTable/CollectionTableDisplay.jsx
+++ b/src/components/CollectionTable/CollectionTableDisplay.jsx
@@ -272,12 +272,10 @@ function CollectionTableDisplay({
(pagination.page - 1) * pagination.size,
Math.min(pagination.page * pagination.size, displayedLines.length),
)
- .map((line) => (
-
- ))}
+ .map((line) => (
+
+ )
+ )}
{tableFooter}
diff --git a/src/components/MonitoringTable/FollowUpTable.jsx b/src/components/MonitoringTable/FollowUpTable.jsx
index 7f7ce5c..718b1c5 100644
--- a/src/components/MonitoringTable/FollowUpTable.jsx
+++ b/src/components/MonitoringTable/FollowUpTable.jsx
@@ -187,7 +187,7 @@ function FollowUpTable({
Math.min(pagination.page * pagination.size, displayedLines.length),
)
.map((line) => (
-
+
))}
{tableFooter}
diff --git a/src/components/View/View.jsx b/src/components/View/View.jsx
index 13b6313..26e9a4b 100644
--- a/src/components/View/View.jsx
+++ b/src/components/View/View.jsx
@@ -29,7 +29,7 @@ class View extends React.Component {
loadingPreferences: true,
campaigns: []
};
- this.dataRetreiver = new DataFormatter(props.keycloak);
+ this.dataRetreiver = new DataFormatter(props.token);
}
componentDidMount() {
diff --git a/src/index.js b/src/index.js
index a4534dc..8aa158c 100644
--- a/src/index.js
+++ b/src/index.js
@@ -1,15 +1,57 @@
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
-import App from './components/App/App';
import 'bootstrap/dist/css/bootstrap.min.css';
import 'font-awesome/css/font-awesome.min.css';
import 'react-notifications/lib/notifications.css';
import 'whatwg-fetch';
+import { initializeOidc } from './Authentication/useAuth';
+import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
+import { App } from "./components/App/App"
+
+async function main() {
+ // Load OIDC configuration
+ const publicUrl = new URL(process.env.PUBLIC_URL, window.location.href);
+ const response = await fetch(`${publicUrl.origin}/configuration.json`)
+ const configuration = await response.json();
+
+ // Inject configuration infos in the localStorage
+ window.localStorage.setItem(
+ 'AUTHENTICATION_MODE',
+ configuration.AUTHENTICATION_MODE,
+ );
+ window.localStorage.setItem('PEARL_JAM_URL', configuration.PEARL_JAM_URL);
+ window.localStorage.setItem('QUEEN_URL_BACK_END', configuration.QUEEN_URL_BACK_END);
+ window.localStorage.setItem('QUEEN_URL_FRONT_END', configuration.QUEEN_URL_FRONT_END);
+
+ // Initialize OIDC globally to use it later
+ const {OidcProvider} = initializeOidc({
+ issuerUri: configuration.ISSUER_URI,
+ clientId: configuration.OIDC_CLIENT_ID,
+ publicUrl: "/",
+ })
+
+ const queryClient = new QueryClient({
+ defaultOptions: {
+ queries: {
+ staleTime: 10000,
+ refetchOnWindowFocus: false,
+ retry: false,
+ },
+ },
+ });
+
+ ReactDOM.render(
+
+
+
+
+
+
+ ,
+ document.getElementById('root'),
+ );
+}
+
+main();
-ReactDOM.render(
-
-
- ,
- document.getElementById('root'),
-);
diff --git a/src/tests/mocks/formattedDataMonitoringTableBysurvey.js b/src/tests/mocks/formattedDataMonitoringTableBysurvey.js
index a9afe72..445123c 100644
--- a/src/tests/mocks/formattedDataMonitoringTableBysurvey.js
+++ b/src/tests/mocks/formattedDataMonitoringTableBysurvey.js
@@ -3,6 +3,7 @@ const val = {
"linesDetails": [
{
"completionRate": 0.057692307692307696,
+ "campaignId": "simpsons2020x00",
"total": 82,
"notStarted": 22,
"onGoing": 76,
@@ -17,6 +18,7 @@ const val = {
},
{
"completionRate": 0.057692307692307696,
+ "campaignId": "simpsosfqns2020x00",
"total": 82,
"notStarted": 22,
"onGoing": 76,
@@ -31,6 +33,7 @@ const val = {
},
{
"completionRate": 0.057692307692307696,
+ "campaignId": "vqs2fsqe021x00",
"total": 82,
"notStarted": 22,
"onGoing": 76,
@@ -45,6 +48,7 @@ const val = {
},
{
"completionRate": 0.057692307692307696,
+ "campaignId": "simpsonqsdfsqes2020x00",
"total": 82,
"notStarted": 22,
"onGoing": 76,
@@ -59,6 +63,7 @@ const val = {
},
{
"completionRate": 0.057692307692307696,
+ "campaignId": "vqs2qfsdfsqe021x00",
"total": 82,
"notStarted": 22,
"onGoing": 76,
@@ -73,6 +78,7 @@ const val = {
},
{
"completionRate": 0.057692307692307696,
+ "campaignId": "simpsonkgs2020x00",
"total": 82,
"notStarted": 22,
"onGoing": 76,
@@ -87,6 +93,7 @@ const val = {
},
{
"completionRate": 0.057692307692307696,
+ "campaignId": "vqs202fgd1x00",
"total": 82,
"notStarted": 22,
"onGoing": 76,
diff --git a/src/utils/DataFormatter.js b/src/utils/DataFormatter.js
index 6ddcaa8..466278a 100644
--- a/src/utils/DataFormatter.js
+++ b/src/utils/DataFormatter.js
@@ -10,8 +10,8 @@ import Service from "./Service";
import Utils from "./Utils";
class DataFormatter {
- constructor(keycloak) {
- this.service = new Service(keycloak);
+ constructor(token) {
+ this.service = new Service(token);
}
getInterviewers(cb) {
@@ -491,6 +491,7 @@ class DataFormatter {
res.map((x) => {
const obj = Utils.formatForMonitoringTable(x);
obj.survey = x.campaign.label;
+ obj.campaignId = x.campaign.id;
return obj;
})
);
@@ -674,7 +675,7 @@ class DataFormatter {
.filter((camp) => camp.total)
.map((camp) =>
Utils.formatForCollectionTable(
- { survey: camp.campaign.label },
+ { survey: camp.campaign.label, campaignId: camp.campaign?.id },
data[0].find((c) => c.campaign.id === camp.campaign.id),
camp
)
diff --git a/src/utils/Service.js b/src/utils/Service.js
index 84347a2..45bedf8 100644
--- a/src/utils/Service.js
+++ b/src/utils/Service.js
@@ -1,20 +1,18 @@
import { NotificationManager } from "react-notifications";
import D from "../i18n";
-
-const baseUrlPearlJam = `${window.localStorage.getItem("PEARL_JAM_URL")}`;
-const baseUrlQueen = `${window.localStorage.getItem("QUEEN_URL_BACK_END")}`;
-
class Service {
- constructor(keycloak) {
- this.keycloak = keycloak;
+ constructor(token) {
+ this.token = token;
+ this.baseUrlPearlJam = `${window.localStorage.getItem("PEARL_JAM_URL")}`;
+ this.baseUrlQueen = `${window.localStorage.getItem("QUEEN_URL_BACK_END")}`;
}
-
makeOptions() {
- if (this.keycloak) {
+ if (this.token) {
+
return {
headers: new Headers({
"Content-Type": "application/json",
- Authorization: `Bearer ${this.keycloak.token}`,
+ Authorization: `Bearer ${this.token}`,
}),
};
}
@@ -31,7 +29,7 @@ class Service {
getSurveyUnits(campaignId, state, cb) {
return new Promise((resolve) => {
fetch(
- `${baseUrlPearlJam}/api/campaign/${campaignId}/survey-units?${
+ `${this.baseUrlPearlJam}/api/campaign/${campaignId}/survey-units?${
state ? `state=${state}` : ""
}`,
this.makeOptions()
@@ -55,7 +53,7 @@ class Service {
}
async getSurveyUnitsQuestionnaireId(listSurveyUnitIds, cb) {
- return fetch(`${baseUrlQueen}/api/survey-units/questionnaire-model-id`, {
+ return fetch(`${this.baseUrlQueen}/api/survey-units/questionnaire-model-id`, {
...this.makeOptions(),
method: "POST",
body: JSON.stringify(listSurveyUnitIds),
@@ -76,7 +74,7 @@ class Service {
}
getSurveyUnitsClosable(cb) {
- fetch(`${baseUrlPearlJam}/api/survey-units/closable`, this.makeOptions())
+ fetch(`${this.baseUrlPearlJam}/api/survey-units/closable`, this.makeOptions())
.then((res) => res.json())
.then((data) => {
cb(data);
@@ -93,7 +91,7 @@ class Service {
getSurveyUnitsNotAttributedByCampaign(campaignId, cb) {
fetch(
- `${baseUrlPearlJam}/api/campaign/${campaignId}/survey-units/not-attributed`,
+ `${this.baseUrlPearlJam}/api/campaign/${campaignId}/survey-units/not-attributed`,
this.makeOptions()
)
.then((res) => res.json())
@@ -108,7 +106,7 @@ class Service {
getSurveyUnitsAbandonedByCampaign(campaignId, cb) {
fetch(
- `${baseUrlPearlJam}/api/campaign/${campaignId}/survey-units/abandoned`,
+ `${this.baseUrlPearlJam}/api/campaign/${campaignId}/survey-units/abandoned`,
this.makeOptions()
)
.then((res) => res.json())
@@ -122,7 +120,7 @@ class Service {
}
getStatesBySurveyUnit(su, cb) {
- fetch(`${baseUrlPearlJam}/api/survey-unit/${su}/states`, this.makeOptions())
+ fetch(`${this.baseUrlPearlJam}/api/survey-unit/${su}/states`, this.makeOptions())
.then((res) => res.json())
.then((data) => {
cb(data);
@@ -141,7 +139,7 @@ class Service {
const options = {};
Object.assign(options, this.makeOptions());
options.method = "PUT";
- fetch(`${baseUrlPearlJam}/api/survey-unit/${su}/state/FIN`, options)
+ fetch(`${this.baseUrlPearlJam}/api/survey-unit/${su}/state/FIN`, options)
.then((res) => cb(res))
.catch((e) => {
console.error(e);
@@ -153,7 +151,7 @@ class Service {
const options = {};
Object.assign(options, this.makeOptions());
options.method = "PUT";
- fetch(`${baseUrlPearlJam}/api/survey-unit/${su}/state/${state}`, options)
+ fetch(`${this.baseUrlPearlJam}/api/survey-unit/${su}/state/${state}`, options)
.then((res) => cb(res))
.catch((e) => {
console.error(e);
@@ -166,7 +164,7 @@ class Service {
Object.assign(options, this.makeOptions());
options.method = "PUT";
fetch(
- `${baseUrlPearlJam}/api/survey-unit/${su}/close/${closingCause}`,
+ `${this.baseUrlPearlJam}/api/survey-unit/${su}/close/${closingCause}`,
options
)
.then((res) => cb(res))
@@ -181,7 +179,7 @@ class Service {
Object.assign(options, this.makeOptions());
options.method = "PUT";
fetch(
- `${baseUrlPearlJam}/api/survey-unit/${su}/closing-cause/${closingCause}`,
+ `${this.baseUrlPearlJam}/api/survey-unit/${su}/closing-cause/${closingCause}`,
options
)
.then((res) => cb(res))
@@ -196,7 +194,7 @@ class Service {
Object.assign(options, this.makeOptions());
options.method = "PUT";
options.body = JSON.stringify(comment);
- fetch(`${baseUrlPearlJam}/api/survey-unit/${su}/comment`, options)
+ fetch(`${this.baseUrlPearlJam}/api/survey-unit/${su}/comment`, options)
.then((res) => cb(res))
.catch((e) => {
console.error(e);
@@ -208,7 +206,7 @@ class Service {
const options = {};
Object.assign(options, this.makeOptions());
options.method = "PUT";
- fetch(`${baseUrlPearlJam}/api/survey-unit/${su}/viewed`, options)
+ fetch(`${this.baseUrlPearlJam}/api/survey-unit/${su}/viewed`, options)
.then((res) => cb(res))
.catch((e) => {
console.error(e);
@@ -227,7 +225,7 @@ class Service {
Object.assign(options, this.makeOptions());
options.method = "PUT";
options.body = JSON.stringify(preferences);
- fetch(`${baseUrlPearlJam}/api/preferences`, options)
+ fetch(`${this.baseUrlPearlJam}/api/preferences`, options)
.then((res) => cb(res))
.catch(console.error);
}
@@ -240,7 +238,7 @@ class Service {
// -------------------- //
getUser(cb) {
return new Promise((resolve) => {
- fetch(`${baseUrlPearlJam}/api/user`, this.makeOptions())
+ fetch(`${this.baseUrlPearlJam}/api/user`, this.makeOptions())
.then((res) => res.json())
.then((data) => {
if (cb) {
@@ -269,7 +267,7 @@ class Service {
// Campaigns service begin //
// ----------------------- //
getCampaigns(cb) {
- fetch(`${baseUrlPearlJam}/api/campaigns`, this.makeOptions())
+ fetch(`${this.baseUrlPearlJam}/api/campaigns`, this.makeOptions())
.then((res) => res.json())
.then((data) => {
cb(data);
@@ -287,7 +285,7 @@ class Service {
getCampaignsByInterviewer(idep, cb) {
return new Promise((resolve) => {
fetch(
- `${baseUrlPearlJam}/api/interviewer/${idep}/campaigns`,
+ `${this.baseUrlPearlJam}/api/interviewer/${idep}/campaigns`,
this.makeOptions()
)
.then((res) => res.json())
@@ -316,7 +314,7 @@ class Service {
getStateCount(campaignId, date, cb) {
return new Promise((resolve) => {
fetch(
- `${baseUrlPearlJam}/api/campaign/${campaignId}/survey-units/state-count?date=${date}`,
+ `${this.baseUrlPearlJam}/api/campaign/${campaignId}/survey-units/state-count?date=${date}`,
this.makeOptions()
)
.then((res) => res.json())
@@ -335,7 +333,7 @@ class Service {
getStateCountNotAttributed(campaignId, date, cb) {
return new Promise((resolve) => {
fetch(
- `${baseUrlPearlJam}/api/campaign/${campaignId}/survey-units/not-attributed/state-count?date=${date}`,
+ `${this.baseUrlPearlJam}/api/campaign/${campaignId}/survey-units/not-attributed/state-count?date=${date}`,
this.makeOptions()
)
.then((res) => res.json())
@@ -358,7 +356,7 @@ class Service {
getStateCountByInterviewer(campaignId, idep, date, cb) {
return new Promise((resolve) => {
fetch(
- `${baseUrlPearlJam}/api/campaign/${campaignId}/survey-units/interviewer/${idep}/state-count?date=${date}`,
+ `${this.baseUrlPearlJam}/api/campaign/${campaignId}/survey-units/interviewer/${idep}/state-count?date=${date}`,
this.makeOptions()
)
.then((res) => res.json())
@@ -381,7 +379,7 @@ class Service {
getStateCountByCampaign(date, cb) {
return new Promise((resolve) => {
fetch(
- `${baseUrlPearlJam}/api/campaigns/survey-units/state-count?date=${date}`,
+ `${this.baseUrlPearlJam}/api/campaigns/survey-units/state-count?date=${date}`,
this.makeOptions()
)
.then((res) => res.json())
@@ -399,7 +397,7 @@ class Service {
getStateCountTotalByCampaign(campaignId, cb) {
fetch(
- `${baseUrlPearlJam}/api/campaign/${campaignId}/survey-units/state-count`,
+ `${this.baseUrlPearlJam}/api/campaign/${campaignId}/survey-units/state-count`,
this.makeOptions()
)
.then((res) => res.json())
@@ -425,7 +423,7 @@ class Service {
getContactOutcomes(campaignId, date, cb) {
return new Promise((resolve) => {
fetch(
- `${baseUrlPearlJam}/api/campaign/${campaignId}/survey-units/contact-outcomes?date=${date}`,
+ `${this.baseUrlPearlJam}/api/campaign/${campaignId}/survey-units/contact-outcomes?date=${date}`,
this.makeOptions()
)
.then((res) => res.json())
@@ -444,7 +442,7 @@ class Service {
getContactOutcomesNotAttributed(campaignId, date, cb) {
return new Promise((resolve) => {
fetch(
- `${baseUrlPearlJam}/api/campaign/${campaignId}/survey-units/not-attributed/contact-outcomes?date=${date}`,
+ `${this.baseUrlPearlJam}/api/campaign/${campaignId}/survey-units/not-attributed/contact-outcomes?date=${date}`,
this.makeOptions()
)
.then((res) => res.json())
@@ -467,7 +465,7 @@ class Service {
getContactOutcomesByInterviewer(campaignId, idep, date, cb) {
return new Promise((resolve) => {
fetch(
- `${baseUrlPearlJam}/api/campaign/${campaignId}/survey-units/interviewer/${idep}/contact-outcomes?date=${date}`,
+ `${this.baseUrlPearlJam}/api/campaign/${campaignId}/survey-units/interviewer/${idep}/contact-outcomes?date=${date}`,
this.makeOptions()
)
.then((res) => res.json())
@@ -490,7 +488,7 @@ class Service {
getContactOutcomesByCampaign(date, cb) {
return new Promise((resolve) => {
fetch(
- `${baseUrlPearlJam}/api/campaigns/survey-units/contact-outcomes?date=${date}`,
+ `${this.baseUrlPearlJam}/api/campaigns/survey-units/contact-outcomes?date=${date}`,
this.makeOptions()
)
.then((res) => res.json())
@@ -515,7 +513,7 @@ class Service {
getClosingCausesByInterviewer(campaignId, idep, date, cb) {
return new Promise((resolve) => {
fetch(
- `${baseUrlPearlJam}/api/campaign/${campaignId}/survey-units/interviewer/${idep}/closing-causes?date=${date}`,
+ `${this.baseUrlPearlJam}/api/campaign/${campaignId}/survey-units/interviewer/${idep}/closing-causes?date=${date}`,
this.makeOptions()
)
.then((res) => res.json())
@@ -542,7 +540,7 @@ class Service {
// Interviewers service begin //
// --------------------------- //
getInterviewers(cb) {
- fetch(`${baseUrlPearlJam}/api/interviewers`, this.makeOptions())
+ fetch(`${this.baseUrlPearlJam}/api/interviewers`, this.makeOptions())
.then((res) => res.json())
.then((data) => {
cb(data);
@@ -556,7 +554,7 @@ class Service {
getInterviewersByCampaign(campaignId, cb) {
return new Promise((resolve) => {
fetch(
- `${baseUrlPearlJam}/api/campaign/${campaignId}/interviewers`,
+ `${this.baseUrlPearlJam}/api/campaign/${campaignId}/interviewers`,
this.makeOptions()
)
.then((res) => res.json())
@@ -578,7 +576,7 @@ class Service {
// ----------------------------- //
getQuestionnaireId(campaignId, cb) {
fetch(
- `${baseUrlQueen}/api/campaign/${campaignId}/questionnaire-id`,
+ `${this.baseUrlQueen}/api/campaign/${campaignId}/questionnaire-id`,
this.makeOptions()
)
.then((res) => res.json())
@@ -603,7 +601,7 @@ class Service {
options.method = "POST";
options.body = JSON.stringify(body);
- fetch(`${baseUrlPearlJam}/api/message`, options).then((data) => {
+ fetch(`${this.baseUrlPearlJam}/api/message`, options).then((data) => {
cb(data);
});
}
@@ -614,7 +612,7 @@ class Service {
options.method = "POST";
options.body = JSON.stringify({ text });
- fetch(`${baseUrlPearlJam}/api/verify-name`, options)
+ fetch(`${this.baseUrlPearlJam}/api/verify-name`, options)
.then((res) => res.json())
.then((data) => {
cb(data);
@@ -626,7 +624,7 @@ class Service {
}
getMessageHistory(cb) {
- fetch(`${baseUrlPearlJam}/api/message-history`, this.makeOptions())
+ fetch(`${this.baseUrlPearlJam}/api/message-history`, this.makeOptions())
.then((res) => res.json())
.then((data) => {
cb(data);
diff --git a/src/utils/Service.test.js b/src/utils/Service.test.js
index e52c593..d989b6a 100644
--- a/src/utils/Service.test.js
+++ b/src/utils/Service.test.js
@@ -26,7 +26,7 @@ const {
const service = new Service();
it('Test option creation', async () => {
- const s = new Service({ token: 'ABC' });
+ const s = new Service('ABC');
// Should return correct options
expect(s.makeOptions()).toEqual({ headers: { map: { authorization: 'Bearer ABC', 'content-type': 'application/json' } } });
});
diff --git a/src/utils/Utils.js b/src/utils/Utils.js
index 18b6a29..ffaeecf 100644
--- a/src/utils/Utils.js
+++ b/src/utils/Utils.js
@@ -82,10 +82,6 @@ class Utils {
line.appointmentTaken = stateCount.apsCount;
line.interviewStarted = stateCount.insCount;
- line.interviewerFirstName = stateCount.interviewerFirstName;
- line.interviewerFirstName = stateCount.interviewerLastName;
- line.interviewerId = stateCount.interviewerId;
-
return line;
}
diff --git a/src/utils/constants.json b/src/utils/constants.json
index 4940fac..18c5940 100644
--- a/src/utils/constants.json
+++ b/src/utils/constants.json
@@ -1,11 +1,10 @@
{
"KEYCLOAK": "keycloak",
"ANONYMOUS": "anonymous",
-
- "BY_INTERVIEWER_ONE_SURVEY":0,
- "BY_INTERVIEWER":1,
- "BY_SURVEY":2,
+ "OIDC": "oidc",
+ "BY_INTERVIEWER_ONE_SURVEY": 0,
+ "BY_INTERVIEWER": 1,
+ "BY_SURVEY": 2,
"BY_SITE": 3,
"BY_SURVEY_ONE_INTERVIEWER": 4
}
-
diff --git a/yarn.lock b/yarn.lock
index 7437d64..c9c4a2f 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1828,6 +1828,20 @@
"@svgr/plugin-svgo" "^4.3.1"
loader-utils "^1.2.3"
+"@tanstack/query-core@^4.0.0-beta.1":
+ version "4.36.1"
+ resolved "https://registry.yarnpkg.com/@tanstack/query-core/-/query-core-4.36.1.tgz#79f8c1a539d47c83104210be2388813a7af2e524"
+ integrity sha512-DJSilV5+ytBP1FbFcEJovv4rnnm/CokuVvrBEtW/Va9DvuJ3HksbXUJEpI0aV1KtuL4ZoO9AVE6PyNLzF7tLeA==
+
+"@tanstack/react-query@4.0.5":
+ version "4.0.5"
+ resolved "https://registry.yarnpkg.com/@tanstack/react-query/-/react-query-4.0.5.tgz#4597ac03394ddfa6ad8b5e1beb6282468623d398"
+ integrity sha512-tIggVlhoFevVpY/LkZroPmrERFHN8tw4aZLtgwSArzHmMJ03WQcaNvbbHy6GERidXtaMdUz+IeQryrE7cO7WPQ==
+ dependencies:
+ "@tanstack/query-core" "^4.0.0-beta.1"
+ "@types/use-sync-external-store" "^0.0.3"
+ use-sync-external-store "^1.2.0"
+
"@testing-library/dom@*":
version "9.3.3"
resolved "https://registry.yarnpkg.com/@testing-library/dom/-/dom-9.3.3.tgz#108c23a5b0ef51121c26ae92eb3179416b0434f5"
@@ -2094,6 +2108,11 @@
"@types/testing-library__dom" "*"
pretty-format "^25.1.0"
+"@types/use-sync-external-store@^0.0.3":
+ version "0.0.3"
+ resolved "https://registry.yarnpkg.com/@types/use-sync-external-store/-/use-sync-external-store-0.0.3.tgz#b6725d5f4af24ace33b36fafd295136e75509f43"
+ integrity sha512-EwmlvuaxPNej9+T4v5AuBPJa2x2UOJVdjCtDHgcDqitUeOtjnJKJ+apYjVcAoBEMjKW1VVFGZLUb5+qqa09XFA==
+
"@types/warning@^3.0.0":
version "3.0.3"
resolved "https://registry.yarnpkg.com/@types/warning/-/warning-3.0.3.tgz#d1884c8cc4a426d1ac117ca2611bf333834c6798"
@@ -4180,6 +4199,11 @@ crypto-browserify@^3.11.0:
randombytes "^2.0.0"
randomfill "^1.0.3"
+crypto-js@^4.2.0:
+ version "4.2.0"
+ resolved "https://registry.yarnpkg.com/crypto-js/-/crypto-js-4.2.0.tgz#4d931639ecdfd12ff80e8186dba6af2c2e856631"
+ integrity sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==
+
css-blank-pseudo@^0.1.4:
version "0.1.4"
resolved "https://registry.yarnpkg.com/css-blank-pseudo/-/css-blank-pseudo-0.1.4.tgz#dfdefd3254bf8a82027993674ccf35483bfcb3c5"
@@ -8117,10 +8141,10 @@ jsx-ast-utils@^2.2.1, jsx-ast-utils@^2.2.3:
object.assign "^4.1.4"
object.values "^1.1.6"
-keycloak-js@4.0.0-beta.2:
- version "4.0.0-beta.2"
- resolved "https://registry.yarnpkg.com/keycloak-js/-/keycloak-js-4.0.0-beta.2.tgz#01f791da18db2cecce467cd00d79dd49f847ba7d"
- integrity sha512-cMoiOOboVmK4DTXZMeShPfDfwciIc/QNMBfU90XuQfjQKeNmUZZFOzpdH5bYv7In61dCDBAdojcK5+y5sFXOmg==
+jwt-decode@^3.1.2:
+ version "3.1.2"
+ resolved "https://registry.yarnpkg.com/jwt-decode/-/jwt-decode-3.1.2.tgz#3fb319f3675a2df0c2895c8f5e9fa4b67b04ed59"
+ integrity sha512-UfpWE/VZn0iP50d8cz9NrZLM9lSWhcJ+0Gt/nm4by88UL+J1SiKN8/5dkjMmbEzwL2CAe+67GsegCbIKtbp75A==
killable@^1.0.1:
version "1.0.1"
@@ -9195,6 +9219,23 @@ obuf@^1.0.0, obuf@^1.1.2:
resolved "https://registry.yarnpkg.com/obuf/-/obuf-1.1.2.tgz#09bea3343d41859ebd446292d11c9d4db619084e"
integrity sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==
+oidc-client-ts@2.4.0:
+ version "2.4.0"
+ resolved "https://registry.yarnpkg.com/oidc-client-ts/-/oidc-client-ts-2.4.0.tgz#764c8a33de542026e2798de9849ce8049047d7e5"
+ integrity sha512-WijhkTrlXK2VvgGoakWJiBdfIsVGz6CFzgjNNqZU1hPKV2kyeEaJgLs7RwuiSp2WhLfWBQuLvr2SxVlZnk3N1w==
+ dependencies:
+ crypto-js "^4.2.0"
+ jwt-decode "^3.1.2"
+
+oidc-spa@4.5.1:
+ version "4.5.1"
+ resolved "https://registry.yarnpkg.com/oidc-spa/-/oidc-spa-4.5.1.tgz#5bf772143d739aa9a6907fb61f17ac55e595f14a"
+ integrity sha512-MMgjT2d3zpdh91B6vehgAMlKD0rUAxQeowx3wFCs64fSiH5zD9mjXsqoflAEdelsbvvHv7h+sTv3/Znbquhj8w==
+ dependencies:
+ jwt-decode "^3.1.2"
+ oidc-client-ts "2.4.0"
+ tsafe "^1.6.5"
+
on-finished@2.4.1:
version "2.4.1"
resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.4.1.tgz#58c8c44116e54845ad57f14ab10b03533184ac3f"
@@ -12579,6 +12620,11 @@ ts-pnp@^1.1.2:
resolved "https://registry.yarnpkg.com/ts-pnp/-/ts-pnp-1.2.0.tgz#a500ad084b0798f1c3071af391e65912c86bca92"
integrity sha512-csd+vJOb/gkzvcCHgTGSChYpy5f1/XKNsmvBGO4JXS+z1v2HobugDz4s1IeFXM3wZB44uczs+eazB5Q/ccdhQw==
+tsafe@^1.6.5:
+ version "1.6.6"
+ resolved "https://registry.yarnpkg.com/tsafe/-/tsafe-1.6.6.tgz#fd93e64d6eb13ef83ed1650669cc24bad4f5df9f"
+ integrity sha512-gzkapsdbMNwBnTIjgO758GujLCj031IgHK/PKr2mrmkCSJMhSOR5FeOuSxKLMUoYc0vAA4RGEYYbjt/v6afD3g==
+
tsconfig-paths@^3.15.0:
version "3.15.0"
resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz#5299ec605e55b1abb23ec939ef15edaf483070d4"
@@ -12872,6 +12918,11 @@ url@^0.11.0:
punycode "^1.4.1"
qs "^6.11.2"
+use-sync-external-store@^1.2.0:
+ version "1.2.2"
+ resolved "https://registry.yarnpkg.com/use-sync-external-store/-/use-sync-external-store-1.2.2.tgz#c3b6390f3a30eba13200d2302dcdf1e7b57b2ef9"
+ integrity sha512-PElTlVMwpblvbNqQ82d2n6RjStvdSoNe9FG28kNfz3WiXilJm4DdNkEzRhCZuIDwY8U08WVihhGR5iRqAwfDiw==
+
use@^3.1.0:
version "3.1.1"
resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f"