Skip to content

Commit

Permalink
feat: refactor with authorization, change current account type (#1046)
Browse files Browse the repository at this point in the history
* refactor: refactor with authorization, change current account type

* refactor: allow array of components

* refactor: item login authorization

* refactor: change redirection link

* refactor: fix children type

* refactor: change for current member

* refactor: fix type

* feat: add prevent guest wrapper

* refactor: export prevent guest

* refactor: add id to preventguestwrapper

* refactor: remove signed out test

* refactor: fix issues

* refactor: apply PR requested changes

* refactor: apply PR requested changes

* feat: do not show profile for user switch
  • Loading branch information
pyphilia authored Sep 20, 2024
1 parent 9552201 commit bfe516f
Show file tree
Hide file tree
Showing 16 changed files with 510 additions and 258 deletions.
69 changes: 69 additions & 0 deletions src/Authorization/PreventGuestWrapper.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import type { Meta, StoryObj } from '@storybook/react';
import { expect, within } from '@storybook/test';

import { AccountType, CompleteGuest, CompleteMember } from '@graasp/sdk';

import BuildIcon from '@/icons/BuildIcon.js';

import PreventGuestWrapper from './PreventGuestWrapper.js';

const meta = {
title: 'Actions/PreventGuestWrapper',
component: PreventGuestWrapper,

argTypes: {},
args: {
buttonText: 'Log out and Create a Graasp account',
errorText: 'An error occured.',
text: 'You are currently using Graasp with a guest account. In order to use all features of Graasp, you have to log out and create a Graasp account.',
children: (
<div data-testid='content'>
<BuildIcon />
<BuildIcon />
<BuildIcon />
</div>
),
},
} satisfies Meta<typeof PreventGuestWrapper>;

export default meta;

type Story = StoryObj<typeof meta>;

export const Guest = {
args: {
currentAccount: { type: AccountType.Guest } as CompleteGuest,
},
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);

// should see message
await expect(canvas.getByRole('alert')).toBeVisible();
},
} satisfies Story;

export const Individual = {
args: {
currentAccount: { id: 'member', name: 'member' } as CompleteMember,
},
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);

// should see content
await expect(canvas.getByTestId('content')).toBeVisible();
},
} satisfies Story;

export const ShowError = {
args: {
errorText: 'error text',
},
play: async ({ args, canvasElement }) => {
const canvas = within(canvasElement);

// should see error message
if (args.errorText) {
await expect(canvas.getByText(args.errorText)).toBeVisible();
}
},
} satisfies Story;
73 changes: 73 additions & 0 deletions src/Authorization/PreventGuestWrapper.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import { ClipboardPen } from 'lucide-react';

import {
Alert,
Box,
Container,
Button as MuiButton,
Stack,
Typography,
} from '@mui/material';

import { ReactNode } from 'react';

import { AccountType, CurrentAccount } from '@graasp/sdk';

type Props = {
buttonText: string;
children?: ReactNode;
currentAccount?: CurrentAccount | null;
/**
* Component to display on error.
* Overrides errorText
*/
error?: JSX.Element;
errorText: string;
id?: string;
onButtonClick?: () => void;
startIcon?: JSX.Element;
text: string | JSX.Element;
};

const PreventGuestWrapper = ({
buttonText,
children,
currentAccount,
error,
id,
onButtonClick,
startIcon = <ClipboardPen />,
errorText,
text,
}: Props): ReactNode => {
if (currentAccount) {
// guest - should not have access to children
if (currentAccount.type === AccountType.Guest) {
return (
<Stack height='100%' justifyContent='center' alignItems='center'>
<Container maxWidth='md'>
<Alert severity='info' id={id}>
<Typography>{text}</Typography>
<Box mt={2} textAlign='center'>
<MuiButton
startIcon={startIcon}
variant='contained'
sx={{ textTransform: 'none' }}
onClick={onButtonClick}
>
{buttonText}
</MuiButton>
</Box>
</Alert>
</Container>
</Stack>
);
}

return children;
}

return error ?? <Alert severity='error'>{errorText}</Alert>;
};

export default PreventGuestWrapper;
19 changes: 9 additions & 10 deletions src/Authorization/Redirect.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,13 @@ import { expect, within } from '@storybook/test';

import { BrowserRouter } from 'react-router-dom';

import BuildIcon from '../icons/BuildIcon.js';
import withAuthorization from './withAuthorization.js';

const ComponentWithAuthorization = withAuthorization(BuildIcon, {
// use an empty string because we do not want to be redirected but the prop is mandatory
redirectionLink: '',
});
import SignedInWrapper from './SignedInWrapper.js';

// this story is separated from the others
// because the redirection breaks a bit the navigation in storybook
const meta: Meta<typeof ComponentWithAuthorization> = {
const meta: Meta<typeof SignedInWrapper> = {
title: 'Actions/Authorization/Redirect',
component: ComponentWithAuthorization,
component: SignedInWrapper,
parameters: {
docs: {
source: {
Expand All @@ -24,6 +18,11 @@ const meta: Meta<typeof ComponentWithAuthorization> = {
},
},
},
render: () => (
<SignedInWrapper redirectionLink=''>
<div />
</SignedInWrapper>
),
decorators: [
(story) => {
return <BrowserRouter>{story()}</BrowserRouter>;
Expand All @@ -32,7 +31,7 @@ const meta: Meta<typeof ComponentWithAuthorization> = {
};
export default meta;

type Story = StoryObj<typeof ComponentWithAuthorization>;
type Story = StoryObj<typeof SignedInWrapper>;

export const Redirect = {
play: async ({ canvasElement }) => {
Expand Down
45 changes: 45 additions & 0 deletions src/Authorization/SignedInWrapper.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import type { Meta, StoryObj } from '@storybook/react';
import { expect, within } from '@storybook/test';

import { CompleteMember } from '@graasp/sdk';

import BuildIcon from '@/icons/BuildIcon.js';

import SignedInWrapper from './SignedInWrapper.js';

const redirectionLink = 'https://redirect.org';

const meta: Meta<typeof SignedInWrapper> = {
title: 'Actions/SignedInWrapper',
component: SignedInWrapper,

argTypes: {
onRedirect: { action: 'onRedirect' },
},
args: {
redirectionLink,
children: (
<div data-testid='content'>
<BuildIcon />
<BuildIcon />
<BuildIcon />
</div>
),
},
};

export default meta;

type Story = StoryObj<typeof SignedInWrapper>;

export const Authorized: Story = {
args: {
currentAccount: { id: 'member', name: 'member' } as CompleteMember,
},
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);

// should see content
await expect(canvas.getByTestId('content')).toBeVisible();
},
};
41 changes: 41 additions & 0 deletions src/Authorization/SignedInWrapper.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { ReactNode } from 'react';

import { CurrentAccount, redirect } from '@graasp/sdk';

import RedirectionContent from './RedirectionContent.js';

export type SignedInWrapperProps = {
redirectionLink: string;
currentAccount?: CurrentAccount | null;
onRedirect?: () => void;
children?: ReactNode;
};

const SignedInWrapper = ({
currentAccount,
redirectionLink,
onRedirect,
children,
}: SignedInWrapperProps): SignedInWrapperProps['children'] => {
const redirectToSignIn = (): void => {
if (!redirectionLink) {
console.debug('No link has been set for redirection');
return;
}
redirect(window, redirectionLink);
};

// check authorization: user shouldn't be empty
if (currentAccount?.id) {
return children;
}

onRedirect?.();

redirectToSignIn();

// redirect page if redirection is not working
return <RedirectionContent link={redirectionLink} />;
};

export default SignedInWrapper;
36 changes: 0 additions & 36 deletions src/Authorization/withAuthorization.stories.tsx

This file was deleted.

39 changes: 0 additions & 39 deletions src/Authorization/withAuthorization.tsx

This file was deleted.

4 changes: 2 additions & 2 deletions src/UserSwitch/UserSwitch.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ type Story = StoryObj<typeof meta>;
export const SignedIn = {
args: {
currentMember: MOCK_CURRENT_MEMBER,
renderAvatar: () => (
avatar: (
<Avatar
maxWidth={SMALL_AVATAR_SIZE}
maxHeight={SMALL_AVATAR_SIZE}
Expand Down Expand Up @@ -48,7 +48,7 @@ export const SignedIn = {

export const SignedOut = {
args: {
renderAvatar: () => (
avatar: (
<Avatar
maxWidth={SMALL_AVATAR_SIZE}
maxHeight={SMALL_AVATAR_SIZE}
Expand Down
Loading

0 comments on commit bfe516f

Please sign in to comment.