diff --git a/package.json b/package.json index 186544f2b..38f492615 100644 --- a/package.json +++ b/package.json @@ -88,7 +88,6 @@ "react-dnd-html5-backend": "16.0.1", "react-quill": "2.0.0", "react-rnd": "10.4.11", - "react-text-mask": "5.5.0", "uuid": "10.0.0", "vitest": "1.6.0" }, diff --git a/src/constants.ts b/src/constants.ts index e28e22f7e..4e7ea9903 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -23,7 +23,6 @@ export const SETTINGS = { }, SIGN_IN_MODE: { PSEUDONYM: 'pseudonym', - MEMBER_ID: 'memberId', }, }, }; diff --git a/src/itemLogin/ItemLoginAuthorization.tsx b/src/itemLogin/ItemLoginAuthorization.tsx index a2e327ed6..92f9517b0 100644 --- a/src/itemLogin/ItemLoginAuthorization.tsx +++ b/src/itemLogin/ItemLoginAuthorization.tsx @@ -29,7 +29,6 @@ export type ItemLoginAuthorizationProps = { usernameInputId?: string; signInButtonId?: string; passwordInputId?: string; - modeSelectId?: string; ForbiddenContent?: ReactElement; }; @@ -41,11 +40,9 @@ const ItemLoginAuthorization = itemId, signIn, Error: ErrorComponent, - memberIdInputId, usernameInputId, signInButtonId, passwordInputId, - modeSelectId, ForbiddenContent = , }: ItemLoginAuthorizationProps) => (ChildComponent: typeof React.Component | (() => JSX.Element)) => { @@ -102,11 +99,9 @@ const ItemLoginAuthorization = itemId={itemId} signIn={signIn} itemLoginSchemaType={itemLoginSchemaType} - memberIdInputId={memberIdInputId} usernameInputId={usernameInputId} signInButtonId={signInButtonId} passwordInputId={passwordInputId} - modeSelectId={modeSelectId} /> ); } diff --git a/src/itemLogin/ItemLoginScreen.stories.tsx b/src/itemLogin/ItemLoginScreen.stories.tsx index 29039ac87..a0bc1b79f 100644 --- a/src/itemLogin/ItemLoginScreen.stories.tsx +++ b/src/itemLogin/ItemLoginScreen.stories.tsx @@ -17,16 +17,6 @@ const meta: Meta = { signIn: fn(), }, argTypes: { - memberIdInputId: { - table: { - category: TABLE_CATEGORIES.SELECTORS, - }, - }, - modeSelectId: { - table: { - category: TABLE_CATEGORIES.SELECTORS, - }, - }, passwordInputId: { table: { category: TABLE_CATEGORIES.SELECTORS, @@ -54,45 +44,42 @@ export const ItemLoginUsernameAndPassword: Story = { args: { itemLoginSchemaType: ItemLoginSchemaType.UsernameAndPassword, }, -}; + play: async ({ args, canvasElement }) => { + const canvas = within(canvasElement); -ItemLoginUsernameAndPassword.play = async ({ args, canvasElement }) => { - const canvas = within(canvasElement); + await userEvent.type( + canvas.getByLabelText('Pseudonym'), + 'email@provider.com', + ); + await userEvent.type(canvas.getByLabelText('Password'), 'mypassword'); + await userEvent.click(canvas.getByText('Sign In')); - await userEvent.type( - canvas.getByLabelText('Pseudonym'), - 'email@provider.com', - ); - await userEvent.type(canvas.getByLabelText('Password'), 'mypassword'); - await userEvent.click(canvas.getByText('Sign In')); - - expect(args.signIn).toHaveBeenCalled(); + expect(args.signIn).toHaveBeenCalled(); + }, }; export const ItemLoginUsername: Story = { args: { itemLoginSchemaType: ItemLoginSchemaType.Username, }, -}; - -ItemLoginUsername.play = async ({ args, canvasElement }) => { - const canvas = within(canvasElement); + play: async ({ args, canvasElement }) => { + const canvas = within(canvasElement); - await userEvent.type( - canvas.getByLabelText('Pseudonym'), - 'email@provider.com', - ); - await userEvent.click(canvas.getByText('Sign In')); + await userEvent.type( + canvas.getByLabelText('Pseudonym'), + 'email@provider.com', + ); + await userEvent.click(canvas.getByText('Sign In')); - expect(args.signIn).toHaveBeenCalled(); + expect(args.signIn).toHaveBeenCalled(); + }, }; export const Forbidden: Story = { args: {}, -}; + play: async ({ canvasElement }) => { + const canvas = within(canvasElement); -Forbidden.play = async ({ canvasElement }) => { - const canvas = within(canvasElement); - - await expect(canvas.getByText(FORBIDDEN_TEXT)).toBeInTheDocument(); + await expect(canvas.getByText(FORBIDDEN_TEXT)).toBeInTheDocument(); + }, }; diff --git a/src/itemLogin/ItemLoginScreen.tsx b/src/itemLogin/ItemLoginScreen.tsx index dba42ba67..7a98978b5 100644 --- a/src/itemLogin/ItemLoginScreen.tsx +++ b/src/itemLogin/ItemLoginScreen.tsx @@ -1,24 +1,18 @@ -import InfoIcon from '@mui/icons-material/Info'; -import { - Container, - FormControlLabel, - MenuItem, - Select, - SelectChangeEvent, - TextField, - Tooltip, - styled, -} from '@mui/material'; +import { Container, Stack, TextField, styled } from '@mui/material'; -import React, { FC, ReactElement, ReactNode, useRef, useState } from 'react'; +import { + ChangeEvent, + KeyboardEvent, + ReactElement, + useRef, + useState, +} from 'react'; import { useTranslation } from 'react-i18next'; import { ItemLoginSchemaType, UUID } from '@graasp/sdk'; import Button from '../buttons/Button'; -import { SETTINGS } from '../constants'; import ForbiddenText from './ForbiddenText'; -import MemberIdTextField from './MemberIdTextField'; import { isMemberIdValid } from './utils'; export type SignInPropertiesType = { @@ -37,26 +31,9 @@ const WrapperContainer = styled(Container)({ }); const StyledTextField = styled(TextField)(({ theme }) => ({ margin: theme.spacing(1, 0), -})); -const StyledOutlinedInput = styled(TextField)(({ theme }) => ({ - margin: theme.spacing(1, 0), -})); -const UsernameAndMemberIdContainer = styled('div')({ - display: 'flex', - alignItems: 'center', -}); -const SignInWithWrapper = styled(FormControlLabel)(({ theme }) => ({ - justifyContent: 'flex-end', - marginLeft: theme.spacing(0), - '.MuiFormControlLabel-label': { - marginRight: theme.spacing(1), - }, -})); -const UsernameInfoIcon = styled(InfoIcon)(({ theme }) => ({ - margin: theme.spacing(0, 1), -})); +})) as typeof TextField; -export interface ItemLoginScreenProps { +export type ItemLoginScreenProps = { itemId: UUID; /** * item login schema object @@ -67,34 +44,24 @@ export interface ItemLoginScreenProps { * content to display when the user doesn't have access */ ForbiddenContent?: ReactElement; - memberIdInputId?: string; - modeSelectId?: string; - modeSelectLabel?: string; passwordInputId?: string; signInButtonId?: string; usernameInputId?: string; -} +}; -const ItemLoginScreen: FC = ({ +const ItemLoginScreen = ({ ForbiddenContent = , itemId, itemLoginSchemaType, - memberIdInputId, - modeSelectId, - modeSelectLabel, passwordInputId, signIn, signInButtonId, usernameInputId, -}) => { +}: ItemLoginScreenProps): JSX.Element => { const { t } = useTranslation(); - const loginModeRef = useRef(null); + const passwordFieldRef = useRef(null); const [password, setPassword] = useState(); const [username, setUsername] = useState(); - const [memberId, setMemberId] = useState(); - const [signInMode, setSignInMode] = useState( - SETTINGS.ITEM_LOGIN.SIGN_IN_MODE.PSEUDONYM, - ); // no item login detected if ( @@ -109,15 +76,7 @@ const ItemLoginScreen: FC = ({ ); const onClickSignIn = (): void => { - const signInProperties: SignInPropertiesType = {}; - switch (signInMode) { - case SETTINGS.ITEM_LOGIN.SIGN_IN_MODE.MEMBER_ID: - signInProperties.memberId = memberId; - break; - case SETTINGS.ITEM_LOGIN.SIGN_IN_MODE.PSEUDONYM: - default: - signInProperties.username = username; - } + const signInProperties: SignInPropertiesType = { username }; if (withPassword) { signInProperties.password = password; @@ -126,138 +85,65 @@ const ItemLoginScreen: FC = ({ signIn({ itemId, ...signInProperties }); }; - const handleOnSignInModeChange = (e: SelectChangeEvent): void => { - const { value } = e.target; - setSignInMode(value as string); - }; - - const onPasswordChange = (e: React.ChangeEvent): void => { + const onPasswordChange = (e: ChangeEvent): void => { setPassword(e.target.value); }; - const onMemberIdChange = (e: React.ChangeEvent): void => { - setMemberId(e.target.value); - }; - const onUsernameChange = (e: React.ChangeEvent): void => { + const onUsernameChange = (e: ChangeEvent): void => { setUsername(e.target.value); }; - const shouldSignInBeDisabled = (): boolean => { - const usernameError = - signInMode === SETTINGS.ITEM_LOGIN.SIGN_IN_MODE.PSEUDONYM && - (!username?.length || isMemberIdValid(username)); - const memberIdError = - signInMode === SETTINGS.ITEM_LOGIN.SIGN_IN_MODE.MEMBER_ID && - (!memberId?.length || !isMemberIdValid(memberId)); - const passwordError = withPassword && !password?.length; - return usernameError || passwordError || memberIdError; - }; - - const renderMemberIdTextField = (): ReactNode => { - if (signInMode !== SETTINGS.ITEM_LOGIN.SIGN_IN_MODE.MEMBER_ID) { - return null; + const handlePressEnter = (e: KeyboardEvent): void => { + if (e.key === 'Enter') { + onClickSignIn(); } - - const error = memberId?.length && !isMemberIdValid(memberId); - return ( - // - // {/* - // {t('Member Id')} - // */} - - // - ); }; - const renderUsernameTextField = (): ReactNode => { - if (signInMode !== SETTINGS.ITEM_LOGIN.SIGN_IN_MODE.PSEUDONYM) { - return null; + const handleUsernamePressEnter = ( + e: KeyboardEvent, + ): void => { + if (e.key === 'Enter') { + if (withPassword) { + console.log(passwordFieldRef.current); + // focus next field + passwordFieldRef.current?.focus(); + } else { + // single field, send the login + onClickSignIn(); + } } - const isMemberId = isMemberIdValid(username); - const error = Boolean(username?.length && isMemberId); - const helperText = isMemberId - ? t('This is a member id. You should switch the sign in mode.') - : null; - return ( - - ); }; - const renderUsernameOrMemberIdField = (): ReactNode => { - const select = ( - <> - - - - - - ); - - return ( - <> - - - {/* we actually need to render two text fields to avoid data conflicts - using a single function returning one or the other text fields sometimes - lead to the previous data being melded into the new text-field - */} - {renderUsernameTextField()} - {renderMemberIdTextField()} - - - ); + const shouldSignInBeDisabled = (): boolean => { + const usernameError = !username?.length || isMemberIdValid(username); + const passwordError = withPassword && !password?.length; + return usernameError || passwordError; }; + const isMemberId = isMemberIdValid(username); + const error = Boolean(username?.length && isMemberId); + const helperText = isMemberId + ? t('This is a member id. You should switch the sign in mode.') + : null; + return ( - {renderUsernameOrMemberIdField()} + + + {withPassword && ( = ({ color='primary' variant='outlined' id={passwordInputId} + onKeyDown={handlePressEnter} + // used to set focus when first field is filled + inputRef={passwordFieldRef} /> )}