-
Notifications
You must be signed in to change notification settings - Fork 9
/
CreateSectionWidget.tsx
128 lines (113 loc) · 3.92 KB
/
CreateSectionWidget.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
import { CODE_NUMPAD_ENTER, CODE_RETURN } from 'keycode-js'
import { styled } from '@mui/material/styles'
import { useSnackbar } from 'notistack'
import React, { ChangeEvent, useState } from 'react'
import { Button, Grid, TextField } from '@mui/material'
import APIErrorMessage from './APIErrorMessage.js'
import { addCourseSections } from '../api.js'
import { CanvasCourseBase, CanvasCourseSection } from '../models/canvas.js'
import { CanvasCoursesSectionNameValidator, ICanvasSectionNameInvalidError } from '../utils/canvasSectionNameValidator.js'
import { CsrfToken } from '../models/models.js'
const PREFIX = 'CreateSectionWidget'
const classes = {
root: `${PREFIX}-root`,
input: `${PREFIX}-input`,
button: `${PREFIX}-button`
}
// TODO jss-to-styled codemod: The Fragment root was replaced by div. Change the tag if needed.
const Root = styled('div')((
{
theme
}
) => ({
[`& .${classes.root}`]: {
backgroundColor: '#FAFAFA',
height: 200
},
[`& .${classes.input}`]: {
width: '100%'
},
[`& .${classes.button}`]: {
width: '100%'
}
}))
export interface CreateSectionWidgetProps {
course: CanvasCourseBase
csrfToken: CsrfToken
onSectionCreated: (newSection: CanvasCourseSection) => void
}
function CreateSectionWidget (props: CreateSectionWidgetProps): JSX.Element {
const { enqueueSnackbar } = useSnackbar()
const [newSectionName, setNewSectionName] = useState<string>('')
const [isCreating, setIsCreating] = useState(false)
const nameValidator = new CanvasCoursesSectionNameValidator(props.course.id)
const newSectionNameChanged = (event: ChangeEvent<HTMLInputElement>): void => {
setNewSectionName(event.target.value)
}
const errorAlert = (errors: ICanvasSectionNameInvalidError[]): void => {
const errorMessage = errors.map(e => { return e.reason }).join('<br/>')
enqueueSnackbar(errorMessage, {
variant: 'error'
})
}
const createSection = (): void => {
if (newSectionName.trim().length === 0) {
return
}
setIsCreating(true)
nameValidator.validateSectionName(newSectionName).then(errors => {
if (errors.length === 0) {
addCourseSections(props.course.id, [newSectionName], props.csrfToken.token)
.then(newSections => {
props.onSectionCreated(newSections[0])
setNewSectionName('')
enqueueSnackbar('Section was created!', { variant: 'success' })
}).catch((error: unknown) => {
enqueueSnackbar(
<APIErrorMessage
context='creating the section'
error={error instanceof Error ? error : undefined}
/>,
{ variant: 'error' }
)
})
} else {
errorAlert(errors)
}
}).catch((error: unknown) => {
enqueueSnackbar(
<APIErrorMessage
context='validating section name'
error={error instanceof Error ? error : undefined}
/>,
{ variant: 'error' }
)
}).finally(() => {
setIsCreating(false)
})
}
const isCreateDisabled = (): boolean => {
return isCreating || newSectionName.trim().length === 0
}
const keyDown = (code: string): void => {
if (isCreateDisabled()) return
if (code === CODE_RETURN || code === CODE_NUMPAD_ENTER) {
createSection()
}
}
return (
(<Root>
<Grid container spacing={2}>
<Grid item xs={12} sm={9}>
<TextField className={classes.input} size='small' label='input the name of the new section' variant='outlined' id="outlined-basic" onChange={newSectionNameChanged} value={newSectionName} onKeyDown={(e) => keyDown(e.code)}/>
</Grid>
<Grid item xs={12} sm>
<Button className={classes.button} variant="contained" color="primary" onClick={createSection} value={newSectionName} disabled={isCreateDisabled()}>
Create
</Button>
</Grid>
</Grid>
</Root>)
)
}
export default CreateSectionWidget