From 7fcab7ad1d46cb73d0041a90c999f1b49e10856d Mon Sep 17 00:00:00 2001 From: Stefano Pigozzi Date: Sat, 16 Oct 2021 03:30:32 +0200 Subject: [PATCH] =?UTF-8?q?=F0=9F=92=A5=20Add=20icons=20and=20refactor=20a?= =?UTF-8?q?uthorization=20components?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../authorization/AuthorizationAdminBox.tsx | 43 ++++------ .../AuthorizationAdminPageButton.tsx | 35 ++++++++ .../authorization/AuthorizationBrowseBox.tsx | 20 ++--- .../AuthorizationGoToSophonButton.tsx | 34 ++++++++ .../AuthorizationLoggedInBox.tsx | 63 ++++++++++++++ .../authorization/AuthorizationLoginBox.tsx | 30 ++----- .../authorization/AuthorizationLogoutBox.tsx | 86 ------------------- .../AuthorizationLogoutButton.tsx | 34 ++++++++ .../authorization/AuthorizationStepPage.tsx | 6 +- frontend/src/components/elements/IconText.tsx | 24 ++++++ frontend/src/types/ExtraTypes.ts | 8 ++ 11 files changed, 233 insertions(+), 150 deletions(-) create mode 100644 frontend/src/components/authorization/AuthorizationAdminPageButton.tsx create mode 100644 frontend/src/components/authorization/AuthorizationGoToSophonButton.tsx create mode 100644 frontend/src/components/authorization/AuthorizationLoggedInBox.tsx delete mode 100644 frontend/src/components/authorization/AuthorizationLogoutBox.tsx create mode 100644 frontend/src/components/authorization/AuthorizationLogoutButton.tsx create mode 100644 frontend/src/components/elements/IconText.tsx diff --git a/frontend/src/components/authorization/AuthorizationAdminBox.tsx b/frontend/src/components/authorization/AuthorizationAdminBox.tsx index 208e1d6..6b3bdc8 100644 --- a/frontend/src/components/authorization/AuthorizationAdminBox.tsx +++ b/frontend/src/components/authorization/AuthorizationAdminBox.tsx @@ -1,42 +1,31 @@ -import {navigate} from "@reach/router" +import {faCog} from "@fortawesome/free-solid-svg-icons" import {Box, Form, Heading, Idiomatic as I} from "@steffo/bluelib-react" import * as React from "react" import {useAuthorizationContext} from "../../contexts/authorization" -import {useInstanceContext} from "../../contexts/instance" +import {IconText} from "../elements/IconText" +import {AuthorizationAdminPageButton} from "./AuthorizationAdminPageButton" +/** + * Box that allows the user to access the Sophon administration page. + * + * @constructor + */ export function AuthorizationAdminBox(): JSX.Element { - const instance = useInstanceContext() const authorization = useAuthorizationContext() - const canAdministrate = + const enabled = React.useMemo( - () => ( - authorization !== undefined && authorization.state.token === undefined && !authorization.state.running - ), + () => authorization && !authorization.state.running && authorization.state.token === undefined, [authorization], ) - const doAdministrate = - React.useCallback( - async () => { - if(!instance) { - return - } - if(!instance.state.url) { - return - } - - await navigate(`${instance.state.url}admin`) - }, - [instance], - ) - - return ( - + - Server administration + + Server administration +

To configure the Sophon server, an account with superuser access is required. @@ -46,9 +35,7 @@ export function AuthorizationAdminBox(): JSX.Element {

- - Administrate - +
diff --git a/frontend/src/components/authorization/AuthorizationAdminPageButton.tsx b/frontend/src/components/authorization/AuthorizationAdminPageButton.tsx new file mode 100644 index 0000000..8562de7 --- /dev/null +++ b/frontend/src/components/authorization/AuthorizationAdminPageButton.tsx @@ -0,0 +1,35 @@ +import {faCog} from "@fortawesome/free-solid-svg-icons" +import {navigate} from "@reach/router" +import {Button} from "@steffo/bluelib-react" +import * as React from "react" +import {useInstanceContext} from "../../contexts/instance" +import {CanBeDisabled} from "../../types/ExtraTypes" +import {IconText} from "../elements/IconText" + + +export function AuthorizationAdminPageButton({disabled = false}: CanBeDisabled): JSX.Element { + const instance = useInstanceContext() + + const canAdministrate = + React.useMemo( + () => !disabled && instance, + [disabled, instance], + ) + + const doAdministrate = + React.useCallback( + async () => { + await navigate(`${instance!.state.url}admin`) + }, + [instance], + ) + + + return ( + + ) +} diff --git a/frontend/src/components/authorization/AuthorizationBrowseBox.tsx b/frontend/src/components/authorization/AuthorizationBrowseBox.tsx index fcf798d..f2c9615 100644 --- a/frontend/src/components/authorization/AuthorizationBrowseBox.tsx +++ b/frontend/src/components/authorization/AuthorizationBrowseBox.tsx @@ -1,8 +1,10 @@ +import {faUser} from "@fortawesome/free-regular-svg-icons" import {faLock, faUniversity} from "@fortawesome/free-solid-svg-icons" import {FontAwesomeIcon} from "@fortawesome/react-fontawesome" import {Box, Form, Heading, Idiomatic as I} from "@steffo/bluelib-react" import * as React from "react" import {useAuthorizationContext} from "../../contexts/authorization" +import {IconText} from "../elements/IconText" export function AuthorizationBrowseBox(): JSX.Element { @@ -18,15 +20,7 @@ export function AuthorizationBrowseBox(): JSX.Element { const doBrowse = React.useCallback( - async () => { - if(!authorization) { - return - } - - authorization.dispatch({ - type: "browse", - }) - }, + () => authorization!.dispatch({type: "browse"}), [authorization], ) @@ -34,7 +28,9 @@ export function AuthorizationBrowseBox(): JSX.Element { // By disabling the box, the login box is highlighted while a login attempt is running, making the user focus on the login attempt - Browse as guest + + Browse as guest +

You can browse Sophon without an account. @@ -45,7 +41,9 @@ export function AuthorizationBrowseBox(): JSX.Element {

- Browse + + Browse as guest +
diff --git a/frontend/src/components/authorization/AuthorizationGoToSophonButton.tsx b/frontend/src/components/authorization/AuthorizationGoToSophonButton.tsx new file mode 100644 index 0000000..ff0f59c --- /dev/null +++ b/frontend/src/components/authorization/AuthorizationGoToSophonButton.tsx @@ -0,0 +1,34 @@ +import {faSignInAlt} from "@fortawesome/free-solid-svg-icons" +import {navigate} from "@reach/router" +import {Button} from "@steffo/bluelib-react" +import * as React from "react" +import {useInstanceContext} from "../../contexts/instance" +import {useSophonPath} from "../../hooks/useSophonPath" +import {CanBeDisabled} from "../../types/ExtraTypes" +import {IconText} from "../elements/IconText" + + +export function AuthorizationGoToSophonButton({disabled = false}: CanBeDisabled): JSX.Element { + const instance = useInstanceContext() + const location = useSophonPath() + + const canGoTo = + React.useMemo( + () => !disabled && instance && !location.loggedIn, + [disabled, instance, location], + ) + + const doGoTo = + React.useCallback( + () => navigate("l/logged-in/"), + [], + ) + + return ( + + ) +} diff --git a/frontend/src/components/authorization/AuthorizationLoggedInBox.tsx b/frontend/src/components/authorization/AuthorizationLoggedInBox.tsx new file mode 100644 index 0000000..8208e16 --- /dev/null +++ b/frontend/src/components/authorization/AuthorizationLoggedInBox.tsx @@ -0,0 +1,63 @@ +import {faUser as faUserRegular} from "@fortawesome/free-regular-svg-icons" +import {faClipboardCheck, faUser as faUserSolid} from "@fortawesome/free-solid-svg-icons" +import {Box, BringAttention as B, Form, Heading} from "@steffo/bluelib-react" +import * as React from "react" +import {useAuthorizationContext} from "../../contexts/authorization" +import {IconText} from "../elements/IconText" +import {AuthorizationGoToSophonButton} from "./AuthorizationGoToSophonButton" +import {AuthorizationLogoutButton} from "./AuthorizationLogoutButton" + + +export function AuthorizationLoggedInBox(): JSX.Element { + const authorization = useAuthorizationContext() + + const loggedUsername = React.useMemo( + () => { + if(!authorization?.state.user) { + return ( + + + a guest + + + ) + } + else { + return ( + + + {authorization.state.user.username} + + + ) + } + }, + [authorization], + ) + + return ( + + + + Logged in + + +

+ You are currently logged in as {loggedUsername}. +

+
+ + + +
+

+ To use a different account with Sophon, you'll need to logout from your current one first. +

+
+ + + +
+
+ ) +} diff --git a/frontend/src/components/authorization/AuthorizationLoginBox.tsx b/frontend/src/components/authorization/AuthorizationLoginBox.tsx index e7ffd59..55ad87b 100644 --- a/frontend/src/components/authorization/AuthorizationLoginBox.tsx +++ b/frontend/src/components/authorization/AuthorizationLoginBox.tsx @@ -1,11 +1,10 @@ -import {faExclamationCircle} from "@fortawesome/free-solid-svg-icons" -import {FontAwesomeIcon} from "@fortawesome/react-fontawesome" +import {faUser} from "@fortawesome/free-solid-svg-icons" import {Box, Form, Heading, useFormState} from "@steffo/bluelib-react" import * as React from "react" import {useAuthorizationContext} from "../../contexts/authorization" import {SophonToken, SophonUser} from "../../types/SophonTypes" import {Validators} from "../../utils/Validators" -import {Loading} from "../elements/Loading" +import {IconText} from "../elements/IconText" import {useInstanceAxios} from "../instance/useInstanceAxios" @@ -74,9 +73,6 @@ export function AuthorizationLoginBox(): JSX.Element { if(!authorization) { return "" } - if(authorization.state.running) { - return "color-yellow" - } if(error) { return "color-red" } @@ -85,24 +81,12 @@ export function AuthorizationLoginBox(): JSX.Element { [authorization, error], ) - const buttonText = - React.useMemo( - () => { - if(authorization?.state.running) { - return - } - if(error) { - return <> Login - } - return <>Login - }, - [error, authorization], - ) - return ( - Login + + Login +

To use most features of Sophon, an account is required. @@ -128,7 +112,9 @@ export function AuthorizationLoginBox(): JSX.Element { /> - {buttonText} + + Login + diff --git a/frontend/src/components/authorization/AuthorizationLogoutBox.tsx b/frontend/src/components/authorization/AuthorizationLogoutBox.tsx deleted file mode 100644 index 0aff1f2..0000000 --- a/frontend/src/components/authorization/AuthorizationLogoutBox.tsx +++ /dev/null @@ -1,86 +0,0 @@ -import {faUser as faUserRegular} from "@fortawesome/free-regular-svg-icons" -import {faChevronRight, faExclamationCircle, faSignOutAlt, faTimesCircle, faUser as faUserSolid} from "@fortawesome/free-solid-svg-icons" -import {FontAwesomeIcon} from "@fortawesome/react-fontawesome" -import {navigate} from "@reach/router" -import {Box, Form, Heading, Idiomatic as I} from "@steffo/bluelib-react" -import * as React from "react" -import {useAuthorizationContext} from "../../contexts/authorization" - - -export function AuthorizationLogoutBox(): JSX.Element { - const authorization = useAuthorizationContext() - - const loggedUsername = React.useMemo( - () => { - if(!authorization) { - return - Not in a AuthorizationContext - - } - else if(authorization.state.user === undefined) { - return - Not logged in - - } - else if(authorization.state.user === null) { - return - a guest - - } - else { - return - {authorization.state.user.username} - - } - }, - [authorization], - ) - - const canLogout = React.useMemo( - () => ( - authorization !== undefined && authorization.state.user !== undefined && !authorization.state.running - ), - [authorization], - ) - - const doLogout = React.useCallback( - () => { - if(!authorization) { - return - } - - authorization.dispatch({ - type: "clear", - }) - }, - [authorization], - ) - - return ( - - - Logout - -

- You are currently logged in as {loggedUsername}. -

-
- - navigate("l/logged-in/")}> -  Continue to Sophon - - -
-

- To use a different account with Sophon, you'll need to logout from your current one first. -

-
- - -  Logout - - -
-
- ) -} diff --git a/frontend/src/components/authorization/AuthorizationLogoutButton.tsx b/frontend/src/components/authorization/AuthorizationLogoutButton.tsx new file mode 100644 index 0000000..2276fd3 --- /dev/null +++ b/frontend/src/components/authorization/AuthorizationLogoutButton.tsx @@ -0,0 +1,34 @@ +import {faSignOutAlt} from "@fortawesome/free-solid-svg-icons" +import {Button} from "@steffo/bluelib-react" +import * as React from "react" +import {useAuthorizationContext} from "../../contexts/authorization" +import {CanBeDisabled} from "../../types/ExtraTypes" +import {IconText} from "../elements/IconText" + + +export function AuthorizationLogoutButton({disabled = false}: CanBeDisabled): JSX.Element { + const authorization = + useAuthorizationContext() + + const canLogout = + React.useMemo( + () => ( + !disabled && authorization !== undefined && authorization.state.user !== undefined && !authorization.state.running + ), + [disabled, authorization], + ) + + const onClick = + React.useCallback( + () => authorization!.dispatch({type: "clear"}), + [authorization], + ) + + return ( + + ) +} diff --git a/frontend/src/components/authorization/AuthorizationStepPage.tsx b/frontend/src/components/authorization/AuthorizationStepPage.tsx index 6075b62..c72e13a 100644 --- a/frontend/src/components/authorization/AuthorizationStepPage.tsx +++ b/frontend/src/components/authorization/AuthorizationStepPage.tsx @@ -3,8 +3,8 @@ import * as React from "react" import {useAuthorizationContext} from "../../contexts/authorization" import {AuthorizationAdminBox} from "./AuthorizationAdminBox" import {AuthorizationBrowseBox} from "./AuthorizationBrowseBox" +import {AuthorizationLoggedInBox} from "./AuthorizationLoggedInBox" import {AuthorizationLoginBox} from "./AuthorizationLoginBox" -import {AuthorizationLogoutBox} from "./AuthorizationLogoutBox" export function AuthorizationStepPage(): JSX.Element | null { @@ -18,7 +18,7 @@ export function AuthorizationStepPage(): JSX.Element | null { if(authorization.state.token === null) { return ( - + @@ -28,7 +28,7 @@ export function AuthorizationStepPage(): JSX.Element | null { return ( - + ) diff --git a/frontend/src/components/elements/IconText.tsx b/frontend/src/components/elements/IconText.tsx new file mode 100644 index 0000000..4fef78a --- /dev/null +++ b/frontend/src/components/elements/IconText.tsx @@ -0,0 +1,24 @@ +import {FontAwesomeIcon, FontAwesomeIconProps} from "@fortawesome/react-fontawesome" +import * as React from "react" + + +/** + * The props of {@link IconText}. + */ +export interface IconTextProps extends FontAwesomeIconProps { + children: React.ReactNode, +} + + +/** + * A {@link FontAwesomeIcon} (`icon`) followed by some text (`children`). + * + * @constructor + */ +export function IconText({children, ...props}: IconTextProps): JSX.Element { + return ( + +  {children} + + ) +} \ No newline at end of file diff --git a/frontend/src/types/ExtraTypes.ts b/frontend/src/types/ExtraTypes.ts index c6ad749..d434181 100644 --- a/frontend/src/types/ExtraTypes.ts +++ b/frontend/src/types/ExtraTypes.ts @@ -39,4 +39,12 @@ export interface WithViewSet { */ export interface WithSlug { slug: string, +} + + +/** + * Props of an object that can be disabled. + */ +export interface CanBeDisabled { + disabled?: boolean, } \ No newline at end of file