Skip to content

Commit

Permalink
fix: update main component and refactor (graasp#491)
Browse files Browse the repository at this point in the history
fix: some translations
  • Loading branch information
spaenleh authored Feb 2, 2024
1 parent 7e597d3 commit cbe0ad9
Show file tree
Hide file tree
Showing 23 changed files with 333 additions and 236 deletions.
17 changes: 12 additions & 5 deletions cypress/e2e/navigation.cy.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
import { PermissionLevel } from '@graasp/sdk';

import { buildMainPath } from '@/config/paths';
import { SHOW_MORE_ITEMS_ID, buildTreeItemClass } from '@/config/selectors';
import {
HOME_PAGE_PAGINATION_ID,
buildHomePaginationId,
buildTreeItemClass,
} from '@/config/selectors';

import {
FOLDER_WITH_SUBFOLDER_ITEM,
Expand All @@ -27,8 +31,8 @@ describe('Navigation', () => {
cy.visit('/');

cy.wait(['@getCurrentMember', '@getAccessibleItems']);

cy.get(`#${SHOW_MORE_ITEMS_ID}`).click();
cy.get(`#${HOME_PAGE_PAGINATION_ID}`).scrollIntoView().should('be.visible');
cy.get(`#${buildHomePaginationId(2)}`).click();
});

it('Expand folder when navigating', () => {
Expand All @@ -38,8 +42,11 @@ describe('Navigation', () => {

const child = FOLDER_WITH_SUBFOLDER_ITEM.items[1];
const childOfChild = FOLDER_WITH_SUBFOLDER_ITEM.items[3];
cy.get(`.${buildTreeItemClass(child.id)}`).click();
cy.get(`.${buildTreeItemClass(childOfChild.id)}`).should('be.visible');
// we need to to use the `:visible` meta selector because there are 2 navigations (one for mobile hidden, and one for desktop)
cy.get(`.${buildTreeItemClass(child.id)}:visible`).click();
cy.get(`.${buildTreeItemClass(childOfChild.id)}:visible`).should(
'be.visible',
);
});

it('show all folders for partial order', () => {
Expand Down
11 changes: 8 additions & 3 deletions cypress/support/integrationUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,14 @@ export const expectLinkViewScreenLayout = ({

if (!html) {
if (settings?.showLinkButton ?? DEFAULT_LINK_SHOW_BUTTON) {
cy.get('[data-testid="OpenInNewIcon"]').should('be.visible');
cy.get('[data-testid="OpenInNewIcon"]')
.scrollIntoView()
.should('be.visible');
} else {
// button should not be shown when the setting is false
cy.get('[data-testid="OpenInNewIcon"]').should('not.exist');
cy.get('[data-testid="OpenInNewIcon"]')
.scrollIntoView()
.should('not.exist');
}
}
};
Expand Down Expand Up @@ -138,7 +142,8 @@ export const expectFolderLayout = ({
.filter(({ type }) => type === ItemType.FOLDER)
.forEach(({ id }) => {
// click in mainmenu
cy.get(`.${buildTreeItemClass(id)}`).click();
// there are two because of th two menus
cy.get(`.${buildTreeItemClass(id)}:visible`).click();

expectFolderLayout({ rootId: id, items });
});
Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,10 @@
"@emotion/react": "11.11.1",
"@emotion/styled": "11.11.0",
"@graasp/chatbox": "3.0.3",
"@graasp/query-client": "2.2.3",
"@graasp/query-client": "2.4.2",
"@graasp/sdk": "3.5.0",
"@graasp/translations": "1.21.1",
"@graasp/ui": "4.4.0",
"@graasp/ui": "4.5.0",
"@mui/icons-material": "5.14.19",
"@mui/lab": "5.0.0-alpha.151",
"@mui/material": "5.14.19",
Expand Down
10 changes: 7 additions & 3 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ import { useCurrentMemberContext } from '@/contexts/CurrentMemberContext';
import HomePage from '@/modules/pages/HomePage';
import ItemPage from '@/modules/pages/ItemPage';

import PageWrapper from './modules/layout/PageWrapper';

export const App = (): JSX.Element => {
const location = useLocation();
const [searchParams, setSearchParams] = useSearchParams();
Expand Down Expand Up @@ -50,9 +52,11 @@ export const App = (): JSX.Element => {

return (
<Routes>
<Route path={buildMainPath()} element={<ItemPage />} />
<Route path={HOME_PATH} element={<HomePageWithAuthorization />} />
<Route element={<Navigate to={HOME_PATH} />} />
<Route element={<PageWrapper />}>
<Route path={buildMainPath()} element={<ItemPage />} />
<Route path={HOME_PATH} element={<HomePageWithAuthorization />} />
<Route path="*" element={<Navigate to={HOME_PATH} />} />
</Route>
</Routes>
);
};
Expand Down
8 changes: 7 additions & 1 deletion src/Root.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ import { ToastContainer } from 'react-toastify';
import { CssBaseline, GlobalStyles } from '@mui/material';
import { ThemeProvider } from '@mui/material/styles';

// todo: set locale based on member local using
// https://mui.com/material-ui/customization/theming/#api
// and https://mui.com/material-ui/guides/localization/#locale-text
// with the deepMerge util function
import { theme } from '@graasp/ui';

import { SHOW_NOTIFICATIONS } from '@/config/env';
Expand Down Expand Up @@ -36,7 +40,9 @@ const Root = (): JSX.Element => (
</Router>
</ThemeProvider>
</I18nextProvider>
{import.meta.env.DEV && <ReactQueryDevtools />}
{import.meta.env.DEV && import.meta.env.MODE !== 'test' && (
<ReactQueryDevtools />
)}
</QueryClientProvider>
);

Expand Down
3 changes: 0 additions & 3 deletions src/config/queryClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,6 @@ const {
enableWebsocket: true,
defaultQueryOptions: {
keepPreviousData: true,
// avoid refetching when same data are closely fetched
staleTime: 1000, // ms
cacheTime: 1000, // ms
},
});
export {
Expand Down
4 changes: 4 additions & 0 deletions src/config/selectors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,10 @@ export const OWN_ITEMS_GRID_ID = 'ownItemsGrid';
export const buildMemberAvatarClass = (id?: string): string =>
`memberAvatar-${id}`;

export const HOME_PAGE_PAGINATION_ID = 'homePagePagination';
export const buildHomePaginationId = (page: number | null): string =>
`homePagination-${page}`;

export const APP_NAVIGATION_PLATFORM_SWITCH_ID = 'appNavigationPlatformSwitch';
export const APP_NAVIGATION_PLATFORM_SWITCH_BUTTON_IDS = {
[Platform.Builder]: 'appNavigationPlatformSwitchButtonBuilder',
Expand Down
10 changes: 6 additions & 4 deletions src/contexts/ItemContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@ import { DiscriminatedItem } from '@graasp/sdk';
import { hooks } from '@/config/queryClient';

type Props = {
rootId: string;
rootId?: string;
children: JSX.Element | JSX.Element[];
};

type ItemContextType = {
rootId: string;
rootId?: string;
focusedItemId?: string;
setFocusedItemId: (id: string) => void;
rootItem?: DiscriminatedItem;
Expand All @@ -24,7 +24,9 @@ type ItemContextType = {
const ItemContext = React.createContext<ItemContextType>({
rootId: '',
focusedItemId: '',
setFocusedItemId: () => null,
setFocusedItemId: (id: string) => {
console.error(`Called setFocusedItemId(${id}) without a matching Provider`);
},
isRootItemLoading: true,
isRootItemError: false,
isDescendantsLoading: true,
Expand All @@ -42,7 +44,7 @@ const ItemContextProvider = ({ children, rootId }: Props): JSX.Element => {
data: descendants,
isLoading: isDescendantsLoading,
isError: isDescendantsError,
} = hooks.useDescendants({ id: rootId, enabled: true });
} = hooks.useDescendants({ id: rootId ?? '', enabled: true });

const value = useMemo(
() => ({
Expand Down
4 changes: 4 additions & 0 deletions src/langs/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,8 @@ export const PLAYER = {
HIDDEN_WRAPPER_TOOLTIP: 'HIDDEN_WRAPPER_TOOLTIP',
SHOW_MORE: 'SHOW_MORE',
RECENT_ITEMS_TITLE: 'RECENT_ITEMS_TITLE',
DRAWER_ARIAL_LABEL: 'DRAWER_ARIAL_LABEL',
ERROR_FETCHING_ITEM: 'ERROR_FETCHING_ITEM',
ERROR_ACCESSING_ITEM: 'ERROR_ACCESSING_ITEM',
ERROR_ACCESSING_ITEM_HELPER: 'ERROR_ACCESSING_ITEM_HELPER',
};
6 changes: 5 additions & 1 deletion src/langs/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,9 @@
"LOAD_MORE": "Load more",
"HIDDEN_WRAPPER_TOOLTIP": "This element is hidden, you can see it because you have admin or write access, users with read access won't see it",
"SHOW_MORE": "Show More...",
"RECENT_ITEMS_TITLE": "Most Recent Items"
"RECENT_ITEMS_TITLE": "Most Recent Items",
"DRAWER_ARIAL_LABEL": "Open drawer",
"ERROR_FETCHING_ITEM": "There was an error fetching the requested item",
"ERROR_ACCESSING_ITEM": "You cannot access this item",
"ERROR_ACCESSING_ITEM_HELPER": "Your current account does not have the rights to access this item."
}
57 changes: 20 additions & 37 deletions src/modules/item/ItemForbiddenScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,11 @@ import AccountCircleIcon from '@mui/icons-material/AccountCircle';
import BlockIcon from '@mui/icons-material/Block';
import { IconButton, Stack, Typography } from '@mui/material';

import { Context } from '@graasp/sdk';
import { AUTH } from '@graasp/translations';
import { Button, Main } from '@graasp/ui';
import { Button } from '@graasp/ui';

import { useAuthTranslation } from '@/config/i18n';
import HeaderNavigation from '@/modules/header/HeaderNavigation';
import HeaderRightContent from '@/modules/header/HeaderRightContent';
import { PLAYER } from '@/langs/constants';
import UserSwitchWrapper from '@/modules/userSwitch/UserSwitchWrapper';

const ItemForbiddenScreen: FC = () => {
Expand All @@ -25,40 +23,25 @@ const ItemForbiddenScreen: FC = () => {
);

return (
<Main
open={false}
context={Context.Player}
headerLeftContent={<HeaderNavigation topItemName="" />}
headerRightContent={<HeaderRightContent />}
<Stack
direction="column"
justifyContent="center"
alignItems="center"
textAlign="center"
margin="auto"
height="100%"
>
<Stack
direction="column"
justifyContent="center"
alignItems="center"
textAlign="center"
margin="auto"
height="100%"
>
<Typography variant="h4">
<IconButton size="large">
<BlockIcon />
</IconButton>
{
// todo: add translations
t('You cannot access this item')
}
</Typography>
<Typography variant="body1">
{
// todo: add translations
t(
'Your current account does not have the rights to access this item.',
)
}
</Typography>
<UserSwitchWrapper ButtonContent={ButtonContent} preserveUrl />
</Stack>
</Main>
<Typography variant="h4">
<IconButton size="large">
<BlockIcon />
</IconButton>
{t(PLAYER.ERROR_ACCESSING_ITEM)}
</Typography>
<Typography variant="body1">
{t(PLAYER.ERROR_ACCESSING_ITEM_HELPER)}
</Typography>
<UserSwitchWrapper ButtonContent={ButtonContent} preserveUrl />
</Stack>
);
};

Expand Down
61 changes: 20 additions & 41 deletions src/modules/item/MainScreen.tsx
Original file line number Diff line number Diff line change
@@ -1,71 +1,50 @@
import { useState } from 'react';
import { useTranslation } from 'react-i18next';
import { useParams } from 'react-router-dom';

import { Alert, Skeleton, Typography } from '@mui/material';

import { Context } from '@graasp/sdk';
import { Main, useMobileView } from '@graasp/ui';

import { ROOT_ID_PATH } from '@/config/paths';
import { hooks } from '@/config/queryClient';
import { useItemContext } from '@/contexts/ItemContext';
import { LayoutContextProvider } from '@/contexts/LayoutContext';
import HeaderNavigation from '@/modules/header/HeaderNavigation';
import HeaderRightContent from '@/modules/header/HeaderRightContent';
import { PLAYER } from '@/langs/constants';
import SideContent from '@/modules/rightPanel/SideContent';

import Item from './Item';
import ItemNavigation from './ItemNavigation';

const MainScreen = (): JSX.Element => {
const { isMobile } = useMobileView();

const MainScreen = (): JSX.Element | null => {
const rootId = useParams()[ROOT_ID_PATH];
const { focusedItemId } = useItemContext();
const mainId = focusedItemId || rootId;
const { data: item, isLoading, isError } = hooks.useItem(mainId);
const { t } = useTranslation();
const [topItemName, setTopItemName] = useState('');
const [isFirstItem, setIsFirstItem] = useState(true);

if (isLoading) {
return <Skeleton variant="rectangular" width="100%" />;
}

if (!item || isError) {
// todo: add this to translations
return <Alert severity="error">{t('This item does not exist')}</Alert>;
}

if (isFirstItem) {
setTopItemName(item.name);
setIsFirstItem(false);
}

const content = !rootId ? (
const content = rootId ? (
<Item id={mainId} />
) : (
<Typography align="center" variant="h4">
{t('No item defined.')}
</Typography>
) : (
<Item id={mainId} />
);

return (
<Main
open={!isMobile && Boolean(rootId)}
context={Context.Player}
sidebar={<ItemNavigation />}
headerLeftContent={
<HeaderNavigation rootId={rootId} topItemName={topItemName} />
}
headerRightContent={<HeaderRightContent />}
>
if (item) {
return (
<LayoutContextProvider>
<SideContent item={item} content={content} />
</LayoutContextProvider>
</Main>
);
);
}

if (isLoading) {
return <Skeleton variant="rectangular" width="100%" />;
}

if (isError) {
// todo: add this to translations
return <Alert severity="error">{t(PLAYER.ERROR_FETCHING_ITEM)}</Alert>;
}

return null;
};

export default MainScreen;
Loading

0 comments on commit cbe0ad9

Please sign in to comment.