-
Notifications
You must be signed in to change notification settings - Fork 17
/
Copy pathGridList.tsx
143 lines (133 loc) · 4.71 KB
/
GridList.tsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
import * as React from 'react';
import {
useTheme,
useMediaQuery,
Box,
ImageList,
ImageListItem,
ImageListItemBar,
} from '@mui/material';
import {
Identifier,
useCreatePath,
NumberField,
useListContext,
useResourceContext,
} from 'react-admin';
import { Link } from 'react-router-dom';
import { Lock, useGetLocks } from '@react-admin/ra-realtime';
import { LockOverlay } from './LockOverlay';
import { USDFormat } from '../formatUtils';
const GridList = () => {
const { isPending } = useListContext();
return isPending ? <LoadingGridList /> : <LoadedGridList />;
};
const useColsForWidth = () => {
const theme = useTheme();
const sm = useMediaQuery(theme.breakpoints.up('sm'));
const md = useMediaQuery(theme.breakpoints.up('md'));
const lg = useMediaQuery(theme.breakpoints.up('lg'));
const xl = useMediaQuery(theme.breakpoints.up('xl'));
// there are all dividers of 24, to have full rows on each page
if (xl) return 8;
if (lg) return 6;
if (md) return 4;
if (sm) return 3;
return 2;
};
const times = (nbChildren: number, fn: (key: number) => any) =>
Array.from({ length: nbChildren }, (_, key) => fn(key));
const LoadingGridList = () => {
const theme = useTheme();
const { perPage } = useListContext();
const cols = useColsForWidth();
return (
<ImageList
rowHeight={180}
cols={cols}
sx={{ m: 0 }}
gap={parseInt(theme.spacing(1))}
>
{times(perPage, key => (
<ImageListItem key={key}>
<Box
bgcolor="grey.500"
height="100%"
sx={{ opacity: 0.5 }}
/>
</ImageListItem>
))}
</ImageList>
);
};
const LoadedGridList = () => {
const theme = useTheme();
const { data } = useListContext();
const resource = useResourceContext();
const { data: locks } = useGetLocks(resource!, {}, { enabled: !!resource });
const cols = useColsForWidth();
const createPath = useCreatePath();
const firstLockRecordId = React.useRef<Identifier>();
if (!data) return null;
return (
<ImageList
data-tour-id="grid-line"
rowHeight={180}
cols={cols}
gap={parseInt(theme.spacing(1))}
sx={{ m: 0 }}
>
{data.map(record => {
const lock = locks
? locks.find((l: Lock) => l.recordId === record.id)
: undefined;
if (lock && !firstLockRecordId.current) {
firstLockRecordId.current = lock.recordId;
}
const isFirstLock = firstLockRecordId.current === record.id;
return (
<ImageListItem
component={Link}
key={record.id}
to={createPath({
resource: 'products',
id: record.id,
type: 'edit',
})}
data-productid={record.id}
data-lockidentity={lock ? lock.identity : undefined}
data-testid={
isFirstLock ? 'productlocktile' : undefined
}
>
<img src={record.thumbnail} alt="" />
{lock && <LockOverlay lock={lock} />}
<ImageListItemBar
title={record.reference}
subtitle={
<span>
{record.width}x{record.height},{' '}
<NumberField
source="price"
record={record}
color="inherit"
options={USDFormat(2)}
sx={{
display: 'inline',
fontSize: '1em',
}}
/>
</span>
}
sx={{
background:
'linear-gradient(to top, rgba(0,0,0,0.8) 0%,rgba(0,0,0,0.4) 70%,rgba(0,0,0,0) 100%)',
}}
/>
</ImageListItem>
);
})}
</ImageList>
);
};
export default GridList;