diff --git a/.env b/.env-template
similarity index 100%
rename from .env
rename to .env-template
diff --git a/public/icons/download-2.svg b/public/icons/download-2.svg
deleted file mode 100644
index bdfae70b..00000000
--- a/public/icons/download-2.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-
-
diff --git a/src/components/layers-panel/layers-control-panel.tsx b/src/components/layers-panel/layers-control-panel.tsx
index d0e86707..b6f13f6d 100644
--- a/src/components/layers-panel/layers-control-panel.tsx
+++ b/src/components/layers-panel/layers-control-panel.tsx
@@ -1,24 +1,20 @@
-import { Fragment, ReactEventHandler, useState, useEffect } from "react";
+import { Fragment, ReactEventHandler, useState } from "react";
import styled from "styled-components";
-
import { SelectionState, LayerExample, LayerViewState, ListItemType } from "../../types";
-
import { ListItem } from "./list-item/list-item";
import PlusIcon from "../../../public/icons/plus.svg";
import ImportIcon from "../../../public/icons/import.svg";
import EsriImage from "../../../public/images/esri.svg";
import { ActionIconButton } from "../action-icon-button/action-icon-button";
import { AcrGisUser } from "../arcgis-user/arcgis-user";
-
import { DeleteConfirmation } from "./delete-confirmation";
import { LayerOptionsMenu } from "./layer-options-menu/layer-options-menu";
import { handleSelectAllLeafsInGroup } from "../../utils/layer-utils";
import { ButtonSize } from "../../types";
import { PanelHorizontalLine } from "../common";
-
-
import { arcGisLogin, arcGisLogout, selectUser } from "../../redux/slices/arcgis-auth-slice";
import { useAppDispatch, useAppSelector } from "../../redux/hooks";
+import { ModalDialog } from "../modal-dialog/modal-dialog";
type LayersControlPanelProps = {
layers: LayerExample[];
@@ -86,37 +82,18 @@ export const LayersControlPanel = ({
deleteLayer,
}: LayersControlPanelProps) => {
- // stub {
- // const dispatch = useAppDispatch();
-
- // const handleArcGisLogin = () => {
- // dispatch(arcGisLogin());
- // };
-
- // const handleArcGisLogout = () => {
- // dispatch(arcGisLogout());
- // };
-
- // const username = useAppSelector(selectUser);
- // const [showLogin, setShowLoginButton] = useState(!username);
- // const [showLogout, setShowLogoutButton] = useState(!!username);
-
- // useEffect(() => {
- // setShowLoginButton(!username);
- // setShowLogoutButton(!!username);
- // }, [username]);
-// stub }
+ const dispatch = useAppDispatch();
+ const username = useAppSelector(selectUser);
+ const isLoggedIn = !!username;
+
+ const [showLogoutWarning, setShowLogoutWarning] = useState(false);
const [settingsLayerId, setSettingsLayerId] = useState("");
const [showLayerSettings, setShowLayerSettings] = useState(false);
const [layerToDeleteId, setLayerToDeleteId] = useState("");
- /// Stab {
- const username = 'Michael-g';
- const [isLoggedIn, setIsLoggedIn] = useState(false);
- const onArcGisActionClick = () => { !isLoggedIn && setIsLoggedIn(true) };
- const onArcGisLogoutClick = () => { setIsLoggedIn(false) };
- /// Stab }
+ const onArcGisActionClick = () => { !isLoggedIn && dispatch(arcGisLogin()); };
+ const onArcGisLogoutClick = () => { setShowLogoutWarning(true); };
const isListItemSelected = (
layer: LayerExample,
@@ -150,6 +127,38 @@ export const LayersControlPanel = ({
return selectedState;
};
+ const TextQuestion = styled.div`
+ font-style: normal;
+ font-weight: 500;
+ font-size: 16px;
+ line-height: 19px;
+`;
+
+ const TextInfo = styled.div`
+ font-style: normal;
+ font-weight: 700;
+ font-size: 16px;
+ line-height: 19px;
+`;
+
+ const renderModalDialogContent = (): JSX.Element => {
+ return (
+ <>
+
+ Are you sure you want to log out?
+
+
+
+ You are logged in as
+
+
+
+ {username}
+
+ >
+ );
+ }
+
const renderLayers = (
layers: LayerExample[],
parentLayer?: LayerExample,
@@ -245,6 +254,22 @@ export const LayersControlPanel = ({
{username}
)}
+
+ {showLogoutWarning && (
+ {
+ dispatch(arcGisLogout());
+ setShowLogoutWarning(false);
+ }}
+ onCancel={() => { setShowLogoutWarning(false); }}
+ />
+ )}
+
);
diff --git a/src/components/modal-dialog/modal-dialog.tsx b/src/components/modal-dialog/modal-dialog.tsx
new file mode 100644
index 00000000..100936f9
--- /dev/null
+++ b/src/components/modal-dialog/modal-dialog.tsx
@@ -0,0 +1,142 @@
+import styled, { useTheme } from "styled-components";
+import { ActionButton } from "../action-button/action-button";
+import { ActionButtonVariant, LayoutProps } from "../../types";
+import CloseIcon from "../../../public/icons/close.svg";
+import { Popover } from "react-tiny-popover";
+
+const Overlay = styled.div`
+ width: 100%;
+ height: 100%;
+ position: absolute;
+ left: 0;
+ top: 0;
+ z-index: 103;
+ background: #00000099;
+ `;
+
+const Container = styled.div<{ width: number, height: number }>`
+ position: absolute;
+ display: flex;
+ flex-direction: column;
+ border-radius: 8px;
+ background: ${({ theme }) => theme.colors.mainColor};
+ width: ${({ width }) => (`${width}px`)};
+ height: ${({ height }) => (`${height}px`)};
+ left: calc(50% - ${({ width }) => (`${width * 0.5}px`)} );
+ top: calc(50% - ${({ height }) => (`${height * 0.5}px`)} );
+ z-index: 104;
+ `;
+
+const IconContainer = styled.div`
+ position: absolute;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ border-radius: 8px;
+ width: 44px;
+ height: 44px;
+ top: 13px;
+ right: 14px;
+ `;
+
+const ContentContainer = styled.div`
+ display: flex;
+ flex-direction: column;
+ justify-content: start;
+ height: 100%;
+ width: 100%;
+ margin: 32px 32px 0 32px;
+ row-gap: 16px;
+ color: ${({ theme }) => theme.colors.fontColor};
+`;
+
+const Title = styled.div`
+ font-style: normal;
+ font-weight: 700;
+ font-size: 32px;
+ line-height: 45px;
+`;
+
+const ButtonsContainer = styled.div`
+ display: flex;
+ flex-direction: row;
+ justify-content: center; //space-between;
+ margin: 32px;
+ column-gap: 18px;
+ { > *
+ {
+ width: 180px;
+ }
+ }
+`;
+
+type LogoutPanelProps = {
+ title: string;
+ content: (() => JSX.Element) | JSX.Element;
+ width: number,
+ height: number,
+ onCancel: () => void;
+ onConfirm: () => void;
+};
+
+const CloseCrossButton = styled(CloseIcon)`
+ &:hover {
+ fill: ${({ theme }) => theme.colors.mainDimColorInverted};
+ }
+ `;
+
+export const ModalDialog = ({
+ title,
+ content,
+ width,
+ height,
+ onCancel,
+ onConfirm,
+}: LogoutPanelProps) => {
+ const theme = useTheme();
+
+ const renderPopoverContent = (): JSX.Element => {
+ return (
+ <>
+
+
+
+
+
+
+ {title}
+ {typeof content === 'function' ? content() : content}
+
+
+
+ Cancel
+
+ Log out
+
+
+ >
+ );
+ }
+
+ const getPopoverStyle = () => {
+ return {
+ zIndex: "104",
+ width: "100%",
+ height: "100%"
+ };
+ };
+
+ return (
+
+ <>>
+
+ );
+};
diff --git a/src/pages/arcgis-auth-popup/arcgis-auth-popup.tsx b/src/pages/arcgis-auth-popup/arcgis-auth-popup.tsx
index e55891fe..28ec358c 100644
--- a/src/pages/arcgis-auth-popup/arcgis-auth-popup.tsx
+++ b/src/pages/arcgis-auth-popup/arcgis-auth-popup.tsx
@@ -5,8 +5,7 @@ import {
useAppLayout,
} from "../../utils/hooks/layout";
-import { ArcGISIdentityManager } from '@esri/arcgis-rest-request';
-import { getAuthOptions } from "../../utils/arcgis-auth";
+import { arcGisCompleteLogin } from "../../utils/arcgis-auth";
export type LayoutProps = {
layout: string;
@@ -37,22 +36,10 @@ const AuthContainer = styled.div`
export const AuthApp = () => {
const layout = useAppLayout();
-
- const { redirectUrl, clientId } = getAuthOptions();
- if (!clientId) {
- console.error("The ClientId is not defined in .env file.");
- } else {
- const options = {
- clientId: clientId,
- redirectUri: redirectUrl,
- popup: true,
- pkce: true
- }
- ArcGISIdentityManager.completeOAuth2(options);
- }
+ arcGisCompleteLogin();
return (
);
-
-}
\ No newline at end of file
+
+}
diff --git a/src/redux/store.ts b/src/redux/store.ts
index 51c1ffe5..4b5b407d 100644
--- a/src/redux/store.ts
+++ b/src/redux/store.ts
@@ -22,7 +22,6 @@ const rootReducer = combineReducers({
symbolization: symbolizationSliceReducer,
i3sStats: i3sStatsSliceReducer,
arcGisAuth: arcGisAuthSliceReducer,
-
});
export const setupStore = (preloadedState?: PreloadedState) => {
diff --git a/src/utils/arcgis-auth.ts b/src/utils/arcgis-auth.ts
index b4cad034..a6921493 100644
--- a/src/utils/arcgis-auth.ts
+++ b/src/utils/arcgis-auth.ts
@@ -17,15 +17,32 @@ const updateSessionInfo = async (session?: ArcGISIdentityManager): Promise {
- return {
- redirectUrl: `${window.location.protocol}//${window.location.hostname}:${window.location.port}/auth`,
- clientId: process.env.REACT_APP_ARCGIS_REST_CLIENT_ID
+const getAuthOptions = () => {
+ const port = window.location.port ? `:${window.location.port}` : '';
+ const options = {
+ redirectUri: `${window.location.protocol}//${window.location.hostname}${port}/auth`,
+ clientId: process.env.REACT_APP_ARCGIS_REST_CLIENT_ID || '',
+ popup: true,
+ pkce: true
+ };
+
+ if (!options.clientId) {
+ console.error("The ClientId is not defined in .env file.");
}
+ return options;
}
/**
@@ -37,40 +54,45 @@ export const getAuthenticatedUser = (): string => {
}
/**
- * Makes a ArcGIS login request by opening a popup dialog.
+ * Makes an ArcGIS login request by opening a popup dialog.
* @returns email of the user logged in or an empty string if the user is not logged in.
*/
export const arcGisRequestLogin = async () => {
- const { redirectUrl, clientId } = getAuthOptions();
-
- if (!clientId) {
- console.error("The ClientId is not defined in .env file.");
- return '';
- }
- const options = {
- clientId: clientId,
- redirectUri: redirectUrl,
- popup: true,
- pkce: true
- }
-
let email = '';
- let session: ArcGISIdentityManager | undefined;
- try {
- session = await ArcGISIdentityManager.beginOAuth2(options);
- }
- finally {
- // In case of an exception the session is not set.
- // So the following call will remove any session stored in the local storage.
- email = await updateSessionInfo(session);
+
+ const options = getAuthOptions();
+ if (options.clientId) {
+ let session: ArcGISIdentityManager | undefined;
+ try {
+ session = await ArcGISIdentityManager.beginOAuth2(options);
+ }
+ finally {
+ // In case of an exception the session is not set.
+ // So the following call will remove any session stored in the local storage.
+ email = await updateSessionInfo(session);
+ }
}
return email;
};
/**
- * Makes a ArcGIS logout request.
+ * Completes the ArcGIS login request started by {@link arcGisRequestLogin}.
+ */
+export const arcGisCompleteLogin = async () => {
+ const options = getAuthOptions();
+ if (options.clientId) {
+ ArcGISIdentityManager.completeOAuth2(options);
+ }
+}
+
+/**
+ * Makes an ArcGIS logout request.
* @returns empty string
*/
export const arcGisRequestLogout = async () => {
+ const session = getArcGisSession();
+ if (session) {
+ await ArcGISIdentityManager.destroy(session);
+ }
return await updateSessionInfo();
};