@@ -3,8 +3,9 @@ import withStyles from '../../components/jss'
3
3
import { useState , useCallback } from 'preact/hooks'
4
4
import Modal from '../../components/modal'
5
5
6
- import { updateChallenge , deleteChallenge } from '../../api/admin/challs'
6
+ import { updateChallenge , deleteChallenge , uploadFiles } from '../../api/admin/challs'
7
7
import { useToast } from '../../components/toast'
8
+ import { encodeFile } from '../../util'
8
9
9
10
const DeleteModal = withStyles ( {
10
11
modalBody : {
@@ -50,7 +51,7 @@ const DeleteModal = withStyles({
50
51
)
51
52
} )
52
53
53
- const Problem = ( { classes, problem } ) => {
54
+ const Problem = ( { classes, problem, update : updateClient } ) => {
54
55
const { toast } = useToast ( )
55
56
56
57
const [ flag , setFlag ] = useState ( problem . flag )
@@ -68,20 +69,93 @@ const Problem = ({ classes, problem }) => {
68
69
const [ name , setName ] = useState ( problem . name )
69
70
const handleNameChange = useCallback ( e => setName ( e . target . value ) , [ ] )
70
71
71
- const handleUpdate = useCallback ( e => {
72
+ const [ minPoints , setMinPoints ] = useState ( problem . points . min )
73
+ const handleMinPointsChange = useCallback ( e => setMinPoints ( e . target . value ) , [ ] )
74
+
75
+ const [ maxPoints , setMaxPoints ] = useState ( problem . points . max )
76
+ const handleMaxPointsChange = useCallback ( e => setMaxPoints ( e . target . value ) , [ ] )
77
+
78
+ const handleFileUpload = useCallback ( async e => {
79
+ e . preventDefault ( )
80
+
81
+ const fileData = await Promise . all (
82
+ Array . from ( e . target . files )
83
+ . map ( async file => {
84
+ const data = await encodeFile ( file )
85
+
86
+ return {
87
+ data,
88
+ name : file . name
89
+ }
90
+ } )
91
+ )
92
+
93
+ const fileUpload = await uploadFiles ( {
94
+ files : fileData
95
+ } )
96
+
97
+ if ( fileUpload . error ) {
98
+ toast ( { body : fileUpload . error , type : 'error' } )
99
+ return
100
+ }
101
+
102
+ const data = await updateChallenge ( {
103
+ id : problem . id ,
104
+ data : {
105
+ files : fileUpload . data . concat ( problem . files )
106
+ }
107
+ } )
108
+
109
+ e . target . value = null
110
+
111
+ updateClient ( {
112
+ problem : data
113
+ } )
114
+
115
+ toast ( { body : 'Problem successfully updated' } )
116
+ } , [ problem . id , problem . files , updateClient , toast ] )
117
+
118
+ const handleRemoveFile = file => async ( ) => {
119
+ const newFiles = problem . files . filter ( f => f !== file )
120
+
121
+ const data = await updateChallenge ( {
122
+ id : problem . id ,
123
+ data : {
124
+ files : newFiles
125
+ }
126
+ } )
127
+
128
+ updateClient ( {
129
+ problem : data
130
+ } )
131
+
132
+ toast ( { body : 'Problem successfully updated' } )
133
+ }
134
+
135
+ const handleUpdate = async e => {
72
136
e . preventDefault ( )
73
137
74
- updateChallenge ( {
138
+ const data = await updateChallenge ( {
75
139
id : problem . id ,
76
140
data : {
77
141
flag,
78
142
description,
79
143
category,
80
144
author,
81
- name
145
+ name,
146
+ points : {
147
+ min : minPoints ,
148
+ max : maxPoints
149
+ }
82
150
}
83
151
} )
84
- } , [ problem , flag , description , category , author , name ] )
152
+
153
+ updateClient ( {
154
+ problem : data
155
+ } )
156
+
157
+ toast ( { body : 'Problem successfully updated' } )
158
+ }
85
159
86
160
const [ isDeleteModalOpen , setIsDeleteModalOpen ] = useState ( false )
87
161
const openDeleteModal = useCallback ( e => {
@@ -117,6 +191,8 @@ const Problem = ({ classes, problem }) => {
117
191
</ div >
118
192
< div class = { `col-6 ${ classes . header } ` } >
119
193
< input class = 'form-group-input input-small' placeholder = 'Author' value = { author } onChange = { handleAuthorChange } />
194
+ < input class = 'form-group-input input-small' type = 'number' value = { minPoints } onChange = { handleMinPointsChange } />
195
+ < input class = 'form-group-input input-small' type = 'number' value = { maxPoints } onChange = { handleMaxPointsChange } />
120
196
</ div >
121
197
</ div >
122
198
@@ -127,6 +203,32 @@ const Problem = ({ classes, problem }) => {
127
203
< input class = 'form-group-input input-small' placeholder = 'Flag' value = { flag } onChange = { handleFlagChange } />
128
204
</ div >
129
205
206
+ {
207
+ problem . files . length !== 0 &&
208
+ < div >
209
+ < p class = 'faded frame__subtitle u-no-margin' > Downloads</ p >
210
+ < div class = 'tag-container' >
211
+ {
212
+ problem . files . map ( file => {
213
+ return (
214
+ < div class = 'tag' key = { file . url } >
215
+ < a native download href = { file . url } >
216
+ { file . name }
217
+ </ a >
218
+ < div class = 'tag tag--delete' style = 'margin: 0; margin-left: 3px' onClick = { handleRemoveFile ( file ) } />
219
+ </ div >
220
+ )
221
+ } )
222
+ }
223
+
224
+ </ div >
225
+ </ div >
226
+ }
227
+
228
+ < div class = 'input-control' >
229
+ < input class = 'form-group-input input-small' placeholder = 'Flag' type = 'file' multiple onChange = { handleFileUpload } />
230
+ </ div >
231
+
130
232
< div class = { `form-section ${ classes . controls } ` } >
131
233
< button class = 'btn-small btn-info' > Update</ button >
132
234
< button class = 'btn-small btn-danger' onClick = { openDeleteModal } type = 'button' > Delete</ button >
0 commit comments