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

Commit ac3c307

Browse files
committed
feat: add skeleton for modal
1 parent f29d176 commit ac3c307

8 files changed

+182
-150
lines changed

package.json

+3
Original file line numberDiff line numberDiff line change
@@ -150,5 +150,8 @@
150150
"vite-plugin-checker": "0.6.4",
151151
"vite-plugin-istanbul": "5.0.0"
152152
},
153+
"resolutions": {
154+
"@graasp/ui": "4.9.3"
155+
},
153156
"packageManager": "[email protected]"
154157
}
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { useState } from 'react';
22

3-
import { Pagination, Stack } from '@mui/material';
3+
import { Alert, Pagination, Skeleton, Stack } from '@mui/material';
44

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

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

41-
return (
42-
<Stack
43-
height="100%"
44-
flex={1}
45-
direction="column"
46-
justifyContent="space-between"
47-
>
48-
<Stack>
49-
{accessibleItems?.data?.map((ele) => (
50-
<RowMenu
51-
key={ele.id}
52-
item={ele}
53-
onNavigate={onNavigate}
54-
selectedId={selectedId}
55-
onClick={onClick}
56-
isDisabled={isDisabled}
57-
/>
58-
))}
41+
if (accessibleItems) {
42+
return (
43+
<Stack
44+
height="100%"
45+
flex={1}
46+
direction="column"
47+
justifyContent="space-between"
48+
>
49+
<Stack>
50+
{accessibleItems.data.map((ele) => (
51+
<RowMenu
52+
key={ele.id}
53+
item={ele}
54+
onNavigate={onNavigate}
55+
selectedId={selectedId}
56+
onClick={onClick}
57+
isDisabled={isDisabled}
58+
/>
59+
))}
60+
</Stack>
61+
<Stack direction="row" justifyContent="end">
62+
{nbPages > 1 && (
63+
<Pagination
64+
sx={{ justifyContent: 'end' }}
65+
size="small"
66+
count={nbPages}
67+
page={page}
68+
onChange={(_, p) => setPage(p)}
69+
/>
70+
)}
71+
</Stack>
5972
</Stack>
60-
<Stack direction="row" justifyContent="end">
61-
{nbPages > 1 && (
62-
<Pagination
63-
sx={{ justifyContent: 'end' }}
64-
size="small"
65-
count={nbPages}
66-
page={page}
67-
onChange={(_, p) => setPage(p)}
68-
/>
69-
)}
70-
</Stack>
71-
</Stack>
72-
);
73+
);
74+
}
75+
76+
if (isLoading) {
77+
return (
78+
<>
79+
<Skeleton height={50} />
80+
<Skeleton height={50} />
81+
<Skeleton height={50} />
82+
</>
83+
);
84+
}
85+
86+
return <Alert severity="error">An unexpected error happened</Alert>;
7387
};
7488

7589
export default AccessibleNavigationTree;
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Box } from '@mui/material';
1+
import { Alert, Box, Skeleton } from '@mui/material';
22

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

@@ -25,28 +25,43 @@ const ChildrenNavigationTree = ({
2525
isDisabled,
2626
}: ChildrenNavigationTreeProps): JSX.Element => {
2727
const { t: translateBuilder } = useBuilderTranslation();
28-
const { data: children } = hooks.useChildren(selectedNavigationItem.id);
28+
const { data: children, isLoading } = hooks.useChildren(
29+
selectedNavigationItem.id,
30+
);
2931
// TODO: use hook's filter when available
3032
const folders = children?.filter((f) => f.type === ItemType.FOLDER);
31-
return (
32-
<>
33-
{folders?.map((ele) => (
34-
<RowMenu
35-
key={ele.id}
36-
item={ele}
37-
onNavigate={onNavigate}
38-
selectedId={selectedId}
39-
onClick={onClick}
40-
isDisabled={isDisabled}
41-
/>
42-
))}
43-
{!folders?.length && (
44-
<Box sx={{ color: 'darkgrey', pt: 1 }}>
45-
{translateBuilder(BUILDER.EMPTY_FOLDER_CHILDREN_FOR_THIS_ITEM)}
46-
</Box>
47-
)}
48-
</>
49-
);
33+
34+
if (children) {
35+
return (
36+
<>
37+
{folders?.map((ele) => (
38+
<RowMenu
39+
key={ele.id}
40+
item={ele}
41+
onNavigate={onNavigate}
42+
selectedId={selectedId}
43+
onClick={onClick}
44+
isDisabled={isDisabled}
45+
/>
46+
))}
47+
{!folders?.length && (
48+
<Box sx={{ color: 'darkgrey', pt: 1 }}>
49+
{translateBuilder(BUILDER.EMPTY_FOLDER_CHILDREN_FOR_THIS_ITEM)}
50+
</Box>
51+
)}
52+
</>
53+
);
54+
}
55+
if (isLoading) {
56+
return (
57+
<>
58+
<Skeleton height={50} />
59+
<Skeleton height={50} />
60+
<Skeleton height={50} />
61+
</>
62+
);
63+
}
64+
return <Alert severity="error">An unexpected error happened</Alert>;
5065
};
5166

5267
export default ChildrenNavigationTree;

src/components/main/itemSelectionModal/ItemSelectionModal.tsx

+20-8
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import {
77
DialogActions,
88
DialogContent,
99
DialogTitle,
10+
Skeleton,
1011
Stack,
1112
} from '@mui/material';
1213

@@ -57,14 +58,18 @@ const ItemSelectionModal = ({
5758
titleKey,
5859
}: ItemSelectionModalProps): JSX.Element => {
5960
const { t: translateBuilder } = useBuilderTranslation();
60-
const { data: items } = hooks.useItems(itemIds);
61-
62-
const title = computeTitle({
63-
items,
64-
count: itemIds.length - 1,
65-
translateBuilder,
66-
translateKey: titleKey,
67-
});
61+
const { data: items, isLoading } = hooks.useItems(itemIds);
62+
63+
const title = items ? (
64+
computeTitle({
65+
items,
66+
count: itemIds.length - 1,
67+
translateBuilder,
68+
translateKey: titleKey,
69+
})
70+
) : (
71+
<Skeleton height={50} />
72+
);
6873

6974
// special elements for breadcrumbs
7075
// root displays specific paths
@@ -181,6 +186,13 @@ const ItemSelectionModal = ({
181186
rootMenuItems={[MY_GRAASP_BREADCRUMB]}
182187
/>
183188
)}
189+
{isLoading && (
190+
<>
191+
<Skeleton height={50} />
192+
<Skeleton height={50} />
193+
<Skeleton height={50} />
194+
</>
195+
)}
184196
{selectedNavigationItem.id === MY_GRAASP_BREADCRUMB.id && (
185197
<AccessibleNavigationTree
186198
isDisabled={isDisabledLocal}
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Typography } from '@mui/material';
1+
import { Alert, Skeleton, Typography } from '@mui/material';
22

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

@@ -29,7 +29,7 @@ const RootNavigationTree = ({
2929
const { t: translateBuilder } = useBuilderTranslation();
3030

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

49-
return (
50-
<>
51-
<Typography color="darkgrey" variant="subtitle2">
52-
{translateBuilder(BUILDER.HOME_TITLE)}
53-
</Typography>
54-
{rootMenuItems.map((mi) => (
55-
<RowMenu
56-
key={mi.name}
57-
item={mi}
58-
onNavigate={onNavigate}
59-
selectedId={selectedId}
60-
onClick={onClick}
61-
// root items cannot be disabled - but they are disabled by the button
62-
/>
63-
))}
64-
{recentFolders && (
65-
<>
66-
<Typography color="darkgrey" variant="subtitle2">
67-
{translateBuilder(BUILDER.ITEM_SELECTION_NAVIGATION_RECENT_ITEMS)}
68-
</Typography>
69-
{recentFolders.map((item) => (
49+
if (recentItems) {
50+
return (
51+
<>
52+
<Typography color="darkgrey" variant="subtitle2">
53+
{translateBuilder(BUILDER.HOME_TITLE)}
54+
</Typography>
55+
{rootMenuItems.map((mi) => (
56+
<RowMenu
57+
key={mi.name}
58+
item={mi}
59+
onNavigate={onNavigate}
60+
selectedId={selectedId}
61+
onClick={onClick}
62+
// root items cannot be disabled - but they are disabled by the button
63+
/>
64+
))}
65+
{recentFolders && (
66+
<>
67+
<Typography color="darkgrey" variant="subtitle2">
68+
{translateBuilder(BUILDER.ITEM_SELECTION_NAVIGATION_RECENT_ITEMS)}
69+
</Typography>
70+
{recentFolders.map((item) => (
71+
<RowMenu
72+
key={item.name}
73+
item={item}
74+
onNavigate={onNavigate}
75+
selectedId={selectedId}
76+
onClick={onClick}
77+
isDisabled={isDisabled}
78+
/>
79+
))}
80+
</>
81+
)}
82+
{/* show second parent to allow moving a level above */}
83+
{parents && parents.length > 1 && (
84+
<>
85+
<Typography color="darkgrey" variant="subtitle2">
86+
{translateBuilder(BUILDER.ITEM_SELECTION_NAVIGATION_PARENT)}
87+
</Typography>
7088
<RowMenu
71-
key={item.name}
72-
item={item}
89+
item={parents[parents.length - 2]}
7390
onNavigate={onNavigate}
7491
selectedId={selectedId}
7592
onClick={onClick}
7693
isDisabled={isDisabled}
7794
/>
78-
))}
79-
</>
80-
)}
81-
{/* show second parent to allow moving a level above */}
82-
{parents && parents.length > 1 && (
83-
<>
84-
<Typography color="darkgrey" variant="subtitle2">
85-
{translateBuilder(BUILDER.ITEM_SELECTION_NAVIGATION_PARENT)}
86-
</Typography>
87-
<RowMenu
88-
item={parents[parents.length - 2]}
89-
onNavigate={onNavigate}
90-
selectedId={selectedId}
91-
onClick={onClick}
92-
isDisabled={isDisabled}
93-
/>
94-
</>
95-
)}
96-
</>
97-
);
95+
</>
96+
)}
97+
</>
98+
);
99+
}
100+
101+
if (isLoading) {
102+
return (
103+
<>
104+
<Skeleton height={50} />
105+
<Skeleton height={50} />
106+
<Skeleton height={50} />
107+
</>
108+
);
109+
}
110+
111+
return <Alert severity="error">An unexpected error happened</Alert>;
98112
};
99113

100114
export default RootNavigationTree;

src/components/main/itemSelectionModal/RowMenu.tsx

+15-3
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,14 @@
11
import { useState } from 'react';
22

33
import { KeyboardArrowRight } from '@mui/icons-material';
4-
import { Button, IconButton, Stack, Typography, styled } from '@mui/material';
4+
import {
5+
Button,
6+
CircularProgress,
7+
IconButton,
8+
Stack,
9+
Typography,
10+
styled,
11+
} from '@mui/material';
512

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

4452
const handleHover = () => {
4553
setIsHoverActive(true);
@@ -82,9 +90,13 @@ const RowMenu = ({
8290
{item.name}
8391
</Typography>
8492
</StyledButton>
85-
{(isHoverActive || selectedId === item.id) && (
93+
{isLoading && <CircularProgress size={20} />}
94+
{!isLoading && (isHoverActive || selectedId === item.id) && (
8695
<IconButton
87-
onClick={() => onNavigate(item)}
96+
onClick={() => {
97+
setIsLoading(true);
98+
onNavigate(item);
99+
}}
88100
id={buildItemRowArrowId(item.id)}
89101
size="small"
90102
>

0 commit comments

Comments
 (0)