Skip to content
This repository has been archived by the owner on Apr 4, 2023. It is now read-only.

Commit

Permalink
[#169647035] added registration page 3
Browse files Browse the repository at this point in the history
added react-cookie to manage session token and remove token context
added consts for long boolean conditions
added todo comments for api generated classes use
remove custom method and added FileSave package to manage documents download
  • Loading branch information
d-al-ibm committed Nov 14, 2019
1 parent 03840d0 commit 5069460
Show file tree
Hide file tree
Showing 9 changed files with 1,659 additions and 1,944 deletions.
5 changes: 4 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
"devDependencies": {
"@types/enzyme": "^3.1.12",
"@types/enzyme-adapter-react-16": "^1.0.2",
"@types/file-saver": "^2.0.1",
"@types/fs-extra": "^5.0.4",
"@types/jest": "^24.0.13",
"@types/js-yaml": "^3.11.2",
Expand All @@ -44,7 +45,7 @@
"jest": "^24.8.0",
"js-yaml": "^3.13.1",
"json-server": "^0.15.1",
"parcel-bundler": "^1.12.3",
"parcel-bundler": "^1.12.4",
"prettier": "^1.12.1",
"react-test-renderer": "^16.8.6",
"rimraf": "^2.6.2",
Expand All @@ -62,6 +63,7 @@
"bootstrap": "^4.3.1",
"bootstrap-italia": "^1.3.2",
"chart.js": "^2.8.0",
"file-saver": "^2.0.2",
"fp-ts": "1.12.0",
"i18next": "^17.0.17",
"i18next-browser-languagedetector": "^3.0.3",
Expand All @@ -70,6 +72,7 @@
"react": "^16.8.6",
"react-app-polyfill": "^1.0.3",
"react-bootstrap-typeahead": "^3.4.6",
"react-cookie": "^4.0.1",
"react-dom": "^16.8.6",
"react-i18next": "^10.13.1",
"react-router-config": "^5.0.1",
Expand Down
59 changes: 18 additions & 41 deletions src/components/DefaultContainer/DefaultContainer.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { NonEmptyString } from "italia-ts-commons/lib/strings";
import React, { Fragment, useContext, useEffect, useState } from "react";
import { useCookies } from "react-cookie";
import { Route, RouteComponentProps, withRouter } from "react-router";
import { EmailAddress } from "../../../generated/definitions/api/EmailAddress";
import { FiscalCode } from "../../../generated/definitions/api/FiscalCode";
import { UserProfile } from "../../../generated/definitions/api/UserProfile";
import { UserRole } from "../../../generated/definitions/api/UserRole";
import { LoadingPageContext } from "../../context/loading-page-context";
import { TokenContext } from "../../context/token-context";
import { ICustomWindow } from "../../customTypes/CustomWindow";
import { AppAlert } from "../AppAlert/AppAlert";
import { CentralHeader } from "../CentralHeader/CentralHeader";
Expand Down Expand Up @@ -34,10 +34,10 @@ interface IDefaultContainerUserProfileState {
* Component containing slim header, central header and app body with second level routing
*/
export const DefaultContainer = withRouter(props => {
const tokenContext = useContext(TokenContext);

const loadingPageContext = useContext(LoadingPageContext);

const [cookies] = useCookies(["sessionToken"]);

/**
* Create window with custom element _env_ for environment variables
*/
Expand Down Expand Up @@ -84,62 +84,39 @@ export const DefaultContainer = withRouter(props => {
setIsVisibleAddMailModal((prevState: boolean) => !prevState);
};

/**
* Given a cookie key `cookieName`, returns the value of
* the cookie or empty string, if the key is not found.
*/
function getCookie(cookieName: string): string {
return (
document.cookie
.split(";")
.map(c => c.trim())
.filter(cookie => {
return (
cookie.substring(0, cookieName.length + 1) === `${cookieName}=`
);
})
.map(cookie => {
return decodeURIComponent(cookie.substring(cookieName.length + 1));
})[0] || ""
);
}

/**
* Set token in token context
*/
useEffect(() => {
const token = getCookie("sessionToken");
// if getCookie returns an empty string and the user is not in pre login page (where token still has to be set),
// it means the token has expired and user browser deleted it -> redirect user to login, otherwise set tokenContext.token
if (
NonEmptyString.is(token) ||
location.pathname === "/spid-login" ||
customWindow._env_.IO_ONBOARDING_PA_IS_MOCK_ENV === "1"
) {
tokenContext.setToken(token);
}
// TODO: when available, redirect to logout page (tracked in story https://www.pivotaltracker.com/story/show/169033467)
else {
// if cookies does not contain sessionToken prop and the user is not in pre login page (where token still has to be set),
// it means the token has expired and browser deleted it -> redirect user to login
// TODO: when available, show logout modal (tracked in story https://www.pivotaltracker.com/story/show/169033467)
const isTokenExpired =
!cookies.sessionToken &&
location.pathname !== "/spid-login" &&
customWindow._env_.IO_ONBOARDING_PA_IS_MOCK_ENV !== "1";
if (isTokenExpired) {
props.history.push("/home");
}
}, [location.pathname]);

useEffect(() => {
// make api call only after onMount because token is string in any case, no longer undefined, and only if userProfile is not set and user is not on spid login page
if (
NonEmptyString.is(tokenContext.token) &&
const isTokenValidAndUserProfileUnset =
NonEmptyString.is(cookies.sessionToken) &&
!NonEmptyString.is(userProfile.given_name) &&
location.pathname !== "/spid-login"
) {
location.pathname !== "/spid-login";
if (isTokenValidAndUserProfileUnset) {
const url =
customWindow._env_.IO_ONBOARDING_PA_API_HOST +
":" +
customWindow._env_.IO_ONBOARDING_PA_API_PORT +
"/profile";
// TODO: use generated classes for api (tracked in story https://www.pivotaltracker.com/story/show/169454440
fetch(url, {
headers: {
Accept: "application/json",
Authorization: `Bearer ${tokenContext.token}`
Authorization: `Bearer ${cookies.sessionToken}`
// 'Content-Type': 'application/json'
},
method: "GET"
Expand All @@ -158,7 +135,7 @@ export const DefaultContainer = withRouter(props => {
return error;
});
}
}, [tokenContext.token]);
}, [cookies.sessionToken]);

const navigateToRegistration = (registrationProps: RouteComponentProps) => (
<RegistrationContainer
Expand Down
6 changes: 3 additions & 3 deletions src/components/Home/Home.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@ export const Home = () => {
/**
* array containing three login elements props
*/
const homeLoginButtonsDataArray: ReadonlyArray<
ComponentProps<typeof HomeLoginButton>
> = [
const homeLoginButtonsDataArray: ReadonlyArray<ComponentProps<
typeof HomeLoginButton
>> = [
{
buttonText: t("common.user.roles.developer"),
img: logoHomeDev,
Expand Down
6 changes: 3 additions & 3 deletions src/components/Modal/AddMailModal.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { NonEmptyString } from "italia-ts-commons/lib/strings";
import React, { ChangeEvent, MouseEvent, useContext, useState } from "react";
import { useCookies } from "react-cookie";
import { useTranslation } from "react-i18next";
import {
Button,
Expand All @@ -16,7 +17,6 @@ import {
} from "reactstrap";
import { EmailAddress } from "../../../generated/definitions/api/EmailAddress";
import { AlertContext } from "../../context/alert-context";
import { TokenContext } from "../../context/token-context";
import { ICustomWindow } from "../../customTypes/CustomWindow";

interface IAddMailModalProps {
Expand Down Expand Up @@ -48,7 +48,7 @@ export const AddMailModal = (props: IAddMailModalProps) => {

const contentType = "application/json";

const tokenContext = useContext(TokenContext);
const [cookies] = useCookies(["sessionToken"]);
const alertContext = useContext(AlertContext);

const [newMail, setNewMail] = useState("");
Expand Down Expand Up @@ -81,7 +81,7 @@ export const AddMailModal = (props: IAddMailModalProps) => {
body: JSON.stringify({ work_email: newUserMail as EmailAddress }),
headers: {
Accept: contentType,
Authorization: `Bearer ${tokenContext.token ? tokenContext.token : ""}`,
Authorization: `Bearer ${cookies.sessionToken}`,
"Content-Type": contentType
},
method: "PUT"
Expand Down
14 changes: 6 additions & 8 deletions src/components/Registration/RegistrationContainer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ import { RegistrationStepTwo } from "./RegistrationStepTwo/RegistrationStepTwo";

import { OrganizationRegistrationParams } from "../../../generated/definitions/api/OrganizationRegistrationParams";
import { LoadingPageContext } from "../../context/loading-page-context";
import { TokenContext } from "../../context/token-context";

import { useCookies } from "react-cookie";
import documentCreationLoadingPageImage from "../../assets/img/document_generation.svg";

interface IRegistrationContainerProps
Expand All @@ -52,7 +52,7 @@ export const RegistrationContainer = withRouter(

const contentType = "application/json";

const tokenContext = useContext(TokenContext);
const [cookies] = useCookies(["sessionToken"]);

const loadingPageContext = useContext(LoadingPageContext);

Expand Down Expand Up @@ -90,12 +90,11 @@ export const RegistrationContainer = withRouter(
const handleAdministrationSearch = (searchString: string) => {
const url =
urlDomainPort + `/public-administrations?search=${searchString}`;
// TODO: use generated classes for api (tracked in story https://www.pivotaltracker.com/story/show/169454440)
fetch(url, {
headers: {
Accept: contentType,
Authorization: `Bearer ${
tokenContext.token ? tokenContext.token : ""
}`
Authorization: `Bearer ${cookies.sessionToken}`
},
method: "GET"
})
Expand Down Expand Up @@ -185,13 +184,12 @@ export const RegistrationContainer = withRouter(
organizationRegistrationParams: OrganizationRegistrationParams
) => {
const url = urlDomainPort + "/organizations";
// TODO: use generated classes for api (tracked in story https://www.pivotaltracker.com/story/show/169454440)
fetch(url, {
body: JSON.stringify(organizationRegistrationParams),
headers: {
Accept: contentType,
Authorization: `Bearer ${
tokenContext.token ? tokenContext.token : ""
}`,
Authorization: `Bearer ${cookies.sessionToken}`,
"Content-Type": contentType
},
method: "POST"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import React, { ComponentProps, Fragment, MouseEvent, useContext } from "react";
import * as FileSaver from "file-saver";
import React, { ComponentProps, Fragment, MouseEvent } from "react";
import { useCookies } from "react-cookie";
import { useTranslation } from "react-i18next";
import {
Button,
Expand All @@ -12,7 +14,6 @@ import {
Row
} from "reactstrap";
import logoSignupStepThree from "../../../assets/img/signup_step3.svg";
import { TokenContext } from "../../../context/token-context";
import { ICustomWindow } from "../../../customTypes/CustomWindow";
import { SearchAdministrations } from "../RegistrationStepOne/SearchAdministrations";

Expand Down Expand Up @@ -51,45 +52,21 @@ const DownloadDocsSection = (props: IDocumentDownloadSectionProps) => {
":" +
customWindow._env_.IO_ONBOARDING_PA_API_PORT;

const tokenContext = useContext(TokenContext);

const showFile = (blob: Blob, documentName: string) => {
// It is necessary to create a new blob object with mime-type explicitly set
// otherwise only Chrome works like it should
const newBlob = new Blob([blob], { type: "application/pdf" });

// IE doesn't allow using a blob object directly as link href
// instead it is necessary to use msSaveOrOpenBlob
if (window.navigator && window.navigator.msSaveOrOpenBlob) {
window.navigator.msSaveOrOpenBlob(newBlob);
return;
}

// For other browsers:
// Create a link pointing to the ObjectURL containing the blob.
const data = window.URL.createObjectURL(newBlob);
const link = document.createElement("a");
link.setAttribute("href", data);
link.setAttribute("download", documentName);
link.click();
setTimeout(() => {
// For Firefox it is necessary to delay revoking the ObjectURL
window.URL.revokeObjectURL(data);
}, 100);
};
const [cookies] = useCookies(["sessionToken"]);

const downloadDocument = () => (_: MouseEvent) => {
const url =
urlDomainPort +
`/organizations/${props.ipaCode}/documents/${props.documentName}`;
// TODO: use generated classes for api (tracked in story https://www.pivotaltracker.com/story/show/169454440)
fetch(url, {
headers: {
Authorization: `Bearer ${tokenContext.token ? tokenContext.token : ""}`
Authorization: `Bearer ${cookies.sessionToken}`
},
method: "GET"
})
.then(response => response.blob())
.then(blob => showFile(blob, props.documentName))
.then(blob => FileSaver.saveAs(blob, props.documentName))
.catch(error => error);
};

Expand Down Expand Up @@ -128,9 +105,9 @@ export const RegistrationStepThree = (props: IRegistrationStepThreeProps) => {
/**
* array containing two documents download sections props
*/
const downloadDocsSectionsDataArray: ReadonlyArray<
ComponentProps<typeof DownloadDocsSection>
> = [
const downloadDocsSectionsDataArray: ReadonlyArray<ComponentProps<
typeof DownloadDocsSection
>> = [
{
documentName: "contract.pdf",
documentType: "contract",
Expand Down
31 changes: 0 additions & 31 deletions src/context/token-context.tsx

This file was deleted.

14 changes: 7 additions & 7 deletions src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,19 @@ import { render } from "react-dom";

import "./i18n";

import { CookiesProvider } from "react-cookie";
import { App } from "./App";
import { AlertContextProvider } from "./context/alert-context";
import { LoadingPageContextProvider } from "./context/loading-page-context";
import { TokenContextProvider } from "./context/token-context";

const app = (
<TokenContextProvider>
<AlertContextProvider>
<LoadingPageContextProvider>
<AlertContextProvider>
<LoadingPageContextProvider>
<CookiesProvider>
<App />
</LoadingPageContextProvider>
</AlertContextProvider>
</TokenContextProvider>
</CookiesProvider>
</LoadingPageContextProvider>
</AlertContextProvider>
);

render(app, document.getElementById("root"));
Loading

0 comments on commit 5069460

Please sign in to comment.