cozy-ui 130.9.0 → 130.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +22 -0
- package/package.json +1 -1
- package/react/Checkbox/Readme.md +44 -39
- package/react/Checkbox/index.jsx +12 -2
- package/react/EditBadge/EditMenu.jsx +102 -0
- package/react/EditBadge/Readme.md +22 -0
- package/react/EditBadge/StatusWrapper.jsx +32 -0
- package/react/EditBadge/helpers.js +102 -0
- package/react/EditBadge/index.jsx +81 -0
- package/react/EditBadge/locales/en.json +18 -0
- package/react/EditBadge/locales/fr.json +18 -0
- package/react/EditBadge/locales/index.js +11 -0
- package/react/EditBadge/locales/ru.json +18 -0
- package/react/EditBadge/locales/vi.json +18 -0
- package/react/MuiCozyTheme/overrides/makeLightNormalOverrides.js +4 -2
- package/react/Radios/Readme.md +63 -71
- package/react/Switch/Readme.md +93 -46
- package/react/utils/react.js +14 -1
- package/transpiled/react/Checkbox/index.d.ts +6 -2
- package/transpiled/react/Checkbox/index.js +6 -2
- package/transpiled/react/EditBadge/EditMenu.d.ts +11 -0
- package/transpiled/react/EditBadge/EditMenu.js +93 -0
- package/transpiled/react/EditBadge/StatusWrapper.d.ts +9 -0
- package/transpiled/react/EditBadge/StatusWrapper.js +44 -0
- package/transpiled/react/EditBadge/helpers.d.ts +20 -0
- package/transpiled/react/EditBadge/helpers.js +153 -0
- package/transpiled/react/EditBadge/index.d.ts +23 -0
- package/transpiled/react/EditBadge/index.js +89 -0
- package/transpiled/react/EditBadge/locales/index.d.ts +10 -0
- package/transpiled/react/EditBadge/locales/index.js +78 -0
- package/transpiled/react/MuiCozyTheme/overrides/makeDarkInvertedOverrides.d.ts +2 -0
- package/transpiled/react/MuiCozyTheme/overrides/makeDarkNormalOverrides.d.ts +2 -0
- package/transpiled/react/MuiCozyTheme/overrides/makeLightInvertedOverrides.d.ts +2 -0
- package/transpiled/react/MuiCozyTheme/overrides/makeLightNormalOverrides.d.ts +2 -0
- package/transpiled/react/MuiCozyTheme/overrides/makeLightNormalOverrides.js +4 -2
- package/transpiled/react/utils/react.d.ts +1 -0
- package/transpiled/react/utils/react.js +19 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,25 @@
|
|
|
1
|
+
# [130.11.0](https://github.com/cozy/cozy-ui/compare/v130.10.0...v130.11.0) (2025-10-21)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Bug Fixes
|
|
5
|
+
|
|
6
|
+
* **Checkbox:** Now `label` type also accept `node` in addition to `string` ([caf3de5](https://github.com/cozy/cozy-ui/commit/caf3de5))
|
|
7
|
+
* **Switch:** Adjust spacing to better deal with `start` label's position ([528834b](https://github.com/cozy/cozy-ui/commit/528834b))
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
### Features
|
|
11
|
+
|
|
12
|
+
* **Checkbox:** Add `labelPlacement` prop ([24c884d](https://github.com/cozy/cozy-ui/commit/24c884d))
|
|
13
|
+
|
|
14
|
+
# [130.10.0](https://github.com/cozy/cozy-ui/compare/v130.9.0...v130.10.0) (2025-10-16)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
### Features
|
|
18
|
+
|
|
19
|
+
* Add EditBadge component ([47e98d2](https://github.com/cozy/cozy-ui/commit/47e98d2))
|
|
20
|
+
* **EditBadge:** We can now pass props to the main Badge component ([98eb169](https://github.com/cozy/cozy-ui/commit/98eb169))
|
|
21
|
+
* **Utils/React:** Add `AddPropsToChildren` function ([1724619](https://github.com/cozy/cozy-ui/commit/1724619))
|
|
22
|
+
|
|
1
23
|
# [130.9.0](https://github.com/cozy/cozy-ui/compare/v130.8.1...v130.9.0) (2025-10-16)
|
|
2
24
|
|
|
3
25
|
|
package/package.json
CHANGED
package/react/Checkbox/Readme.md
CHANGED
|
@@ -3,49 +3,54 @@
|
|
|
3
3
|
```jsx
|
|
4
4
|
import Checkbox from 'cozy-ui/transpiled/react/Checkbox'
|
|
5
5
|
import Grid from 'cozy-ui/transpiled/react/Grid'
|
|
6
|
+
import Variants from 'cozy-ui/docs/components/Variants'
|
|
7
|
+
|
|
8
|
+
const initialVariants = [{ before: false }]
|
|
6
9
|
|
|
7
10
|
;
|
|
8
11
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
<Grid
|
|
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
|
-
|
|
12
|
+
<Variants initialVariants={initialVariants} screenshotAllVariants>
|
|
13
|
+
{variant => (
|
|
14
|
+
<Grid container>
|
|
15
|
+
<Grid item xs={6} sm={3}>
|
|
16
|
+
<div><Checkbox label="Checkbox" labelPlacement={variant.before ? "start" : "end"} /></div>
|
|
17
|
+
<div><Checkbox label="Small Checked" size="small" labelPlacement={variant.before ? "start" : "end"} /></div>
|
|
18
|
+
<div><Checkbox label="Checked checkbox" checked labelPlacement={variant.before ? "start" : "end"} /></div>
|
|
19
|
+
<div><Checkbox label="Mixed checkbox" mixed labelPlacement={variant.before ? "start" : "end"} /></div>
|
|
20
|
+
<div><Checkbox label="Mixed checked checkbox" checked mixed labelPlacement={variant.before ? "start" : "end"} /></div>
|
|
21
|
+
<div><Checkbox label="No effect" disableEffect labelPlacement={variant.before ? "start" : "end"} /></div>
|
|
22
|
+
<div><Checkbox label="Small no effect" size="small" disableEffect labelPlacement={variant.before ? "start" : "end"} /></div>
|
|
23
|
+
</Grid>
|
|
24
|
+
<Grid item xs={6} sm={3}>
|
|
25
|
+
<div><Checkbox label="Disabled checkbox" disabled labelPlacement={variant.before ? "start" : "end"} /></div>
|
|
26
|
+
<div><Checkbox label="Small disabled checkbox" size="small" disabled labelPlacement={variant.before ? "start" : "end"} /></div>
|
|
27
|
+
<div><Checkbox label="Disabled checked checkbox" checked disabled labelPlacement={variant.before ? "start" : "end"} /></div>
|
|
28
|
+
<div><Checkbox label="Disabled mixed checkbox" mixed disabled labelPlacement={variant.before ? "start" : "end"} /></div>
|
|
29
|
+
<div><Checkbox label="Disabled mixed checked checkbox" checked mixed disabled labelPlacement={variant.before ? "start" : "end"} /></div>
|
|
30
|
+
<div><Checkbox label="Disabled no effect" disableEffect disabled labelPlacement={variant.before ? "start" : "end"} /></div>
|
|
31
|
+
<div><Checkbox label="Small disabled no effect" size="small" disableEffect disabled labelPlacement={variant.before ? "start" : "end"} /></div>
|
|
32
|
+
</Grid>
|
|
33
|
+
<Grid item xs={6} sm={3}>
|
|
34
|
+
<div><Checkbox label="Error checkbox" error labelPlacement={variant.before ? "start" : "end"} /></div>
|
|
35
|
+
<div><Checkbox label="Small error checkbox" size="small" error labelPlacement={variant.before ? "start" : "end"} /></div>
|
|
36
|
+
<div><Checkbox label="Error checked checkbox" error checked labelPlacement={variant.before ? "start" : "end"} /></div>
|
|
37
|
+
<div><Checkbox label="Error mixed checkbox" error mixed labelPlacement={variant.before ? "start" : "end"} /></div>
|
|
38
|
+
<div><Checkbox label="Error mixed checked checkbox" error checked mixed labelPlacement={variant.before ? "start" : "end"} /></div>
|
|
39
|
+
<div><Checkbox label="Error no effect" error disableEffect labelPlacement={variant.before ? "start" : "end"} /></div>
|
|
40
|
+
<div><Checkbox label="Small error no effect" size="small" error disableEffect labelPlacement={variant.before ? "start" : "end"} /></div>
|
|
41
|
+
</Grid>
|
|
42
|
+
<Grid item xs={6} sm={3}>
|
|
43
|
+
<div><Checkbox label="Error disabled checkbox" error disabled labelPlacement={variant.before ? "start" : "end"} /></div>
|
|
44
|
+
<div><Checkbox label="Small error disabled checkbox" size="small" error disabled labelPlacement={variant.before ? "start" : "end"} /></div>
|
|
45
|
+
<div><Checkbox label="Error disabled checked checkbox" error checked disabled labelPlacement={variant.before ? "start" : "end"} /></div>
|
|
46
|
+
<div><Checkbox label="Error disabled mixed checkbox" error mixed disabled labelPlacement={variant.before ? "start" : "end"} /></div>
|
|
47
|
+
<div><Checkbox label="Error disabled mixed checked checkbox" error checked mixed disabled labelPlacement={variant.before ? "start" : "end"} /></div>
|
|
48
|
+
<div><Checkbox label="Error disabled no effect" error disableEffect disabled labelPlacement={variant.before ? "start" : "end"} /></div>
|
|
49
|
+
<div><Checkbox label="Small error disabled no effect" size="small" error disableEffect disabled labelPlacement={variant.before ? "start" : "end"} /></div>
|
|
50
|
+
</Grid>
|
|
46
51
|
</Grid>
|
|
47
|
-
|
|
48
|
-
|
|
52
|
+
)}
|
|
53
|
+
</Variants>
|
|
49
54
|
```
|
|
50
55
|
|
|
51
56
|
### Checkbox with complex children
|
package/react/Checkbox/index.jsx
CHANGED
|
@@ -52,7 +52,14 @@ const DefaultCheckbox = ({
|
|
|
52
52
|
)
|
|
53
53
|
}
|
|
54
54
|
|
|
55
|
-
const Checkbox = ({
|
|
55
|
+
const Checkbox = ({
|
|
56
|
+
className,
|
|
57
|
+
label,
|
|
58
|
+
labelPlacement,
|
|
59
|
+
onChange,
|
|
60
|
+
children,
|
|
61
|
+
...props
|
|
62
|
+
}) => {
|
|
56
63
|
if (children) {
|
|
57
64
|
logDepecratedCheckbox(
|
|
58
65
|
'<Checkbox> used with children is deprecated, please use <Checkbox label={something} /> instead of <Checkbox>something</Checkbox>'
|
|
@@ -69,6 +76,7 @@ const Checkbox = ({ className, label, onChange, children, ...props }) => {
|
|
|
69
76
|
className
|
|
70
77
|
)}
|
|
71
78
|
label={label || children}
|
|
79
|
+
labelPlacement={labelPlacement}
|
|
72
80
|
control={<DefaultCheckbox {...props} label={label} />}
|
|
73
81
|
onChange={onChange}
|
|
74
82
|
/>
|
|
@@ -93,7 +101,8 @@ Checkbox.propTypes = {
|
|
|
93
101
|
mixed: PropTypes.bool,
|
|
94
102
|
disableEffect: PropTypes.bool,
|
|
95
103
|
size: PropTypes.oneOf(['small', 'medium']),
|
|
96
|
-
|
|
104
|
+
labelPlacement: PropTypes.oneOf(['top', 'end', 'bottom', 'start']),
|
|
105
|
+
label: PropTypes.oneOfType([PropTypes.string, PropTypes.node])
|
|
97
106
|
}
|
|
98
107
|
|
|
99
108
|
Checkbox.defaultProps = {
|
|
@@ -103,6 +112,7 @@ Checkbox.defaultProps = {
|
|
|
103
112
|
mixed: false,
|
|
104
113
|
disableEffect: false,
|
|
105
114
|
size: 'medium',
|
|
115
|
+
labelPlacement: 'end',
|
|
106
116
|
label: ''
|
|
107
117
|
}
|
|
108
118
|
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import React, { useRef } from 'react'
|
|
2
|
+
|
|
3
|
+
import { handleDelete, handleUpload } from './helpers'
|
|
4
|
+
import { locales } from './locales'
|
|
5
|
+
import Icon from '../Icon'
|
|
6
|
+
import CameraIcon from '../Icons/Camera'
|
|
7
|
+
import TrashIcon from '../Icons/Trash'
|
|
8
|
+
import ListItemIcon from '../ListItemIcon'
|
|
9
|
+
import ListItemText from '../ListItemText'
|
|
10
|
+
import Menu from '../Menu'
|
|
11
|
+
import MenuItem from '../MenuItem'
|
|
12
|
+
import { useAlert } from '../providers/Alert'
|
|
13
|
+
import { useI18n, useExtendI18n } from '../providers/I18n'
|
|
14
|
+
|
|
15
|
+
const EditMenu = ({
|
|
16
|
+
anchorRef,
|
|
17
|
+
status,
|
|
18
|
+
showMenu,
|
|
19
|
+
setShowMenu,
|
|
20
|
+
setStatus,
|
|
21
|
+
setTimestamp,
|
|
22
|
+
onUpload,
|
|
23
|
+
onDelete
|
|
24
|
+
}) => {
|
|
25
|
+
useExtendI18n(locales)
|
|
26
|
+
const { t } = useI18n()
|
|
27
|
+
const { showAlert } = useAlert()
|
|
28
|
+
|
|
29
|
+
const fileInputRef = useRef(null)
|
|
30
|
+
|
|
31
|
+
return (
|
|
32
|
+
<>
|
|
33
|
+
<input
|
|
34
|
+
className="u-dn"
|
|
35
|
+
type="file"
|
|
36
|
+
ref={fileInputRef}
|
|
37
|
+
accept="image/*"
|
|
38
|
+
onChange={event =>
|
|
39
|
+
handleUpload({
|
|
40
|
+
event,
|
|
41
|
+
t,
|
|
42
|
+
fileInputRef,
|
|
43
|
+
status,
|
|
44
|
+
onUpload,
|
|
45
|
+
setStatus,
|
|
46
|
+
setTimestamp,
|
|
47
|
+
setShowMenu,
|
|
48
|
+
showAlert
|
|
49
|
+
})
|
|
50
|
+
}
|
|
51
|
+
/>
|
|
52
|
+
{showMenu && (
|
|
53
|
+
<Menu
|
|
54
|
+
open
|
|
55
|
+
anchorEl={anchorRef}
|
|
56
|
+
getContentAnchorEl={null}
|
|
57
|
+
anchorOrigin={{
|
|
58
|
+
vertical: 'bottom',
|
|
59
|
+
horizontal: 'left'
|
|
60
|
+
}}
|
|
61
|
+
transformOrigin={{
|
|
62
|
+
vertical: 'top',
|
|
63
|
+
horizontal: 'left'
|
|
64
|
+
}}
|
|
65
|
+
onClose={() => setShowMenu(false)}
|
|
66
|
+
>
|
|
67
|
+
<MenuItem
|
|
68
|
+
onClick={() => {
|
|
69
|
+
setShowMenu(false)
|
|
70
|
+
fileInputRef.current.click() // triggers onChange of the input
|
|
71
|
+
}}
|
|
72
|
+
>
|
|
73
|
+
<ListItemIcon>
|
|
74
|
+
<Icon icon={CameraIcon} />
|
|
75
|
+
</ListItemIcon>
|
|
76
|
+
<ListItemText primary={t('EditBadge.menu.update')} />
|
|
77
|
+
</MenuItem>
|
|
78
|
+
<MenuItem
|
|
79
|
+
onClick={() =>
|
|
80
|
+
handleDelete({
|
|
81
|
+
t,
|
|
82
|
+
status,
|
|
83
|
+
onDelete,
|
|
84
|
+
setShowMenu,
|
|
85
|
+
setStatus,
|
|
86
|
+
setTimestamp,
|
|
87
|
+
showAlert
|
|
88
|
+
})
|
|
89
|
+
}
|
|
90
|
+
>
|
|
91
|
+
<ListItemIcon>
|
|
92
|
+
<Icon icon={TrashIcon} />
|
|
93
|
+
</ListItemIcon>
|
|
94
|
+
<ListItemText primary={t('EditBadge.menu.delete')} />
|
|
95
|
+
</MenuItem>
|
|
96
|
+
</Menu>
|
|
97
|
+
)}
|
|
98
|
+
</>
|
|
99
|
+
)
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export default EditMenu
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
⚠️ Must be used within `AlertProvider`.
|
|
2
|
+
|
|
3
|
+
```jsx
|
|
4
|
+
import DemoProvider from 'cozy-ui/docs/components/DemoProvider'
|
|
5
|
+
import AlertProvider from 'cozy-ui/transpiled/react/providers/Alert'
|
|
6
|
+
import EditBadge from 'cozy-ui/transpiled/react/EditBadge'
|
|
7
|
+
import Avatar from 'cozy-ui/transpiled/react/Avatar'
|
|
8
|
+
|
|
9
|
+
;
|
|
10
|
+
|
|
11
|
+
<DemoProvider>
|
|
12
|
+
<AlertProvider>
|
|
13
|
+
<EditBadge
|
|
14
|
+
src={timestamp => ""}
|
|
15
|
+
onUpload={file => {}}
|
|
16
|
+
onDelete={() => {}}
|
|
17
|
+
>
|
|
18
|
+
<Avatar size={94} alt="Avatar" />
|
|
19
|
+
</EditBadge>
|
|
20
|
+
</AlertProvider>
|
|
21
|
+
</DemoProvider>
|
|
22
|
+
```
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import cx from 'classnames'
|
|
2
|
+
import React from 'react'
|
|
3
|
+
|
|
4
|
+
import Spinner from '../Spinner'
|
|
5
|
+
import { AddPropsToChildren } from '../utils/react'
|
|
6
|
+
|
|
7
|
+
const StatusWrapper = ({ src, status, setStatus, timestamp, children }) => {
|
|
8
|
+
if (status === 'LOADING') {
|
|
9
|
+
return (
|
|
10
|
+
<>
|
|
11
|
+
{AddPropsToChildren(children, childProps => ({
|
|
12
|
+
className: cx(childProps.className, 'u-o-50')
|
|
13
|
+
}))}
|
|
14
|
+
<Spinner className="u-m-0" middle size="large" />
|
|
15
|
+
</>
|
|
16
|
+
)
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
if (status === 'PRESENT') {
|
|
20
|
+
return AddPropsToChildren(children, () => ({
|
|
21
|
+
key: timestamp,
|
|
22
|
+
src,
|
|
23
|
+
onError: () => setStatus('ABSENT')
|
|
24
|
+
}))
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return AddPropsToChildren(children, () => ({
|
|
28
|
+
key: timestamp
|
|
29
|
+
}))
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export default StatusWrapper
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
const MAX_FILE_SIZE = 5 * 1024 * 1024
|
|
2
|
+
const ALLOWED_TYPES = ['image/jpeg', 'image/png', 'image/gif', 'image/webp']
|
|
3
|
+
|
|
4
|
+
export const handleUpload = async ({
|
|
5
|
+
event,
|
|
6
|
+
t,
|
|
7
|
+
fileInputRef,
|
|
8
|
+
status,
|
|
9
|
+
onUpload,
|
|
10
|
+
setStatus,
|
|
11
|
+
setTimestamp,
|
|
12
|
+
setShowMenu,
|
|
13
|
+
showAlert
|
|
14
|
+
}) => {
|
|
15
|
+
const file = event.target.files[0]
|
|
16
|
+
if (!file) return
|
|
17
|
+
|
|
18
|
+
if (file.size > MAX_FILE_SIZE) {
|
|
19
|
+
showAlert({
|
|
20
|
+
message: t('EditBadge.upload.file-size'),
|
|
21
|
+
severity: 'error'
|
|
22
|
+
})
|
|
23
|
+
return
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
if (!ALLOWED_TYPES.includes(file.type)) {
|
|
27
|
+
showAlert({
|
|
28
|
+
message: t('EditBadge.upload.file-type'),
|
|
29
|
+
severity: 'error'
|
|
30
|
+
})
|
|
31
|
+
return
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const controller = new AbortController()
|
|
35
|
+
const timeoutId = setTimeout(() => controller.abort(), 30000)
|
|
36
|
+
|
|
37
|
+
const previouStatus = status
|
|
38
|
+
setStatus('LOADING')
|
|
39
|
+
|
|
40
|
+
try {
|
|
41
|
+
await onUpload(file)
|
|
42
|
+
clearTimeout(timeoutId)
|
|
43
|
+
|
|
44
|
+
const newTimestamp = Date.now()
|
|
45
|
+
setStatus('PRESENT')
|
|
46
|
+
setTimestamp(newTimestamp)
|
|
47
|
+
showAlert({
|
|
48
|
+
message: t('EditBadge.upload.success'),
|
|
49
|
+
severity: 'success'
|
|
50
|
+
})
|
|
51
|
+
} catch (error) {
|
|
52
|
+
clearTimeout(timeoutId)
|
|
53
|
+
setStatus(previouStatus)
|
|
54
|
+
showAlert({
|
|
55
|
+
message: t('EditBadge.upload.error'),
|
|
56
|
+
severity: 'error'
|
|
57
|
+
})
|
|
58
|
+
} finally {
|
|
59
|
+
setShowMenu(false)
|
|
60
|
+
if (fileInputRef.current) {
|
|
61
|
+
fileInputRef.current.value = ''
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export const handleDelete = async ({
|
|
67
|
+
t,
|
|
68
|
+
status,
|
|
69
|
+
onDelete,
|
|
70
|
+
setShowMenu,
|
|
71
|
+
setStatus,
|
|
72
|
+
setTimestamp,
|
|
73
|
+
showAlert
|
|
74
|
+
}) => {
|
|
75
|
+
setShowMenu(false)
|
|
76
|
+
|
|
77
|
+
const controller = new AbortController()
|
|
78
|
+
const timeoutId = setTimeout(() => controller.abort(), 30000)
|
|
79
|
+
const previousStatus = status
|
|
80
|
+
setStatus('LOADING')
|
|
81
|
+
|
|
82
|
+
try {
|
|
83
|
+
await onDelete()
|
|
84
|
+
clearTimeout(timeoutId)
|
|
85
|
+
|
|
86
|
+
const checkTimestamp = Date.now()
|
|
87
|
+
|
|
88
|
+
setStatus('ABSENT')
|
|
89
|
+
setTimestamp(checkTimestamp)
|
|
90
|
+
showAlert({
|
|
91
|
+
message: t('EditBadge.delete.success'),
|
|
92
|
+
severity: 'success'
|
|
93
|
+
})
|
|
94
|
+
} catch (error) {
|
|
95
|
+
clearTimeout(timeoutId)
|
|
96
|
+
setStatus(previousStatus)
|
|
97
|
+
showAlert({
|
|
98
|
+
message: t('EditBadge.delete.error'),
|
|
99
|
+
severity: 'error'
|
|
100
|
+
})
|
|
101
|
+
}
|
|
102
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import PropTypes from 'prop-types'
|
|
2
|
+
import React, { useState, useRef } from 'react'
|
|
3
|
+
|
|
4
|
+
import EditMenu from './EditMenu'
|
|
5
|
+
import StatusWrapper from './StatusWrapper'
|
|
6
|
+
import Badge from '../Badge'
|
|
7
|
+
import Button from '../Buttons'
|
|
8
|
+
import Icon from '../Icon'
|
|
9
|
+
import PenIcon from '../Icons/Pen'
|
|
10
|
+
|
|
11
|
+
const EditBadge = ({
|
|
12
|
+
src,
|
|
13
|
+
onUpload,
|
|
14
|
+
onDelete,
|
|
15
|
+
anchorOrigin,
|
|
16
|
+
children,
|
|
17
|
+
...props
|
|
18
|
+
}) => {
|
|
19
|
+
const [showMenu, setShowMenu] = useState(false)
|
|
20
|
+
const [status, setStatus] = useState('PRESENT') // PRESENT || ABSENT || LOADING
|
|
21
|
+
const [timestamp, setTimestamp] = useState(Date.now())
|
|
22
|
+
|
|
23
|
+
const menuAnchorRef = useRef(null)
|
|
24
|
+
|
|
25
|
+
return (
|
|
26
|
+
<Badge
|
|
27
|
+
{...props}
|
|
28
|
+
anchorOrigin={anchorOrigin}
|
|
29
|
+
badgeContent={
|
|
30
|
+
<>
|
|
31
|
+
<Button
|
|
32
|
+
ref={menuAnchorRef}
|
|
33
|
+
component="div"
|
|
34
|
+
className="u-miw-auto u-w-2-half u-h-2-half u-bdrs-circle"
|
|
35
|
+
classes={{ label: 'u-flex u-w-auto' }}
|
|
36
|
+
style={{
|
|
37
|
+
outline: '4px solid var(--paperBackgroundColor)'
|
|
38
|
+
}}
|
|
39
|
+
label={<Icon icon={PenIcon} />}
|
|
40
|
+
size="small"
|
|
41
|
+
onClick={() => setShowMenu(v => !v)}
|
|
42
|
+
/>
|
|
43
|
+
<EditMenu
|
|
44
|
+
anchorRef={menuAnchorRef.current}
|
|
45
|
+
status={status}
|
|
46
|
+
showMenu={showMenu}
|
|
47
|
+
setShowMenu={setShowMenu}
|
|
48
|
+
setStatus={setStatus}
|
|
49
|
+
setTimestamp={setTimestamp}
|
|
50
|
+
onUpload={onUpload}
|
|
51
|
+
onDelete={onDelete}
|
|
52
|
+
/>
|
|
53
|
+
</>
|
|
54
|
+
}
|
|
55
|
+
>
|
|
56
|
+
<StatusWrapper
|
|
57
|
+
src={src(timestamp)}
|
|
58
|
+
status={status}
|
|
59
|
+
setStatus={setStatus}
|
|
60
|
+
timestamp={timestamp}
|
|
61
|
+
>
|
|
62
|
+
{children}
|
|
63
|
+
</StatusWrapper>
|
|
64
|
+
</Badge>
|
|
65
|
+
)
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
EditBadge.defaultProps = {
|
|
69
|
+
anchorOrigin: {
|
|
70
|
+
vertical: 'bottom',
|
|
71
|
+
horizontal: 'right'
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
EditBadge.propTypes = {
|
|
76
|
+
src: PropTypes.func.isRequired,
|
|
77
|
+
onUpload: PropTypes.func.isRequired,
|
|
78
|
+
onDelete: PropTypes.func.isRequired
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export default EditBadge
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"EditBadge": {
|
|
3
|
+
"menu": {
|
|
4
|
+
"update": "Update",
|
|
5
|
+
"delete": "Delete"
|
|
6
|
+
},
|
|
7
|
+
"upload": {
|
|
8
|
+
"file-size": "The file size limit is 5MB.",
|
|
9
|
+
"file-type": "The file type is not supported. Please try again.",
|
|
10
|
+
"success": "Avatar updated successfully",
|
|
11
|
+
"error": "The avatar upload has failed. Please try again."
|
|
12
|
+
},
|
|
13
|
+
"delete": {
|
|
14
|
+
"success": "Avatar deleted successfully",
|
|
15
|
+
"error": "The avatar deletion has failed. Please try again."
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"EditBadge": {
|
|
3
|
+
"menu": {
|
|
4
|
+
"update": "Mettre à jour",
|
|
5
|
+
"delete": "Supprimer"
|
|
6
|
+
},
|
|
7
|
+
"upload": {
|
|
8
|
+
"file-size": "La taille du fichier est limitée à 5Mo.",
|
|
9
|
+
"file-type": "Le type de fichier n'est pas supporté. Merci de réessayer.",
|
|
10
|
+
"success": "Avatar mis à jour avec succès",
|
|
11
|
+
"error": "La mise à jour de l'avatar a échoué. Merci de réessayer."
|
|
12
|
+
},
|
|
13
|
+
"delete": {
|
|
14
|
+
"success": "Avatar supprimé avec succès",
|
|
15
|
+
"error": "La suppression de l'avatar a échoué. Merci de réessayer."
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"EditBadge": {
|
|
3
|
+
"menu": {
|
|
4
|
+
"update": "Обновить",
|
|
5
|
+
"delete": "Удалить"
|
|
6
|
+
},
|
|
7
|
+
"upload": {
|
|
8
|
+
"file-size": "Максимальный размер файла — 5 МБ.",
|
|
9
|
+
"file-type": "Тип файла не поддерживается. Пожалуйста, попробуйте снова.",
|
|
10
|
+
"success": "Аватар успешно обновлён",
|
|
11
|
+
"error": "Не удалось загрузить аватар. Пожалуйста, попробуйте снова."
|
|
12
|
+
},
|
|
13
|
+
"delete": {
|
|
14
|
+
"success": "Аватар успешно удалён",
|
|
15
|
+
"error": "Не удалось удалить аватар. Пожалуйста, попробуйте снова."
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"EditBadge": {
|
|
3
|
+
"menu": {
|
|
4
|
+
"update": "Cập nhật",
|
|
5
|
+
"delete": "Xóa"
|
|
6
|
+
},
|
|
7
|
+
"upload": {
|
|
8
|
+
"file-size": "Giới hạn kích thước tệp là 5MB.",
|
|
9
|
+
"file-type": "Loại tệp không được hỗ trợ. Vui lòng thử lại.",
|
|
10
|
+
"success": "Cập nhật ảnh đại diện thành công",
|
|
11
|
+
"error": "Tải ảnh đại diện thất bại. Vui lòng thử lại."
|
|
12
|
+
},
|
|
13
|
+
"delete": {
|
|
14
|
+
"success": "Xóa ảnh đại diện thành công",
|
|
15
|
+
"error": "Xóa ảnh đại diện thất bại. Vui lòng thử lại."
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -898,9 +898,10 @@ export const makeLightNormalOverrides = theme => ({
|
|
|
898
898
|
},
|
|
899
899
|
MuiSwitch: {
|
|
900
900
|
root: {
|
|
901
|
-
width:
|
|
901
|
+
width: 56,
|
|
902
902
|
height: 40,
|
|
903
|
-
padding: '6px 1px'
|
|
903
|
+
padding: '6px 1px',
|
|
904
|
+
justifyContent: 'center'
|
|
904
905
|
},
|
|
905
906
|
checked: {
|
|
906
907
|
'& + $track$track': {
|
|
@@ -910,6 +911,7 @@ export const makeLightNormalOverrides = theme => ({
|
|
|
910
911
|
switchBase: {
|
|
911
912
|
padding: 5,
|
|
912
913
|
top: 5,
|
|
914
|
+
left: 5,
|
|
913
915
|
color: theme.palette.text.icon,
|
|
914
916
|
'& .cozySwitchThumb': {
|
|
915
917
|
display: 'flex',
|