diff --git a/src/__test__/components/ContentWrapper.test.jsx b/src/__test__/components/ContentWrapper.test.jsx
index 08671a2d6d..6fffea04f4 100644
--- a/src/__test__/components/ContentWrapper.test.jsx
+++ b/src/__test__/components/ContentWrapper.test.jsx
@@ -36,7 +36,11 @@ jest.mock('next/router', () => ({
}));
jest.mock('@aws-amplify/auth', () => ({
- currentAuthenticatedUser: jest.fn().mockImplementation(async () => true),
+ currentAuthenticatedUser: jest.fn().mockImplementation(async () => ({
+ attributes: {
+ 'custom:agreed_terms': 'true',
+ },
+ })),
federatedSignIn: jest.fn(),
}));
@@ -124,7 +128,6 @@ describe('ContentWrapper', () => {
await store.dispatch(updateExperimentInfo({ experimentId, experimentName, sampleIds }));
});
- // PROBLEMATIC
it('renders correctly', async () => {
getBackendStatus.mockImplementation(() => () => ({
loading: false,
diff --git a/src/__test__/components/data-management/SamplesTable.test.jsx b/src/__test__/components/data-management/SamplesTable.test.jsx
index 90d83dc85a..4c3ef1cf9c 100644
--- a/src/__test__/components/data-management/SamplesTable.test.jsx
+++ b/src/__test__/components/data-management/SamplesTable.test.jsx
@@ -19,13 +19,19 @@ import thunk from 'redux-thunk';
import createTestComponentFactory from '__test__/test-utils/testComponentFactory';
import { loadExperiments, setActiveExperiment } from 'redux/actions/experiments';
-import loadEnvironment from 'redux/actions/networkResources/loadEnvironment';
+import loadDeploymentInfo from 'redux/actions/networkResources/loadDeploymentInfo';
import { loadSamples } from 'redux/actions/samples';
import mockDemoExperiments from '__test__/test-utils/mockData/mockDemoExperiments.json';
+import { loadUser } from 'redux/actions/user';
jest.mock('@aws-amplify/auth', () => ({
- currentAuthenticatedUser: jest.fn(() => Promise.resolve({ attributes: { name: 'mockUserName' } })),
+ currentAuthenticatedUser: jest.fn(() => Promise.resolve({
+ attributes: {
+ name: 'mockUserName',
+ 'custom:agreed_terms': 'true',
+ },
+ })),
federatedSignIn: jest.fn(),
}));
@@ -103,7 +109,9 @@ describe('Samples table', () => {
// Defaults to project with samples
await storeState.dispatch(setActiveExperiment(experimentWithSamplesId));
- await storeState.dispatch(loadEnvironment('test'));
+ await storeState.dispatch(loadDeploymentInfo({ environment: 'test' }));
+
+ await storeState.dispatch(loadUser());
});
it('Does not show prompt to upload datasets if samples are available', async () => {
diff --git a/src/__test__/components/header/UserButton.test.jsx b/src/__test__/components/header/UserButton.test.jsx
index 39fd2b6716..2a81fe8582 100644
--- a/src/__test__/components/header/UserButton.test.jsx
+++ b/src/__test__/components/header/UserButton.test.jsx
@@ -1,3 +1,5 @@
+import React from 'react';
+
import { screen, render } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { act } from 'react-dom/test-utils';
@@ -6,12 +8,19 @@ import Auth from '@aws-amplify/auth';
import UserButton from 'components/header/UserButton';
import createTestComponentFactory from '__test__/test-utils/testComponentFactory';
+import { Provider } from 'react-redux';
+import { makeStore } from 'redux/store';
+import { loadUser } from 'redux/actions/user';
const UserButtonFactory = createTestComponentFactory(UserButton);
-const renderUserButton = async () => {
+const renderUserButton = async (store) => {
await act(async () => {
- render(UserButtonFactory({}));
+ render(
+
+ {UserButtonFactory(store)}
+ ,
+ );
});
};
@@ -26,18 +35,25 @@ const getLoginButton = () => {
};
describe('UserButton', () => {
+ let store;
+
beforeEach(async () => {
jest.clearAllMocks();
- Auth.currentAuthenticatedUser = jest.fn(() => Promise.resolve({ attributes: { name: userName } }));
+ store = makeStore();
+
+ Auth.currentAuthenticatedUser = jest.fn(() => Promise.resolve({ attributes: { name: userName, 'custom:agreed_terms': 'true' } }));
Auth.signOut = jest.fn(() => { });
Auth.federatedSignIn = jest.fn(() => { });
+
+ store.dispatch(loadUser());
});
it('Shows sign in by default', async () => {
Auth.currentAuthenticatedUser = jest.fn(() => Promise.resolve(null));
+ store.dispatch(loadUser());
- await renderUserButton();
+ await renderUserButton(store);
expect(screen.getByText(/Sign in/i)).toBeInTheDocument();
});
@@ -45,13 +61,13 @@ describe('UserButton', () => {
it('Shows the user initial for the ', async () => {
const userInitial = getUserInitial();
- await renderUserButton();
+ await renderUserButton(store);
expect(screen.getByText(userInitial)).toBeInTheDocument();
});
it('Clicking on menu opens up the menu bar', async () => {
- await renderUserButton();
+ await renderUserButton(store);
const button = getLoginButton();
diff --git a/src/__test__/pages/__snapshots__/_error.test.jsx.snap b/src/__test__/pages/__snapshots__/_error.test.jsx.snap
index aa4ec46aab..dc8a953812 100644
--- a/src/__test__/pages/__snapshots__/_error.test.jsx.snap
+++ b/src/__test__/pages/__snapshots__/_error.test.jsx.snap
@@ -134,6 +134,7 @@ Array [
},
},
"networkResources": Object {
+ "domainName": "scp.biomage.net",
"environment": "production",
},
"samples": Object {
@@ -143,6 +144,9 @@ Array [
"saving": false,
},
},
+ "user": Object {
+ "current": null,
+ },
},
]
`;
@@ -281,6 +285,7 @@ Array [
},
},
"networkResources": Object {
+ "domainName": "scp.biomage.net",
"environment": "staging",
},
"samples": Object {
@@ -290,6 +295,9 @@ Array [
"saving": false,
},
},
+ "user": Object {
+ "current": null,
+ },
},
]
`;
diff --git a/src/__test__/pages/_error.test.jsx b/src/__test__/pages/_error.test.jsx
index 8fba07c472..8358ea18f4 100644
--- a/src/__test__/pages/_error.test.jsx
+++ b/src/__test__/pages/_error.test.jsx
@@ -6,7 +6,8 @@ import { Provider } from 'react-redux';
import { makeStore } from 'redux/store';
import postErrorToSlack from 'utils/postErrorToSlack';
-import loadEnvironment from 'redux/actions/networkResources/loadEnvironment';
+import loadDeploymentInfo from 'redux/actions/networkResources/loadDeploymentInfo';
+import { DomainName } from 'utils/deploymentInfo';
import createTestComponentFactory from '__test__/test-utils/testComponentFactory';
@@ -36,7 +37,7 @@ describe('ErrorPage', () => {
beforeEach(() => {
jest.clearAllMocks();
storeState = makeStore();
- storeState.dispatch(loadEnvironment('production'));
+ storeState.dispatch(loadDeploymentInfo({ environment: 'production', domainName: DomainName.BIOMAGE }));
});
it('Renders properly without props', () => {
@@ -70,7 +71,7 @@ describe('ErrorPage', () => {
});
it('Should post error to Slack if environment is production', () => {
- storeState.dispatch(loadEnvironment('production'));
+ storeState.dispatch(loadDeploymentInfo({ environment: 'production', domainName: DomainName.BIOMAGE }));
renderErrorPage(mockErrorProp, storeState);
@@ -79,7 +80,7 @@ describe('ErrorPage', () => {
});
it('Should post error to Slack if environment is staging', () => {
- storeState.dispatch(loadEnvironment('staging'));
+ storeState.dispatch(loadDeploymentInfo({ environment: 'staging', domainName: DomainName.BIOMAGE }));
renderErrorPage(mockErrorProp, storeState);
@@ -88,7 +89,7 @@ describe('ErrorPage', () => {
});
it('Should not post error to Slack if environment is not production', () => {
- storeState.dispatch(loadEnvironment('development'));
+ storeState.dispatch(loadDeploymentInfo({ environment: 'development', domainName: DomainName.BIOMAGE }));
renderErrorPage(mockErrorProp, storeState);
diff --git a/src/__test__/pages/experiments/[experimentId]/data-management/index.test.jsx b/src/__test__/pages/experiments/[experimentId]/data-management/index.test.jsx
index 412dba3f34..c861cc691b 100644
--- a/src/__test__/pages/experiments/[experimentId]/data-management/index.test.jsx
+++ b/src/__test__/pages/experiments/[experimentId]/data-management/index.test.jsx
@@ -1,7 +1,7 @@
import React from 'react';
import _ from 'lodash';
-import { render, screen, waitFor } from '@testing-library/react';
+import { render, screen } from '@testing-library/react';
import { act } from 'react-dom/test-utils';
import fetchMock, { enableFetchMocks } from 'jest-fetch-mock';
import { Provider } from 'react-redux';
@@ -20,7 +20,8 @@ import DataManagementPage from 'pages/data-management';
import userEvent from '@testing-library/user-event';
import { setActiveExperiment } from 'redux/actions/experiments';
-import loadEnvironment from 'redux/actions/networkResources/loadEnvironment';
+import loadDeploymentInfo from 'redux/actions/networkResources/loadDeploymentInfo';
+import { loadUser } from 'redux/actions/user';
jest.mock('utils/data-management/downloadFromUrl');
jest.mock('react-resize-detector', () => (props) => props.children({ width: 100, height: 100 }));
@@ -34,7 +35,12 @@ jest.mock('utils/AppRouteProvider', () => ({
}));
jest.mock('@aws-amplify/auth', () => ({
- currentAuthenticatedUser: jest.fn(() => Promise.resolve({ attributes: { name: 'mockUserName' } })),
+ currentAuthenticatedUser: jest.fn(() => Promise.resolve({
+ attributes: {
+ name: 'mockUserName',
+ 'custom:agreed_terms': 'true',
+ },
+ })),
federatedSignIn: jest.fn(),
}));
@@ -53,11 +59,6 @@ const experimentWithoutSamples = experiments.find(
(experiment) => experiment.samplesOrder.length === 0,
);
-const expectedSampleNames = [
- 'Example 1',
- 'Another-Example no.2',
-];
-
const experimentWithSamplesId = experimentWithSamples.id;
const experimentWithoutSamplesId = experimentWithoutSamples.id;
@@ -79,7 +80,8 @@ describe('Data Management page', () => {
fetchMock.mockIf(/.*/, mockAPI(mockAPIResponse));
storeState = makeStore();
- storeState.dispatch(loadEnvironment('test'));
+ storeState.dispatch(loadDeploymentInfo({ environment: 'test' }));
+ storeState.dispatch(loadUser());
});
it('Shows an empty project list if there are no projects', async () => {
diff --git a/src/__test__/pages/settings/profile/index.test.jsx b/src/__test__/pages/settings/profile/index.test.jsx
index da30703dee..9e00417160 100644
--- a/src/__test__/pages/settings/profile/index.test.jsx
+++ b/src/__test__/pages/settings/profile/index.test.jsx
@@ -4,10 +4,15 @@ import { render, screen } from '@testing-library/react';
import { act } from 'react-dom/test-utils';
import userEvent from '@testing-library/user-event';
import { useRouter } from 'next/router';
+import { makeStore } from 'redux/store';
import createTestComponentFactory from '__test__/test-utils/testComponentFactory';
import Auth from '@aws-amplify/auth';
import ProfileSettings from 'pages/settings/profile';
import pushNotificationMessage from 'utils/pushNotificationMessage';
+import { Provider } from 'react-redux';
+
+import { loadUser } from 'redux/actions/user';
+import loadDeploymentInfo from 'redux/actions/networkResources/loadDeploymentInfo';
jest.mock('next/router', () => ({
useRouter: jest.fn(),
@@ -16,19 +21,43 @@ jest.mock('next/router', () => ({
jest.mock('@aws-amplify/auth', () => jest.fn());
jest.mock('utils/pushNotificationMessage');
-const profileSettingsPageFactory = createTestComponentFactory(ProfileSettings);
const updateMock = jest.fn(() => Promise.resolve(true));
+const profileSettingsPageFactory = createTestComponentFactory(ProfileSettings);
+
+const renderProfileSettingsPage = (store, newState = {}) => {
+ render(
+
+ {profileSettingsPageFactory(newState)}
+ ,
+ );
+};
+
+const setUpAuthMocks = () => {
+ Auth.currentAuthenticatedUser = jest.fn(() => Promise.resolve({
+ attributes: {
+ name: userName,
+ 'custom:agreed_terms': 'true',
+ },
+ }));
+ Auth.signOut = jest.fn(() => { });
+ Auth.federatedSignIn = jest.fn(() => { });
+ Auth.updateUserAttributes = updateMock;
+};
+
const userName = 'Arthur Dent';
jest.mock('components/Header', () => () => <>>);
describe('Profile page', () => {
+ const store = makeStore();
+
beforeEach(async () => {
jest.clearAllMocks();
- Auth.currentAuthenticatedUser = jest.fn(() => Promise.resolve({ attributes: { name: userName } }));
- Auth.signOut = jest.fn(() => { });
- Auth.federatedSignIn = jest.fn(() => { });
- Auth.updateUserAttributes = updateMock;
+
+ setUpAuthMocks();
+
+ store.dispatch(loadDeploymentInfo({ environment: 'test' }));
+ store.dispatch(loadUser());
});
it('check that the back button is called on cancel', async () => {
@@ -38,9 +67,7 @@ describe('Profile page', () => {
}));
await act(async () => {
- render(
- profileSettingsPageFactory(),
- );
+ renderProfileSettingsPage(store);
});
await act(async () => {
@@ -52,9 +79,7 @@ describe('Profile page', () => {
it('check update is called on Save changes', async () => {
await act(async () => {
- render(
- profileSettingsPageFactory(),
- );
+ renderProfileSettingsPage(store);
});
const nameInput = screen.getByPlaceholderText(userName);
diff --git a/src/__test__/redux/actions/experiments/__snapshots__/switchExperiment.test.js.snap b/src/__test__/redux/actions/experiments/__snapshots__/switchExperiment.test.js.snap
index 02b43dc3d0..e6ef334ab4 100644
--- a/src/__test__/redux/actions/experiments/__snapshots__/switchExperiment.test.js.snap
+++ b/src/__test__/redux/actions/experiments/__snapshots__/switchExperiment.test.js.snap
@@ -183,6 +183,7 @@ Object {
},
},
"networkResources": Object {
+ "domainName": undefined,
"environment": undefined,
},
"samples": Object {
@@ -321,6 +322,9 @@ Object {
"uuid": "test9188-d682-test-mock-cb6d644cmock-2",
},
},
+ "user": Object {
+ "current": null,
+ },
}
`;
@@ -507,6 +511,7 @@ Object {
},
},
"networkResources": Object {
+ "domainName": undefined,
"environment": undefined,
},
"samples": Object {
@@ -645,5 +650,8 @@ Object {
"uuid": "test9188-d682-test-mock-cb6d644cmock-2",
},
},
+ "user": Object {
+ "current": null,
+ },
}
`;
diff --git a/src/__test__/utils/deploymentInfo.test.js b/src/__test__/utils/deploymentInfo.test.js
new file mode 100644
index 0000000000..e1b4181478
--- /dev/null
+++ b/src/__test__/utils/deploymentInfo.test.js
@@ -0,0 +1,100 @@
+import {
+ ssrGetDeploymentInfo, DomainName, privacyPolicyIsNotAccepted, Environment,
+} from 'utils/deploymentInfo';
+
+describe('deploymentInfo', () => {
+ describe('privacyPolicyIsNotAccepted', () => {
+ it('Returns false for users that accepted privacy policy', () => {
+ const user = { attributes: { 'custom:agreed_terms': 'true' } };
+ const domainName = DomainName.BIOMAGE;
+
+ expect(privacyPolicyIsNotAccepted(user, domainName)).toEqual(false);
+ });
+
+ it('Returns false for users that arent in Biomage deployment', () => {
+ const user = { attributes: {} };
+ const domainName = 'Someotherdomain.com';
+
+ expect(privacyPolicyIsNotAccepted(user, domainName)).toEqual(false);
+ });
+
+ it('Returns true for users that still need to accept terms in Biomage', () => {
+ const user = { attributes: {} };
+ const domainName = DomainName.BIOMAGE;
+
+ expect(privacyPolicyIsNotAccepted(user, domainName)).toEqual(true);
+ });
+
+ it('Returns true for users that still need to accept terms in Biomage staging', () => {
+ const user = { attributes: {} };
+ const domainName = DomainName.BIOMAGE_STAGING;
+
+ expect(privacyPolicyIsNotAccepted(user, domainName)).toEqual(true);
+ });
+ });
+
+ describe('ssrGetDeploymentInfo', () => {
+ let originalEnv;
+
+ // We are going to mess with the process env so save the original to avoid leak into other tests
+ beforeAll(() => {
+ originalEnv = { ...process.env };
+ });
+
+ afterAll(() => {
+ process.env = originalEnv;
+ });
+
+ it('Throws if not called in server side', () => {
+ process.env = undefined;
+
+ expect(ssrGetDeploymentInfo).toThrowError(
+ 'ssrGetDeploymentInfo must be called on the server side. Refer to `store.networkResources.environment` for the actual environment.',
+ );
+ });
+
+ it('Works with test node env', () => {
+ process.env = { NODE_ENV: 'test' };
+
+ expect(ssrGetDeploymentInfo()).toEqual({
+ environment: Environment.DEVELOPMENT,
+ domainName: DomainName.BIOMAGE,
+ });
+ });
+
+ it('Works with prod k8s env in biomage domain', () => {
+ process.env = {
+ NODE_ENV: Environment.PRODUCTION,
+ K8S_ENV: Environment.PRODUCTION,
+ DOMAIN_NAME: DomainName.BIOMAGE,
+ };
+
+ expect(ssrGetDeploymentInfo()).toEqual({
+ environment: Environment.PRODUCTION,
+ domainName: DomainName.BIOMAGE,
+ });
+ });
+
+ it('Works with staging k8s env in biomage staging domain', () => {
+ process.env = {
+ NODE_ENV: Environment.PRODUCTION,
+ K8S_ENV: Environment.STAGING,
+ DOMAIN_NAME: DomainName.BIOMAGE_STAGING,
+ };
+
+ expect(ssrGetDeploymentInfo()).toEqual({
+ environment: Environment.STAGING,
+ domainName: DomainName.BIOMAGE_STAGING,
+ });
+ });
+
+ it('Works in development', () => {
+ process.env = { NODE_ENV: Environment.DEVELOPMENT };
+
+ expect(ssrGetDeploymentInfo()).toEqual({
+ environment: Environment.DEVELOPMENT,
+ domainName: DomainName.BIOMAGE,
+ });
+ });
+ });
+});
diff --git a/src/__test__/utils/work/fetchWork.test.js b/src/__test__/utils/work/fetchWork.test.js
index 1b4cab5745..63b04e58da 100644
--- a/src/__test__/utils/work/fetchWork.test.js
+++ b/src/__test__/utils/work/fetchWork.test.js
@@ -1,6 +1,6 @@
/* eslint-disable global-require */
import { fetchWork } from 'utils/work/fetchWork';
-import Environment from 'utils/environment';
+import { Environment } from 'utils/deploymentInfo';
const {
mockGeneExpressionData,
diff --git a/src/components/ContentWrapper.jsx b/src/components/ContentWrapper.jsx
index fbdd09ff09..76dd869997 100644
--- a/src/components/ContentWrapper.jsx
+++ b/src/components/ContentWrapper.jsx
@@ -17,8 +17,6 @@ import {
} from 'antd';
import { modules } from 'utils/constants';
-import Auth from '@aws-amplify/auth';
-
import { useAppRouter } from 'utils/AppRouteProvider';
import calculateGem2sRerunStatus from 'utils/data-management/calculateGem2sRerunStatus';
@@ -29,22 +27,22 @@ import PreloadContent from 'components/PreloadContent';
import experimentUpdatesHandler from 'utils/experimentUpdatesHandler';
import { getBackendStatus } from 'redux/selectors';
import { loadBackendStatus } from 'redux/actions/backendStatus';
-import { isBrowser } from 'utils/environment';
+import { isBrowser, privacyPolicyIsNotAccepted } from 'utils/deploymentInfo';
import Error from 'pages/_error';
import integrationTestConstants from 'utils/integrationTestConstants';
import pipelineStatus from 'utils/pipelineStatusValues';
import BrowserAlert from 'components/BrowserAlert';
+import { loadUser } from 'redux/actions/user';
+import PrivacyPolicyIntercept from './data-management/PrivacyPolicyIntercept';
-const { Sider, Footer } = Layout;
-
-const { Paragraph, Text } = Typography;
+const { Sider } = Layout;
+const { Text } = Typography;
const ContentWrapper = (props) => {
const dispatch = useDispatch();
- const [isAuth, setIsAuth] = useState(false);
const [collapsed, setCollapsed] = useState(false);
const { routeExperimentId, experimentData, children } = props;
@@ -54,6 +52,9 @@ const ContentWrapper = (props) => {
const activeExperimentId = useSelector((state) => state?.experiments?.meta?.activeExperimentId);
const activeExperiment = useSelector((state) => state.experiments[activeExperimentId]);
+ const domainName = useSelector((state) => state.networkResources.domainName);
+ const user = useSelector((state) => state.user.current);
+
const samples = useSelector((state) => state.samples);
useEffect(() => {
@@ -138,15 +139,10 @@ const ContentWrapper = (props) => {
}, [gem2sBackendStatus, activeExperiment, samples, experiment]);
useEffect(() => {
- Auth.currentAuthenticatedUser()
- .then(() => setIsAuth(true))
- .catch(() => {
- setIsAuth(false);
- Auth.federatedSignIn();
- });
+ dispatch(loadUser());
}, []);
- if (!isAuth) return <>>;
+ if (!user) return <>>;
const BigLogo = () => (
{
);
};
+
+ if (!user) return <>>;
+
return (
<>
+ {privacyPolicyIsNotAccepted(user, domainName) && (
+
dispatch(loadUser())} />
+ )}
{
const dispatch = useDispatch();
- const environment = useSelector((state) => state?.networkResources?.environment);
+ const {
+ environment = undefined, domainName = undefined,
+ } = useSelector((state) => state?.networkResources ?? {});
+
+ const user = useSelector((state) => state?.user?.current);
const [exampleExperiments, setExampleExperiments] = useState([]);
useEffect(() => {
- if (!environment) return;
+ if (!environment || privacyPolicyIsNotAccepted(user, domainName)) return;
fetchAPI('/v2/experiments/examples').then((experiments) => {
setExampleExperiments(experiments);
}).catch(() => { });
- }, [environment]);
+ }, [environment, user]);
const cloneIntoCurrentExperiment = async (exampleExperimentId) => {
const url = `/v2/experiments/${exampleExperimentId}/clone`;
diff --git a/src/components/data-management/PrivacyPolicyIntercept.css b/src/components/data-management/PrivacyPolicyIntercept.css
new file mode 100644
index 0000000000..5103d2fd38
--- /dev/null
+++ b/src/components/data-management/PrivacyPolicyIntercept.css
@@ -0,0 +1,4 @@
+.ok-to-the-right-modal .ant-modal-confirm-btns .ant-btn {
+ float: right;
+ margin-left: 10px;
+}
\ No newline at end of file
diff --git a/src/components/data-management/PrivacyPolicyIntercept.jsx b/src/components/data-management/PrivacyPolicyIntercept.jsx
new file mode 100644
index 0000000000..b1c0116434
--- /dev/null
+++ b/src/components/data-management/PrivacyPolicyIntercept.jsx
@@ -0,0 +1,99 @@
+import React, { useState } from 'react';
+import PropTypes from 'prop-types';
+
+import Auth from '@aws-amplify/auth';
+
+import {
+ Modal, Space, Checkbox, Typography,
+} from 'antd';
+
+import 'components/data-management/PrivacyPolicyIntercept.css';
+
+import pushNotificationMessage from 'utils/pushNotificationMessage';
+import endUserMessages from 'utils/endUserMessages';
+
+const { Text } = Typography;
+
+const agreedPrivacyPolicyKey = 'custom:agreed_terms';
+const agreedEmailsKey = 'custom:agreed_emails';
+
+const PrivacyPolicyIntercept = (props) => {
+ const { user, onOk } = props;
+
+ const {
+ attributes: {
+ [agreedPrivacyPolicyKey]: originalAgreedPrivacyPolicy,
+ [agreedEmailsKey]: originalAgreedEmails,
+ },
+ } = user;
+
+ const [agreedPrivacyPolicy, setAgreedPrivacyPolicy] = useState(originalAgreedPrivacyPolicy);
+ const [agreedEmails, setAgreedEmails] = useState(originalAgreedEmails ?? 'false');
+
+ const privacyPolicyUrl = 'https://static1.squarespace.com/static/5f355513fc75aa471d47455c/t/62d67b8cbd2d7f3177d91f83/1658223501108/Privacy+Policy_July+2022.pdf';
+
+ return (
+ {
+ await Auth.updateUserAttributes(
+ user,
+ {
+ [agreedPrivacyPolicyKey]: agreedPrivacyPolicy,
+ [agreedEmailsKey]: agreedEmails,
+ },
+ )
+ .then(() => {
+ pushNotificationMessage('success', endUserMessages.ACCOUNT_DETAILS_UPDATED, 3);
+ onOk();
+ })
+ .catch(() => pushNotificationMessage('error', endUserMessages.ERROR_SAVING, 3));
+ }}
+ onCancel={async () => Auth.signOut()}
+ >
+
+
+ setAgreedPrivacyPolicy(e.target.checked.toString())}
+ />
+
+ *
+ I accept the terms of the
+ {' '}
+ Biomage privacy policy
+ .
+
+
+
+ setAgreedEmails(e.target.checked.toString())}
+ style={{ marginRight: 10 }}
+ />
+
+ I agree to receive updates about new features in Cellenics,
+ research done with Cellenics, and Cellenics community events. (No external marketing.)
+
+
+
+
+ );
+};
+
+PrivacyPolicyIntercept.propTypes = {
+ user: PropTypes.object.isRequired,
+ onOk: PropTypes.func.isRequired,
+};
+
+PrivacyPolicyIntercept.defaultProps = {};
+
+export default PrivacyPolicyIntercept;
diff --git a/src/components/header/UserButton.jsx b/src/components/header/UserButton.jsx
index a64c307f7e..f31793940c 100644
--- a/src/components/header/UserButton.jsx
+++ b/src/components/header/UserButton.jsx
@@ -1,4 +1,4 @@
-import React, { useEffect, useState } from 'react';
+import React, { useEffect } from 'react';
import {
Avatar,
Button,
@@ -11,24 +11,23 @@ import Auth from '@aws-amplify/auth';
import endUserMessages from 'utils/endUserMessages';
import { resetTrackingId } from 'utils/tracking';
import handleError from 'utils/http/handleError';
+import { loadUser } from 'redux/actions/user';
+import { useDispatch, useSelector } from 'react-redux';
const UserButton = () => {
- const [user, setUser] = useState();
+ const dispatch = useDispatch();
- const getUser = () => Auth.currentAuthenticatedUser()
- .then((userData) => userData)
- .catch((e) => console.log('error during getuser', e));
+ const user = useSelector((state) => state.user.current);
useEffect(() => {
Hub.listen('auth', ({ payload: { event } }) => {
switch (event) {
case 'signIn':
case 'cognitoHostedUI':
- getUser().then((userData) => setUser(userData));
+ dispatch(loadUser());
break;
case 'signOut':
resetTrackingId();
- setUser(null);
break;
case 'signIn_failure':
case 'cognitoHostedUI_failure':
@@ -38,13 +37,11 @@ const UserButton = () => {
break;
}
});
-
- getUser().then((userData) => setUser(userData));
}, []);
const content = () => (