@databiosphere/findable-ui 21.3.0 → 21.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.release-please-manifest.json +1 -1
- package/CHANGELOG.md +8 -0
- package/lib/components/Export/components/ExportForm/components/ExportButton/exportButton.js +6 -1
- package/lib/components/Export/components/ManifestDownload/components/ManifestDownloadEntity/components/FileManifestDownload/fileManifestDownload.js +5 -2
- package/lib/components/Index/components/AzulFileDownload/azulFileDownload.js +10 -5
- package/lib/components/Layout/components/Header/components/Content/components/Navigation/components/NavigationMenu/navigationMenu.js +1 -1
- package/lib/components/Layout/components/Header/components/Content/components/Navigation/components/NavigationMenuItems/navigationMenuItems.js +20 -21
- package/lib/components/Layout/components/Header/components/Content/components/Navigation/constants.d.ts +1 -0
- package/lib/components/Layout/components/Header/components/Content/components/Navigation/constants.js +1 -0
- package/lib/components/Layout/components/Header/components/Content/components/Navigation/navigation.d.ts +2 -1
- package/lib/components/Layout/components/Header/components/Content/components/Navigation/navigation.js +16 -17
- package/lib/components/Layout/components/Header/header.js +2 -1
- package/lib/components/Login/components/Button/types.d.ts +1 -1
- package/lib/components/Login/components/Buttons/buttons.d.ts +2 -0
- package/lib/components/Login/components/Buttons/buttons.js +5 -0
- package/lib/components/Login/components/Buttons/types.d.ts +8 -0
- package/lib/components/Login/components/Buttons/types.js +1 -0
- package/lib/components/Login/components/Section/components/Consent/consent.d.ts +3 -0
- package/lib/components/Login/components/Section/components/Consent/consent.js +14 -0
- package/lib/components/Login/components/Section/components/Consent/consent.styles.d.ts +7 -0
- package/lib/components/Login/components/Section/components/Consent/consent.styles.js +14 -0
- package/lib/components/Login/components/Section/components/Consent/types.d.ts +6 -0
- package/lib/components/Login/components/Section/components/Consent/types.js +1 -0
- package/lib/components/Login/components/Section/components/Warning/warning.d.ts +3 -0
- package/lib/components/Login/components/Section/components/Warning/warning.js +9 -0
- package/lib/components/Login/hooks/useUserConsent/types.d.ts +10 -0
- package/lib/components/Login/hooks/useUserConsent/types.js +1 -0
- package/lib/components/Login/hooks/useUserConsent/useUserConsent.d.ts +2 -0
- package/lib/components/Login/hooks/useUserConsent/useUserConsent.js +24 -0
- package/lib/components/Login/hooks/useUserLogin/types.d.ts +6 -0
- package/lib/components/Login/hooks/useUserLogin/types.js +1 -0
- package/lib/components/Login/hooks/useUserLogin/useUserLogin.d.ts +2 -0
- package/lib/components/Login/hooks/useUserLogin/useUserLogin.js +21 -0
- package/lib/components/common/CustomIcon/components/CloseIcon/closeIcon.d.ts +2 -0
- package/lib/components/common/CustomIcon/components/CloseIcon/closeIcon.js +6 -0
- package/lib/components/common/LoginDialog/constants.d.ts +6 -0
- package/lib/components/common/LoginDialog/constants.js +21 -0
- package/lib/components/common/LoginDialog/loginDialog.d.ts +2 -0
- package/lib/components/common/LoginDialog/loginDialog.js +27 -0
- package/lib/components/common/LoginDialog/loginDialog.styles.d.ts +3 -0
- package/lib/components/common/LoginDialog/loginDialog.styles.js +50 -0
- package/lib/components/common/LoginDialog/types.d.ts +4 -0
- package/lib/components/common/LoginDialog/types.js +1 -0
- package/lib/config/entities.d.ts +1 -0
- package/lib/providers/loginGuard/common/types.d.ts +18 -0
- package/lib/providers/loginGuard/common/types.js +1 -0
- package/lib/providers/loginGuard/context.d.ts +6 -0
- package/lib/providers/loginGuard/context.js +10 -0
- package/lib/providers/loginGuard/hook.d.ts +9 -0
- package/lib/providers/loginGuard/hook.js +12 -0
- package/lib/providers/loginGuard/provider.d.ts +11 -0
- package/lib/providers/loginGuard/provider.js +55 -0
- package/lib/styles/common/mui/typography.d.ts +1 -0
- package/lib/styles/common/mui/typography.js +7 -0
- package/package.json +1 -1
- package/src/components/Export/components/ExportForm/components/ExportButton/exportButton.tsx +8 -1
- package/src/components/Export/components/ManifestDownload/components/ManifestDownloadEntity/components/FileManifestDownload/fileManifestDownload.tsx +11 -3
- package/src/components/Index/components/AzulFileDownload/azulFileDownload.tsx +12 -5
- package/src/components/Layout/components/Header/components/Content/components/Navigation/components/NavigationMenu/navigationMenu.tsx +1 -1
- package/src/components/Layout/components/Header/components/Content/components/Navigation/components/NavigationMenuItems/navigationMenuItems.tsx +16 -15
- package/src/components/Layout/components/Header/components/Content/components/Navigation/constants.ts +1 -0
- package/src/components/Layout/components/Header/components/Content/components/Navigation/navigation.tsx +26 -18
- package/src/components/Layout/components/Header/header.tsx +6 -1
- package/src/components/Login/components/Button/types.ts +1 -1
- package/src/components/Login/components/Buttons/buttons.tsx +22 -0
- package/src/components/Login/components/Buttons/types.ts +9 -0
- package/src/components/Login/components/Section/components/Consent/consent.styles.ts +15 -0
- package/src/components/Login/components/Section/components/Consent/consent.tsx +30 -0
- package/src/components/Login/components/Section/components/Consent/types.ts +10 -0
- package/src/components/Login/components/Section/components/Warning/warning.tsx +24 -0
- package/src/components/Login/hooks/useUserConsent/types.ts +11 -0
- package/src/components/Login/hooks/useUserConsent/useUserConsent.ts +32 -0
- package/src/components/Login/hooks/useUserLogin/types.ts +8 -0
- package/src/components/Login/hooks/useUserLogin/useUserLogin.ts +29 -0
- package/src/components/common/CustomIcon/components/CloseIcon/closeIcon.tsx +17 -0
- package/src/components/common/LoginDialog/constants.ts +33 -0
- package/src/components/common/LoginDialog/loginDialog.styles.ts +51 -0
- package/src/components/common/LoginDialog/loginDialog.tsx +56 -0
- package/src/components/common/LoginDialog/types.ts +4 -0
- package/src/config/entities.ts +1 -0
- package/src/providers/loginGuard/common/types.ts +21 -0
- package/src/providers/loginGuard/context.ts +12 -0
- package/src/providers/loginGuard/hook.ts +14 -0
- package/src/providers/loginGuard/provider.tsx +76 -0
- package/src/styles/common/mui/typography.ts +8 -0
- package/tests/provider.test.tsx +191 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [21.4.0](https://github.com/DataBiosphere/findable-ui/compare/v21.3.0...v21.4.0) (2025-02-28)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* added check login required for export/download [#283](https://github.com/DataBiosphere/findable-ui/issues/283) ([#324](https://github.com/DataBiosphere/findable-ui/issues/324)) ([badb6ab](https://github.com/DataBiosphere/findable-ui/commit/badb6abe9319625a7fdabfe290434a05115cc2a9))
|
|
9
|
+
* use anchor tags for all header and footer links ([#297](https://github.com/DataBiosphere/findable-ui/issues/297)) ([#322](https://github.com/DataBiosphere/findable-ui/issues/322)) ([95effbf](https://github.com/DataBiosphere/findable-ui/commit/95effbfcdb65d71d10141c287b34043086c261e5))
|
|
10
|
+
|
|
3
11
|
## [21.3.0](https://github.com/DataBiosphere/findable-ui/compare/v21.2.0...v21.3.0) (2025-02-14)
|
|
4
12
|
|
|
5
13
|
|
|
@@ -2,12 +2,17 @@ import { Tooltip } from "@mui/material";
|
|
|
2
2
|
import React from "react";
|
|
3
3
|
import { useDownloadStatus } from "../../../../../../hooks/useDownloadStatus";
|
|
4
4
|
import { useFileManifestState } from "../../../../../../hooks/useFileManifestState";
|
|
5
|
+
import { useLoginGuard } from "../../../../../../providers/loginGuard/hook";
|
|
5
6
|
import { ButtonPrimary } from "../../../../../common/Button/components/ButtonPrimary/buttonPrimary";
|
|
6
7
|
export const ExportButton = ({ Button = ButtonPrimary, children, onClick, }) => {
|
|
7
8
|
const downloadStatus = useDownloadStatus();
|
|
8
9
|
const { fileManifestState: { isLoading }, } = useFileManifestState();
|
|
10
|
+
// Prompt user for login before export, if required.
|
|
11
|
+
const { requireLogin } = useLoginGuard();
|
|
9
12
|
return (React.createElement(Tooltip, { arrow: true, title: isLoading ? null : downloadStatus.message },
|
|
10
13
|
React.createElement("span", null,
|
|
11
|
-
React.createElement(Button, { disabled: isLoading || downloadStatus.disabled || downloadStatus.isLoading, onClick:
|
|
14
|
+
React.createElement(Button, { disabled: isLoading || downloadStatus.disabled || downloadStatus.isLoading, onClick: () => {
|
|
15
|
+
requireLogin(onClick);
|
|
16
|
+
} },
|
|
12
17
|
React.createElement("span", null, children)))));
|
|
13
18
|
};
|
|
@@ -3,6 +3,7 @@ import copy from "copy-to-clipboard";
|
|
|
3
3
|
import React, { useRef } from "react";
|
|
4
4
|
import { useDownloadStatus } from "../../../../../../../../hooks/useDownloadStatus";
|
|
5
5
|
import { useFileManifestDownload } from "../../../../../../../../hooks/useFileManifest/useFileManifestDownload";
|
|
6
|
+
import { useLoginGuard } from "../../../../../../../../providers/loginGuard/hook";
|
|
6
7
|
import { ButtonGroup } from "../../../../../../../common/ButtonGroup/buttonGroup";
|
|
7
8
|
import { ButtonGroupButton } from "../../../../../../../common/ButtonGroup/components/ButtonGroupButton/buttonGroupButton";
|
|
8
9
|
import { ContentCopyIconSmall, DownloadIconSmall, } from "../../../../../../../common/CustomIcon/common/constants";
|
|
@@ -16,6 +17,8 @@ export const FileManifestDownload = ({ filters, }) => {
|
|
|
16
17
|
const { fileName, isIdle, isLoading, manifestURL } = useFileManifestDownload(filters, disabled);
|
|
17
18
|
const isInProgress = (isIdle || isLoading) && !disabled;
|
|
18
19
|
const isReady = Boolean(manifestURL) || disabled;
|
|
20
|
+
// Prompt user for login before download and copy, if required.
|
|
21
|
+
const { requireLogin } = useLoginGuard();
|
|
19
22
|
// Copies file manifest.
|
|
20
23
|
const copyManifestURL = (url) => {
|
|
21
24
|
if (!url)
|
|
@@ -39,8 +42,8 @@ export const FileManifestDownload = ({ filters, }) => {
|
|
|
39
42
|
React.createElement(Tooltip, { arrow: true, title: message },
|
|
40
43
|
React.createElement("span", null,
|
|
41
44
|
React.createElement(ButtonGroup, { Buttons: [
|
|
42
|
-
React.createElement(ButtonGroupButton, { key: "download", action: "Download file manifest", disabled: disabled, label: React.createElement(DownloadIconSmall, null), onClick: downloadManifestURL }),
|
|
43
|
-
React.createElement(ButtonGroupButton, { key: "copy", action: "Copy file manifest", disabled: disabled, label: React.createElement(ContentCopyIconSmall, null), onClick: () => copyManifestURL(manifestURL) }),
|
|
45
|
+
React.createElement(ButtonGroupButton, { key: "download", action: "Download file manifest", disabled: disabled, label: React.createElement(DownloadIconSmall, null), onClick: () => requireLogin(downloadManifestURL) }),
|
|
46
|
+
React.createElement(ButtonGroupButton, { key: "copy", action: "Copy file manifest", disabled: disabled, label: React.createElement(ContentCopyIconSmall, null), onClick: () => requireLogin(() => copyManifestURL(manifestURL)) }),
|
|
44
47
|
] })))),
|
|
45
48
|
React.createElement(TableCell, null, fileName))) : (React.createElement(TableCell, null, "The manifest is not available for this project.")))))))));
|
|
46
49
|
};
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Box } from "@mui/material";
|
|
2
2
|
import React, { Fragment, useEffect, useRef, useState } from "react";
|
|
3
3
|
import { useFileLocation } from "../../../../hooks/useFileLocation";
|
|
4
|
+
import { useLoginGuard } from "../../../../providers/loginGuard/hook";
|
|
4
5
|
import { DownloadIcon } from "../../../common/CustomIcon/components/DownloadIcon/downloadIcon";
|
|
5
6
|
import { LoadingIcon } from "../../../common/CustomIcon/components/LoadingIcon/loadingIcon";
|
|
6
7
|
import { IconButton } from "../../../common/IconButton/iconButton";
|
|
@@ -11,6 +12,8 @@ export const AzulFileDownload = ({ entityName, relatedEntityId, relatedEntityNam
|
|
|
11
12
|
const { fileUrl, isLoading, run } = useFileLocation(url);
|
|
12
13
|
const downloadRef = useRef(null);
|
|
13
14
|
const [isRequestPending, setIsRequestPending] = useState(false);
|
|
15
|
+
// Prompt user for login before download, if required.
|
|
16
|
+
const { requireLogin } = useLoginGuard();
|
|
14
17
|
// Initiates file download when file location request is successful.
|
|
15
18
|
useEffect(() => {
|
|
16
19
|
if (!fileUrl)
|
|
@@ -22,11 +25,13 @@ export const AzulFileDownload = ({ entityName, relatedEntityId, relatedEntityNam
|
|
|
22
25
|
downloadEl.click();
|
|
23
26
|
setIsRequestPending(false);
|
|
24
27
|
}, [fileUrl]);
|
|
28
|
+
// Initiates file download when download button is clicked.
|
|
29
|
+
const handleDownloadClick = () => {
|
|
30
|
+
setIsRequestPending(true);
|
|
31
|
+
trackFileDownloaded(entityName, relatedEntityId, relatedEntityName);
|
|
32
|
+
run();
|
|
33
|
+
};
|
|
25
34
|
return (React.createElement(Fragment, null,
|
|
26
|
-
isRequestPending ? (React.createElement(StyledIconButton, { color: "primary", "data-testid": AZUL_FILE_REQUEST_DOWNLOAD_PENDING_TEST_ID, Icon: LoadingIcon, size: "medium" })) : (React.createElement(IconButton, { color: "primary", "data-testid": AZUL_FILE_REQUEST_DOWNLOAD_TEST_ID, disabled: !url, Icon: isLoading ? LoadingIcon : DownloadIcon, onClick: () =>
|
|
27
|
-
setIsRequestPending(true);
|
|
28
|
-
trackFileDownloaded(entityName, relatedEntityId, relatedEntityName);
|
|
29
|
-
run();
|
|
30
|
-
}, size: "medium" })),
|
|
35
|
+
isRequestPending ? (React.createElement(StyledIconButton, { color: "primary", "data-testid": AZUL_FILE_REQUEST_DOWNLOAD_PENDING_TEST_ID, Icon: LoadingIcon, size: "medium" })) : (React.createElement(IconButton, { color: "primary", "data-testid": AZUL_FILE_REQUEST_DOWNLOAD_TEST_ID, disabled: !url, Icon: isLoading ? LoadingIcon : DownloadIcon, onClick: () => requireLogin(handleDownloadClick), size: "medium" })),
|
|
31
36
|
React.createElement(Box, { component: "a", "data-testid": AZUL_FILE_DOWNLOAD_TEST_ID, download: true, ref: downloadRef, sx: { display: "none" } })));
|
|
32
37
|
};
|
|
@@ -26,7 +26,7 @@ export const NavigationMenu = ({ closeAncestor, isSelected = false, isSubMenu =
|
|
|
26
26
|
} },
|
|
27
27
|
React.createElement(MPaper, { variant: "menu" },
|
|
28
28
|
React.createElement(MClickAwayListener, { onClickAway: onClose },
|
|
29
|
-
React.createElement(MMenuList,
|
|
29
|
+
React.createElement(MMenuList, { component: "div" },
|
|
30
30
|
React.createElement(NavigationMenuItems, { closeMenu: () => {
|
|
31
31
|
onClose();
|
|
32
32
|
closeAncestor?.();
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { Divider, ListItemIcon, ListItemText, MenuItem as MMenuItem, } from "@mui/material";
|
|
2
|
-
import
|
|
1
|
+
import { Divider, ListItemIcon, ListItemText, Link as MLink, MenuItem as MMenuItem, } from "@mui/material";
|
|
2
|
+
import Link from "next/link";
|
|
3
3
|
import React, { Fragment } from "react";
|
|
4
4
|
import { TEXT_BODY_400, TEXT_BODY_500, TEXT_BODY_SMALL_400_2_LINES, TEXT_UPPERCASE_500, } from "../../../../../../../../../../theme/common/typography";
|
|
5
5
|
import { ANCHOR_TARGET, REL_ATTRIBUTE, } from "../../../../../../../../../Links/common/entities";
|
|
@@ -8,23 +8,22 @@ import { isNavigationLinkSelected } from "../../common/utils";
|
|
|
8
8
|
import { NavigationMenu } from "../NavigationMenu/navigationMenu";
|
|
9
9
|
import { POPPER_PROPS } from "./common/constants";
|
|
10
10
|
export const NavigationMenuItems = ({ closeMenu, menuItems, pathname, }) => {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
React.createElement(
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
:
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
divider && React.createElement(Divider, null))))));
|
|
11
|
+
return (React.createElement(React.Fragment, null, menuItems.map(({ description, divider, icon, label, menuItems: nestedMenuItems, selectedPatterns, target = ANCHOR_TARGET.SELF, url, }, i) => {
|
|
12
|
+
const isClientSide = isClientSideNavigation(url);
|
|
13
|
+
return nestedMenuItems ? (React.createElement(NavigationMenu, { key: i, closeAncestor: closeMenu, isSelected: isNavigationLinkSelected(pathname, selectedPatterns), isSubMenu: true, menuItems: nestedMenuItems, menuLabel: label, pathname: pathname, popperProps: POPPER_PROPS })) : (React.createElement(Fragment, { key: i },
|
|
14
|
+
React.createElement(MMenuItem, { component: isClientSide ? Link : MLink, disabled: !url, href: url, onClick: () => closeMenu(), rel: isClientSide
|
|
15
|
+
? REL_ATTRIBUTE.NO_OPENER
|
|
16
|
+
: REL_ATTRIBUTE.NO_OPENER_NO_REFERRER, selected: isNavigationLinkSelected(pathname, selectedPatterns), target: target },
|
|
17
|
+
icon && React.createElement(ListItemIcon, null, icon),
|
|
18
|
+
React.createElement(ListItemText, { primary: label, primaryTypographyProps: {
|
|
19
|
+
variant: url
|
|
20
|
+
? description
|
|
21
|
+
? TEXT_BODY_500
|
|
22
|
+
: TEXT_BODY_400
|
|
23
|
+
: TEXT_UPPERCASE_500,
|
|
24
|
+
}, secondary: description, secondaryTypographyProps: {
|
|
25
|
+
variant: TEXT_BODY_SMALL_400_2_LINES,
|
|
26
|
+
} })),
|
|
27
|
+
divider && React.createElement(Divider, null)));
|
|
28
|
+
})));
|
|
30
29
|
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const NAVIGATION_TEST_ID = "navigation";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const NAVIGATION_TEST_ID = "navigation";
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import React, { CSSProperties, ReactNode } from "react";
|
|
2
2
|
import { BreakpointKey } from "../../../../../../../../hooks/useBreakpointHelper";
|
|
3
3
|
import { ANCHOR_TARGET } from "../../../../../../../Links/common/entities";
|
|
4
|
+
import { TestIdProps } from "../../../../../../../types";
|
|
4
5
|
import { SelectedMatch } from "../../../../common/entities";
|
|
5
6
|
import { HeaderProps } from "../../../../header";
|
|
6
7
|
import { MenuItem } from "./components/NavigationMenuItems/navigationMenuItems";
|
|
@@ -15,7 +16,7 @@ export interface NavLinkItem {
|
|
|
15
16
|
url: string;
|
|
16
17
|
visible?: Partial<Record<BreakpointKey, boolean>>;
|
|
17
18
|
}
|
|
18
|
-
export interface NavigationProps {
|
|
19
|
+
export interface NavigationProps extends TestIdProps {
|
|
19
20
|
className?: string;
|
|
20
21
|
closeAncestor?: () => void;
|
|
21
22
|
headerProps?: HeaderProps;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { Button, Divider } from "@mui/material";
|
|
2
|
-
import
|
|
1
|
+
import { Button, Divider, Link as MLink } from "@mui/material";
|
|
2
|
+
import Link from "next/link";
|
|
3
3
|
import React, { forwardRef, Fragment } from "react";
|
|
4
4
|
import { ANCHOR_TARGET, REL_ATTRIBUTE, } from "../../../../../../../Links/common/entities";
|
|
5
5
|
import { isClientSideNavigation } from "../../../../../../../Links/common/utils";
|
|
@@ -8,19 +8,18 @@ import { NavigationButtonLabel } from "./components/NavigationButtonLabel/naviga
|
|
|
8
8
|
import { NavigationDrawer } from "./components/NavigationDrawer/navigationDrawer";
|
|
9
9
|
import { NavigationMenu } from "./components/NavigationMenu/navigationMenu";
|
|
10
10
|
import { Navigation as Links } from "./navigation.styles";
|
|
11
|
-
export const Navigation = forwardRef(function Navigation({ className, closeAncestor, headerProps, isMenuIn = false, links, pathname, style, }, ref) {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
divider && React.createElement(Divider, null))))));
|
|
11
|
+
export const Navigation = forwardRef(function Navigation({ className, closeAncestor, headerProps, isMenuIn = false, links, pathname, style, testId, }, ref) {
|
|
12
|
+
return (React.createElement(Links, { ref: ref, className: className, "data-testid": testId, isMenuIn: isMenuIn, style: style }, links.map(({ divider, label, menuItems, selectedPatterns, target = ANCHOR_TARGET.SELF, url, }, i) => {
|
|
13
|
+
const isClientSide = isClientSideNavigation(url);
|
|
14
|
+
return menuItems ? (React.createElement(Fragment, { key: i },
|
|
15
|
+
isMenuIn ? (React.createElement(NavigationDrawer, { closeAncestor: closeAncestor, headerProps: headerProps, isMenuIn: isMenuIn, isSelected: isNavigationLinkSelected(pathname, selectedPatterns), menuItems: menuItems, menuLabel: label, pathname: pathname })) : (React.createElement(NavigationMenu, { closeAncestor: closeAncestor, isSelected: isNavigationLinkSelected(pathname, selectedPatterns), menuItems: menuItems, menuLabel: label, pathname: pathname })),
|
|
16
|
+
divider && React.createElement(Divider, null))) : (React.createElement(Fragment, { key: i },
|
|
17
|
+
React.createElement(Button, { component: isClientSide ? Link : MLink, disabled: !url, href: url, onClick: () => closeAncestor?.(), rel: isClientSide
|
|
18
|
+
? REL_ATTRIBUTE.NO_OPENER
|
|
19
|
+
: REL_ATTRIBUTE.NO_OPENER_NO_REFERRER, target: target, variant: isNavigationLinkSelected(pathname, selectedPatterns)
|
|
20
|
+
? "activeNav"
|
|
21
|
+
: "nav" },
|
|
22
|
+
React.createElement(NavigationButtonLabel, { label: label })),
|
|
23
|
+
divider && React.createElement(Divider, null)));
|
|
24
|
+
})));
|
|
26
25
|
});
|
|
@@ -7,6 +7,7 @@ import { Actions } from "./components/Content/components/Actions/actions";
|
|
|
7
7
|
import { Authentication, renderButton as renderAuthenticationButton, renderIconButton as renderAuthenticationIconButton, } from "./components/Content/components/Actions/components/Authentication/authentication";
|
|
8
8
|
import { Menu } from "./components/Content/components/Actions/components/Menu/menu";
|
|
9
9
|
import { renderButton as renderSearchButton, renderIconButton as renderSearchIconButton, Search, } from "./components/Content/components/Actions/components/Search/search";
|
|
10
|
+
import { NAVIGATION_TEST_ID } from "./components/Content/components/Navigation/constants";
|
|
10
11
|
import { Navigation as DXNavigation } from "./components/Content/components/Navigation/navigation";
|
|
11
12
|
import { Slogan } from "./components/Content/components/Slogan/slogan";
|
|
12
13
|
import { Divider } from "./components/Content/components/Slogan/slogan.styles";
|
|
@@ -38,7 +39,7 @@ export const Header = ({ ...headerProps }) => {
|
|
|
38
39
|
isIn.isSloganIn && React.createElement(Slogan, { slogan: slogan }),
|
|
39
40
|
isIn.isLeftNavigationIn && (React.createElement(DXNavigation, { ...navigationProps, links: navItemsL })))),
|
|
40
41
|
React.createElement(Fade, { ...FADE_TRANSITION_PROPS, in: isIn.isCenterGroupIn },
|
|
41
|
-
React.createElement(Center, null, isIn.isCenterNavigationIn && (React.createElement(DXNavigation, { ...navigationProps, links: navItemsC })))),
|
|
42
|
+
React.createElement(Center, null, isIn.isCenterNavigationIn && (React.createElement(DXNavigation, { ...navigationProps, testId: NAVIGATION_TEST_ID, links: navItemsC })))),
|
|
42
43
|
React.createElement(Fade, { ...FADE_TRANSITION_PROPS, in: isIn.isRightGroupIn },
|
|
43
44
|
React.createElement(Right, null,
|
|
44
45
|
isIn.isRightNavigationIn && (React.createElement(DXNavigation, { ...navigationProps, links: navItemsR })),
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { Button } from "../Button/button";
|
|
3
|
+
export const Buttons = ({ className, handleLogin, providers = [], ...props /* Mui ButtonProps */ }) => {
|
|
4
|
+
return providers?.map((provider) => (React.createElement(Button, { key: provider.id, className: className, endIcon: "icon" in provider && provider.icon, onClick: () => handleLogin(provider.id), ...props }, provider.name)));
|
|
5
|
+
};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { ButtonProps } from "@mui/material";
|
|
2
|
+
import { ClientSafeProvider } from "next-auth/react";
|
|
3
|
+
import { OAuthProvider } from "../../../../config/entities";
|
|
4
|
+
import { BaseComponentProps } from "../../../../theme/common/entities";
|
|
5
|
+
export interface Props<P> extends BaseComponentProps, ButtonProps {
|
|
6
|
+
handleLogin: (providerId: string) => void;
|
|
7
|
+
providers?: ClientSafeProvider[] | OAuthProvider<P>[];
|
|
8
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { Checkbox, Typography } from "@mui/material";
|
|
2
|
+
import React from "react";
|
|
3
|
+
import { TEXT_BODY_400 } from "../../../../../../theme/common/typography";
|
|
4
|
+
import { CheckedIcon } from "../../../../../common/CustomIcon/components/CheckedIcon/checkedIcon";
|
|
5
|
+
import { UncheckedErrorIcon } from "../../../../../common/CustomIcon/components/UncheckedErrorIcon/uncheckedErrorIcon";
|
|
6
|
+
import { UncheckedIcon } from "../../../../../common/CustomIcon/components/UncheckedIcon/uncheckedIcon";
|
|
7
|
+
import { StyledGrid2 } from "./consent.styles";
|
|
8
|
+
export const Consent = ({ children, className, handleConsent, isDisabled, isError, ...props /* Mui Grid2Props */ }) => {
|
|
9
|
+
if (isDisabled)
|
|
10
|
+
return null;
|
|
11
|
+
return (React.createElement(StyledGrid2, { className: className, ...props },
|
|
12
|
+
React.createElement(Checkbox, { checkedIcon: React.createElement(CheckedIcon, null), icon: isError ? React.createElement(UncheckedErrorIcon, null) : React.createElement(UncheckedIcon, null), onChange: handleConsent }),
|
|
13
|
+
React.createElement(Typography, { variant: TEXT_BODY_400 }, children)));
|
|
14
|
+
};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export declare const StyledGrid2: import("@emotion/styled").StyledComponent<import("@mui/material").GridBaseProps & {
|
|
2
|
+
sx?: import("@mui/material").SxProps<import("@mui/material").Theme>;
|
|
3
|
+
} & import("@mui/system").SystemProps<import("@mui/material").Theme> & Omit<Omit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref"> & {
|
|
4
|
+
ref?: ((instance: HTMLDivElement | null) => void | import("react").DO_NOT_USE_OR_YOU_WILL_BE_FIRED_CALLBACK_REF_RETURN_VALUES[keyof import("react").DO_NOT_USE_OR_YOU_WILL_BE_FIRED_CALLBACK_REF_RETURN_VALUES]) | import("react").RefObject<HTMLDivElement> | null | undefined;
|
|
5
|
+
}, ("fontSize" | "fontWeight" | "lineHeight" | "letterSpacing" | "textTransform" | "p" | "color" | "border" | "borderTop" | "borderRight" | "borderBottom" | "borderLeft" | "borderColor" | "borderRadius" | "display" | "displayPrint" | "overflow" | "textOverflow" | "visibility" | "whiteSpace" | "flexBasis" | "flexDirection" | "flexWrap" | "justifyContent" | "alignItems" | "alignContent" | "order" | "flex" | "flexGrow" | "flexShrink" | "alignSelf" | "justifyItems" | "justifySelf" | "gap" | "columnGap" | "rowGap" | "gridColumn" | "gridRow" | "gridAutoFlow" | "gridAutoColumns" | "gridAutoRows" | "gridTemplateColumns" | "gridTemplateRows" | "gridTemplateAreas" | "gridArea" | "bgcolor" | "zIndex" | "position" | "top" | "right" | "bottom" | "left" | "boxShadow" | "width" | "maxWidth" | "minWidth" | "height" | "maxHeight" | "minHeight" | "boxSizing" | "m" | "mt" | "mr" | "mb" | "ml" | "mx" | "my" | "pt" | "pr" | "pb" | "pl" | "px" | "py" | "margin" | "marginTop" | "marginRight" | "marginBottom" | "marginLeft" | "marginX" | "marginY" | "marginInline" | "marginInlineStart" | "marginInlineEnd" | "marginBlock" | "marginBlockStart" | "marginBlockEnd" | "padding" | "paddingTop" | "paddingRight" | "paddingBottom" | "paddingLeft" | "paddingX" | "paddingY" | "paddingInline" | "paddingInlineStart" | "paddingInlineEnd" | "paddingBlock" | "paddingBlockStart" | "paddingBlockEnd" | "typography" | "fontFamily" | "fontStyle" | "textAlign") | "sx" | keyof import("@mui/material").GridBaseProps> & {
|
|
6
|
+
theme?: import("@emotion/react").Theme;
|
|
7
|
+
}, {}, {}>;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import styled from "@emotion/styled";
|
|
2
|
+
import { Grid2 } from "@mui/material";
|
|
3
|
+
export const StyledGrid2 = styled(Grid2) `
|
|
4
|
+
align-items: center;
|
|
5
|
+
align-self: flex-start;
|
|
6
|
+
display: flex;
|
|
7
|
+
gap: 12px;
|
|
8
|
+
|
|
9
|
+
.MuiTypography-text-body-400 {
|
|
10
|
+
.MuiLink-root {
|
|
11
|
+
color: inherit;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
`;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { Grid2Props } from "@mui/material";
|
|
2
|
+
import { ReactNode } from "react";
|
|
3
|
+
import { UseUserConsent } from "../../../../hooks/useUserConsent/types";
|
|
4
|
+
export interface ConsentProps extends Grid2Props, Pick<UseUserConsent, "handleConsent">, Pick<UseUserConsent["state"], "isDisabled" | "isError"> {
|
|
5
|
+
children: ReactNode;
|
|
6
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { Typography } from "@mui/material";
|
|
2
|
+
import React from "react";
|
|
3
|
+
import { COLOR } from "../../../../../../styles/common/mui/typography";
|
|
4
|
+
import { TEXT_BODY_SMALL_400 } from "../../../../../../theme/common/typography";
|
|
5
|
+
export const Warning = ({ children, className, ...props /* Mui TypographyOwnProps */ }) => {
|
|
6
|
+
if (!children)
|
|
7
|
+
return null;
|
|
8
|
+
return (React.createElement(Typography, { className: className, color: COLOR.INK_LIGHT, mt: 6, variant: TEXT_BODY_SMALL_400, ...props }, children));
|
|
9
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { useCallback, useState } from "react";
|
|
2
|
+
import { useAuthenticationConfig } from "../../../../hooks/authentication/config/useAuthenticationConfig";
|
|
3
|
+
export const useUserConsent = () => {
|
|
4
|
+
const authConfig = useAuthenticationConfig();
|
|
5
|
+
const [isDisabled] = useState(Boolean(!authConfig?.termsOfService));
|
|
6
|
+
const [isError, setIsError] = useState(false);
|
|
7
|
+
const [isValid, setIsValid] = useState(false);
|
|
8
|
+
const handleError = useCallback((error) => {
|
|
9
|
+
setIsError(error);
|
|
10
|
+
}, []);
|
|
11
|
+
const handleConsent = useCallback((changeEvent) => {
|
|
12
|
+
handleError(false);
|
|
13
|
+
setIsValid(changeEvent.target.checked);
|
|
14
|
+
}, [handleError]);
|
|
15
|
+
return {
|
|
16
|
+
handleConsent,
|
|
17
|
+
handleError,
|
|
18
|
+
state: {
|
|
19
|
+
isDisabled,
|
|
20
|
+
isError,
|
|
21
|
+
isValid,
|
|
22
|
+
},
|
|
23
|
+
};
|
|
24
|
+
};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { ProviderId } from "../../../../providers/authentication/common/types";
|
|
2
|
+
import { UseUserConsent } from "../useUserConsent/types";
|
|
3
|
+
export interface UseUserLogin extends Omit<UseUserConsent, "handleError" | "state"> {
|
|
4
|
+
consentState: Pick<UseUserConsent["state"], "isDisabled" | "isError">;
|
|
5
|
+
handleLogin: (providerId: ProviderId) => void;
|
|
6
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { useCallback } from "react";
|
|
2
|
+
import { useAuth } from "../../../../providers/authentication/auth/hook";
|
|
3
|
+
import { useUserConsent } from "../useUserConsent/useUserConsent";
|
|
4
|
+
export const useUserLogin = () => {
|
|
5
|
+
const { service: { requestLogin } = {} } = useAuth();
|
|
6
|
+
const { handleConsent, handleError, state: consentState } = useUserConsent();
|
|
7
|
+
const { isDisabled, isError, isValid } = consentState; // Consent state: { isValid } is an indicator of whether the user has accepted the login terms.
|
|
8
|
+
const handleLogin = useCallback((providerId) => {
|
|
9
|
+
if (!isDisabled && !isValid) {
|
|
10
|
+
// If the user has not accepted terms, set error state to true.
|
|
11
|
+
handleError(true);
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
requestLogin?.(providerId);
|
|
15
|
+
}, [handleError, isDisabled, isValid, requestLogin]);
|
|
16
|
+
return {
|
|
17
|
+
consentState: { isDisabled, isError },
|
|
18
|
+
handleConsent,
|
|
19
|
+
handleLogin,
|
|
20
|
+
};
|
|
21
|
+
};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { SvgIcon } from "@mui/material";
|
|
2
|
+
import React from "react";
|
|
3
|
+
export const CloseIcon = ({ fontSize = "xsmall", viewBox = "0 0 18 18", ...props /* Spread props to allow for Mui SvgIconProps specific prop overrides e.g. "htmlColor". */ }) => {
|
|
4
|
+
return (React.createElement(SvgIcon, { fontSize: fontSize, viewBox: viewBox, ...props },
|
|
5
|
+
React.createElement("path", { d: "M8.99994 10.1061L5.38104 13.725C5.23104 13.875 5.04984 13.947 4.83744 13.941C4.62504 13.9344 4.44384 13.8561 4.29384 13.7061C4.14384 13.5561 4.06884 13.3719 4.06884 13.1535C4.06884 12.9345 4.14384 12.75 4.29384 12.6L7.89384 9.00005L4.27494 5.38115C4.12494 5.23115 4.05294 5.04695 4.05894 4.82855C4.06554 4.60955 4.14384 4.42505 4.29384 4.27505C4.44384 4.12505 4.62804 4.05005 4.84644 4.05005C5.06544 4.05005 5.24994 4.12505 5.39994 4.27505L8.99994 7.89395L12.6188 4.27505C12.7688 4.12505 12.953 4.05005 13.1714 4.05005C13.3904 4.05005 13.5749 4.12505 13.7249 4.27505C13.8749 4.42505 13.9499 4.60955 13.9499 4.82855C13.9499 5.04695 13.8749 5.23115 13.7249 5.38115L10.106 9.00005L13.7249 12.6189C13.8749 12.7689 13.9499 12.9501 13.9499 13.1625C13.9499 13.3749 13.8749 13.5561 13.7249 13.7061C13.5749 13.8561 13.3904 13.9311 13.1714 13.9311C12.953 13.9311 12.7688 13.8561 12.6188 13.7061L8.99994 10.1061Z", fill: "currentColor" })));
|
|
6
|
+
};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { DialogContentTextProps, DialogProps, DialogTitleProps, IconButtonProps, IconProps } from "@mui/material";
|
|
2
|
+
export declare const DIALOG_CONTENT_TEXT_PROPS: DialogContentTextProps;
|
|
3
|
+
export declare const DIALOG_PROPS: Partial<DialogProps>;
|
|
4
|
+
export declare const DIALOG_TITLE_PROPS: DialogTitleProps;
|
|
5
|
+
export declare const ICON_BUTTON_PROPS: IconButtonProps;
|
|
6
|
+
export declare const ICON_PROPS: Pick<IconProps, "fontSize">;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { FONT_SIZE } from "../../../styles/common/mui/icon";
|
|
2
|
+
import { COLOR, VARIANT } from "../../../styles/common/mui/typography";
|
|
3
|
+
export const DIALOG_CONTENT_TEXT_PROPS = {
|
|
4
|
+
color: COLOR.INK_LIGHT,
|
|
5
|
+
component: "div",
|
|
6
|
+
variant: VARIANT.TEXT_BODY_400,
|
|
7
|
+
};
|
|
8
|
+
export const DIALOG_PROPS = {
|
|
9
|
+
PaperProps: { elevation: 0 },
|
|
10
|
+
};
|
|
11
|
+
export const DIALOG_TITLE_PROPS = {
|
|
12
|
+
variant: VARIANT.TEXT_HEADING_SMALL,
|
|
13
|
+
};
|
|
14
|
+
export const ICON_BUTTON_PROPS = {
|
|
15
|
+
color: "inkLight",
|
|
16
|
+
edge: "end",
|
|
17
|
+
size: "xsmall",
|
|
18
|
+
};
|
|
19
|
+
export const ICON_PROPS = {
|
|
20
|
+
fontSize: FONT_SIZE.SMALL,
|
|
21
|
+
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { DialogActions, DialogContent, DialogContentText, DialogTitle, IconButton, } from "@mui/material";
|
|
2
|
+
import React from "react";
|
|
3
|
+
import { useAuthenticationConfig } from "../../../hooks/authentication/config/useAuthenticationConfig";
|
|
4
|
+
import { Buttons } from "../../Login/components/Buttons/buttons";
|
|
5
|
+
import { Consent } from "../../Login/components/Section/components/Consent/consent";
|
|
6
|
+
import { Warning } from "../../Login/components/Section/components/Warning/warning";
|
|
7
|
+
import { useUserLogin } from "../../Login/hooks/useUserLogin/useUserLogin";
|
|
8
|
+
import { CloseIcon } from "../CustomIcon/components/CloseIcon/closeIcon";
|
|
9
|
+
import { DIALOG_CONTENT_TEXT_PROPS, DIALOG_PROPS, DIALOG_TITLE_PROPS, ICON_BUTTON_PROPS, ICON_PROPS, } from "./constants";
|
|
10
|
+
import { StyledDialog } from "./loginDialog.styles";
|
|
11
|
+
export const LoginDialog = ({ onClose, open, }) => {
|
|
12
|
+
const authConfig = useAuthenticationConfig();
|
|
13
|
+
const { consentState, handleConsent, handleLogin } = useUserLogin();
|
|
14
|
+
if (!authConfig)
|
|
15
|
+
return null;
|
|
16
|
+
return (React.createElement(StyledDialog, { ...DIALOG_PROPS, onClose: onClose, open: open },
|
|
17
|
+
React.createElement(DialogTitle, { ...DIALOG_TITLE_PROPS },
|
|
18
|
+
React.createElement("div", null, "Sign In Required"),
|
|
19
|
+
React.createElement(IconButton, { ...ICON_BUTTON_PROPS, onClick: onClose },
|
|
20
|
+
React.createElement(CloseIcon, { ...ICON_PROPS }))),
|
|
21
|
+
React.createElement(DialogContent, null,
|
|
22
|
+
React.createElement(DialogContentText, { ...DIALOG_CONTENT_TEXT_PROPS }, "Please sign in to proceed with this action."),
|
|
23
|
+
React.createElement(Consent, { handleConsent: handleConsent, ...consentState }, authConfig.termsOfService)),
|
|
24
|
+
React.createElement(DialogActions, { disableSpacing: true },
|
|
25
|
+
React.createElement(Buttons, { handleLogin: handleLogin, providers: authConfig.providers })),
|
|
26
|
+
React.createElement(Warning, null, authConfig.warning)));
|
|
27
|
+
};
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import styled from "@emotion/styled";
|
|
2
|
+
import { Dialog } from "@mui/material";
|
|
3
|
+
import { inkMain } from "../../../styles/common/mixins/colors";
|
|
4
|
+
import { alpha80 } from "../../../theme/common/palette";
|
|
5
|
+
export const StyledDialog = styled(Dialog) `
|
|
6
|
+
&.MuiDialog-root {
|
|
7
|
+
.MuiBackdrop-root {
|
|
8
|
+
background-color: ${inkMain}${alpha80};
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
.MuiDialog-paper {
|
|
12
|
+
border-radius: 8px;
|
|
13
|
+
max-width: 400px;
|
|
14
|
+
padding: 32px;
|
|
15
|
+
position: relative; /* positions close icon */
|
|
16
|
+
|
|
17
|
+
.MuiDialogTitle-root,
|
|
18
|
+
.MuiDialogContent-root,
|
|
19
|
+
.MuiDialogActions-root {
|
|
20
|
+
padding: 0;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
.MuiDialogTitle-root {
|
|
24
|
+
font-size: 20px;
|
|
25
|
+
|
|
26
|
+
.MuiIconButton-root {
|
|
27
|
+
position: absolute;
|
|
28
|
+
right: 12px;
|
|
29
|
+
top: 12px;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
.MuiDialogContent-root {
|
|
34
|
+
.MuiDialogContentText-root {
|
|
35
|
+
margin: 8px 0;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
.MuiGrid2-root {
|
|
39
|
+
margin: 24px 0;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
.MuiDialogActions-root {
|
|
44
|
+
display: flex;
|
|
45
|
+
flex-direction: column;
|
|
46
|
+
gap: 16px 0;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
`;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/lib/config/entities.d.ts
CHANGED