Skip to content
This repository has been archived by the owner on Jan 23, 2025. It is now read-only.

Commit

Permalink
feat: add skeleton for modal (#1083)
Browse files Browse the repository at this point in the history
* feat: add skeleton for modal

* refactor: update yarn lock
  • Loading branch information
pyphilia authored Mar 19, 2024
1 parent 4cc6a4c commit 26a7e53
Show file tree
Hide file tree
Showing 6 changed files with 179 additions and 112 deletions.
80 changes: 47 additions & 33 deletions src/components/main/itemSelectionModal/AccessibleNavigationTree.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { useState } from 'react';

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

import { ItemType, PermissionLevel } from '@graasp/sdk';

Expand All @@ -26,7 +26,7 @@ const AccessibleNavigationTree = ({
// todo: to change with real recent items (most used)
const [page, setPage] = useState(1);
// todo: show only items with admin rights
const { data: accessibleItems } = hooks.useAccessibleItems(
const { data: accessibleItems, isLoading } = hooks.useAccessibleItems(
{
permissions: [PermissionLevel.Write, PermissionLevel.Admin],
types: [ItemType.FOLDER],
Expand All @@ -38,38 +38,52 @@ const AccessibleNavigationTree = ({
? Math.ceil(accessibleItems.totalCount / PAGE_SIZE)
: 0;

return (
<Stack
height="100%"
flex={1}
direction="column"
justifyContent="space-between"
>
<Stack>
{accessibleItems?.data?.map((ele) => (
<RowMenu
key={ele.id}
item={ele}
onNavigate={onNavigate}
selectedId={selectedId}
onClick={onClick}
isDisabled={isDisabled}
/>
))}
if (accessibleItems) {
return (
<Stack
height="100%"
flex={1}
direction="column"
justifyContent="space-between"
>
<Stack>
{accessibleItems.data.map((ele) => (
<RowMenu
key={ele.id}
item={ele}
onNavigate={onNavigate}
selectedId={selectedId}
onClick={onClick}
isDisabled={isDisabled}
/>
))}
</Stack>
<Stack direction="row" justifyContent="end">
{nbPages > 1 && (
<Pagination
sx={{ justifyContent: 'end' }}
size="small"
count={nbPages}
page={page}
onChange={(_, p) => setPage(p)}
/>
)}
</Stack>
</Stack>
<Stack direction="row" justifyContent="end">
{nbPages > 1 && (
<Pagination
sx={{ justifyContent: 'end' }}
size="small"
count={nbPages}
page={page}
onChange={(_, p) => setPage(p)}
/>
)}
</Stack>
</Stack>
);
);
}

if (isLoading) {
return (
<>
<Skeleton height={50} />
<Skeleton height={50} />
<Skeleton height={50} />
</>
);
}

return <Alert severity="error">An unexpected error happened</Alert>;
};

export default AccessibleNavigationTree;
57 changes: 36 additions & 21 deletions src/components/main/itemSelectionModal/ChildrenNavigationTree.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Box } from '@mui/material';
import { Alert, Box, Skeleton } from '@mui/material';

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

Expand All @@ -25,28 +25,43 @@ const ChildrenNavigationTree = ({
isDisabled,
}: ChildrenNavigationTreeProps): JSX.Element => {
const { t: translateBuilder } = useBuilderTranslation();
const { data: children } = hooks.useChildren(selectedNavigationItem.id);
const { data: children, isLoading } = hooks.useChildren(
selectedNavigationItem.id,
);
// TODO: use hook's filter when available
const folders = children?.filter((f) => f.type === ItemType.FOLDER);
return (
<>
{folders?.map((ele) => (
<RowMenu
key={ele.id}
item={ele}
onNavigate={onNavigate}
selectedId={selectedId}
onClick={onClick}
isDisabled={isDisabled}
/>
))}
{!folders?.length && (
<Box sx={{ color: 'darkgrey', pt: 1 }}>
{translateBuilder(BUILDER.EMPTY_FOLDER_CHILDREN_FOR_THIS_ITEM)}
</Box>
)}
</>
);

if (children) {
return (
<>
{folders?.map((ele) => (
<RowMenu
key={ele.id}
item={ele}
onNavigate={onNavigate}
selectedId={selectedId}
onClick={onClick}
isDisabled={isDisabled}
/>
))}
{!folders?.length && (
<Box sx={{ color: 'darkgrey', pt: 1 }}>
{translateBuilder(BUILDER.EMPTY_FOLDER_CHILDREN_FOR_THIS_ITEM)}
</Box>
)}
</>
);
}
if (isLoading) {
return (
<>
<Skeleton height={50} />
<Skeleton height={50} />
<Skeleton height={50} />
</>
);
}
return <Alert severity="error">An unexpected error happened</Alert>;
};

export default ChildrenNavigationTree;
28 changes: 20 additions & 8 deletions src/components/main/itemSelectionModal/ItemSelectionModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
DialogActions,
DialogContent,
DialogTitle,
Skeleton,
Stack,
} from '@mui/material';

Expand Down Expand Up @@ -57,14 +58,18 @@ const ItemSelectionModal = ({
titleKey,
}: ItemSelectionModalProps): JSX.Element => {
const { t: translateBuilder } = useBuilderTranslation();
const { data: items } = hooks.useItems(itemIds);

const title = computeTitle({
items,
count: itemIds.length - 1,
translateBuilder,
translateKey: titleKey,
});
const { data: items, isLoading } = hooks.useItems(itemIds);

const title = items ? (
computeTitle({
items,
count: itemIds.length - 1,
translateBuilder,
translateKey: titleKey,
})
) : (
<Skeleton height={50} />
);

// special elements for breadcrumbs
// root displays specific paths
Expand Down Expand Up @@ -181,6 +186,13 @@ const ItemSelectionModal = ({
rootMenuItems={[MY_GRAASP_BREADCRUMB]}
/>
)}
{isLoading && (
<>
<Skeleton height={50} />
<Skeleton height={50} />
<Skeleton height={50} />
</>
)}
{selectedNavigationItem.id === MY_GRAASP_BREADCRUMB.id && (
<AccessibleNavigationTree
isDisabled={isDisabledLocal}
Expand Down
104 changes: 59 additions & 45 deletions src/components/main/itemSelectionModal/RootNavigationTree.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Typography } from '@mui/material';
import { Alert, Skeleton, Typography } from '@mui/material';

import { DiscriminatedItem, ItemType, PermissionLevel } from '@graasp/sdk';

Expand Down Expand Up @@ -29,7 +29,7 @@ const RootNavigationTree = ({
const { t: translateBuilder } = useBuilderTranslation();

// todo: to change with real recent items (most used)
const { data: recentItems } = hooks.useAccessibleItems(
const { data: recentItems, isLoading } = hooks.useAccessibleItems(
// you can move into an item you have at least write permission
{
permissions: [PermissionLevel.Admin, PermissionLevel.Write],
Expand All @@ -46,55 +46,69 @@ const RootNavigationTree = ({
path: items[0].path,
});

return (
<>
<Typography color="darkgrey" variant="subtitle2">
{translateBuilder(BUILDER.HOME_TITLE)}
</Typography>
{rootMenuItems.map((mi) => (
<RowMenu
key={mi.name}
item={mi}
onNavigate={onNavigate}
selectedId={selectedId}
onClick={onClick}
// root items cannot be disabled - but they are disabled by the button
/>
))}
{recentFolders && (
<>
<Typography color="darkgrey" variant="subtitle2">
{translateBuilder(BUILDER.ITEM_SELECTION_NAVIGATION_RECENT_ITEMS)}
</Typography>
{recentFolders.map((item) => (
if (recentItems) {
return (
<>
<Typography color="darkgrey" variant="subtitle2">
{translateBuilder(BUILDER.HOME_TITLE)}
</Typography>
{rootMenuItems.map((mi) => (
<RowMenu
key={mi.name}
item={mi}
onNavigate={onNavigate}
selectedId={selectedId}
onClick={onClick}
// root items cannot be disabled - but they are disabled by the button
/>
))}
{recentFolders && (
<>
<Typography color="darkgrey" variant="subtitle2">
{translateBuilder(BUILDER.ITEM_SELECTION_NAVIGATION_RECENT_ITEMS)}
</Typography>
{recentFolders.map((item) => (
<RowMenu
key={item.name}
item={item}
onNavigate={onNavigate}
selectedId={selectedId}
onClick={onClick}
isDisabled={isDisabled}
/>
))}
</>
)}
{/* show second parent to allow moving a level above */}
{parents && parents.length > 1 && (
<>
<Typography color="darkgrey" variant="subtitle2">
{translateBuilder(BUILDER.ITEM_SELECTION_NAVIGATION_PARENT)}
</Typography>
<RowMenu
key={item.name}
item={item}
item={parents[parents.length - 2]}
onNavigate={onNavigate}
selectedId={selectedId}
onClick={onClick}
isDisabled={isDisabled}
/>
))}
</>
)}
{/* show second parent to allow moving a level above */}
{parents && parents.length > 1 && (
<>
<Typography color="darkgrey" variant="subtitle2">
{translateBuilder(BUILDER.ITEM_SELECTION_NAVIGATION_PARENT)}
</Typography>
<RowMenu
item={parents[parents.length - 2]}
onNavigate={onNavigate}
selectedId={selectedId}
onClick={onClick}
isDisabled={isDisabled}
/>
</>
)}
</>
);
</>
)}
</>
);
}

if (isLoading) {
return (
<>
<Skeleton height={50} />
<Skeleton height={50} />
<Skeleton height={50} />
</>
);
}

return <Alert severity="error">An unexpected error happened</Alert>;
};

export default RootNavigationTree;
18 changes: 15 additions & 3 deletions src/components/main/itemSelectionModal/RowMenu.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
import { useState } from 'react';

import { KeyboardArrowRight } from '@mui/icons-material';
import { Button, IconButton, Stack, Typography, styled } from '@mui/material';
import {
Button,
CircularProgress,
IconButton,
Stack,
Typography,
styled,
} from '@mui/material';

import { ItemType } from '@graasp/sdk';
import { ItemIcon } from '@graasp/ui';
Expand Down Expand Up @@ -40,6 +47,7 @@ const RowMenu = ({
isDisabled,
}: RowMenuProps): JSX.Element | null => {
const [isHoverActive, setIsHoverActive] = useState(false);
const [isLoading, setIsLoading] = useState(false);

const handleHover = () => {
setIsHoverActive(true);
Expand Down Expand Up @@ -82,9 +90,13 @@ const RowMenu = ({
{item.name}
</Typography>
</StyledButton>
{(isHoverActive || selectedId === item.id) && (
{isLoading && <CircularProgress size={20} />}
{!isLoading && (isHoverActive || selectedId === item.id) && (
<IconButton
onClick={() => onNavigate(item)}
onClick={() => {
setIsLoading(true);
onNavigate(item);
}}
id={buildItemRowArrowId(item.id)}
size="small"
>
Expand Down
Loading

0 comments on commit 26a7e53

Please sign in to comment.