@@ -23,7 +23,7 @@ import {
2323import { useForm } from '@mantine/form' ;
2424import { notifications } from '@mantine/notifications' ;
2525import { IconPhotoMinus , IconUserCancel , IconUserEdit } from '@tabler/icons-react' ;
26- import { useEffect } from 'react' ;
26+ import { useEffect , useMemo } from 'react' ;
2727import { mutate } from 'swr' ;
2828
2929export default function EditUserModal ( {
@@ -37,6 +37,12 @@ export default function EditUserModal({
3737} ) {
3838 const currentUser = useUserStore ( ( state ) => state . user ) ;
3939
40+ const derivedFileType : 'BY_BYTES' | 'BY_FILES' | 'NONE' = useMemo ( ( ) => {
41+ if ( user ?. quota ?. maxBytes != null ) return 'BY_BYTES' ;
42+ if ( user ?. quota ?. maxFiles != null ) return 'BY_FILES' ;
43+ return 'NONE' ;
44+ } , [ user ] ) ;
45+
4046 const form = useForm < {
4147 username : string ;
4248 password : string ;
@@ -52,10 +58,10 @@ export default function EditUserModal({
5258 password : '' ,
5359 role : user ?. role || 'USER' ,
5460 avatar : null ,
55- fileType : user ?. quota ?. filesQuota || 'NONE' ,
56- maxFiles : user ?. quota ?. maxFiles || 0 ,
57- maxBytes : user ?. quota ?. maxBytes || '' ,
58- maxUrls : user ?. quota ?. maxUrls || 0 ,
61+ fileType : derivedFileType ,
62+ maxFiles : user ?. quota ?. maxFiles ?? 0 ,
63+ maxBytes : user ?. quota ?. maxBytes ?? '' ,
64+ maxUrls : user ?. quota ?. maxUrls ?? 0 ,
5965 } ,
6066 validate : {
6167 maxBytes ( value , values ) {
@@ -74,19 +80,33 @@ export default function EditUserModal({
7480 } ) ,
7581 } ) ;
7682
83+ useEffect ( ( ) => {
84+ form . setValues ( {
85+ username : user ?. username || '' ,
86+ password : '' ,
87+ role : user ?. role || 'USER' ,
88+ avatar : null ,
89+ fileType :
90+ user ?. quota ?. maxBytes != null ? 'BY_BYTES' : user ?. quota ?. maxFiles != null ? 'BY_FILES' : 'NONE' ,
91+ maxFiles : user ?. quota ?. maxFiles ?? 0 ,
92+ maxBytes : user ?. quota ?. maxBytes ?? '' ,
93+ maxUrls : user ?. quota ?. maxUrls ?? 0 ,
94+ } ) ;
95+ } , [ user ] ) ;
96+
7797 const onSubmit = async ( values : typeof form . values ) => {
7898 if ( ! user ) return ;
7999
80100 let avatar64 : string | null = null ;
81101 if ( values . avatar ) {
82- if ( ! values . avatar . type . startsWith ( 'image/' ) ) return form . setFieldError ( 'avatar' , 'Invalid file type' ) ;
102+ if ( ! values . avatar . type . startsWith ( 'image/' ) ) {
103+ return form . setFieldError ( 'avatar' , 'Invalid file type' ) ;
104+ }
83105
84106 try {
85- const res = await readToDataURL ( values . avatar ) ;
86- avatar64 = res ;
107+ avatar64 = await readToDataURL ( values . avatar ) ;
87108 } catch ( e ) {
88109 console . error ( e ) ;
89-
90110 return form . setFieldError ( 'avatar' , 'Failed to read avatar file' ) ;
91111 }
92112 }
@@ -95,24 +115,28 @@ export default function EditUserModal({
95115 filesType ?: 'BY_BYTES' | 'BY_FILES' | 'NONE' ;
96116 maxFiles ?: number | null ;
97117 maxBytes ?: string | null ;
98-
99118 maxUrls ?: number | null ;
100119 } = { } ;
101120
102121 if ( values . fileType === 'NONE' ) {
103122 finalQuota . filesType = 'NONE' ;
104- finalQuota . maxFiles = null ;
105- finalQuota . maxBytes = null ;
106- finalQuota . maxUrls = null ;
107- } else if ( values . fileType === 'BY_BYTES' ) {
123+ }
124+
125+ if ( values . fileType === 'BY_BYTES' ) {
108126 finalQuota . filesType = 'BY_BYTES' ;
109127 finalQuota . maxBytes = values . maxBytes ;
110- } else {
128+ finalQuota . maxFiles = null ;
129+ }
130+
131+ if ( values . fileType === 'BY_FILES' ) {
111132 finalQuota . filesType = 'BY_FILES' ;
112133 finalQuota . maxFiles = values . maxFiles ;
134+ finalQuota . maxBytes = null ;
113135 }
114136
115- if ( values . maxUrls ) finalQuota . maxUrls = values . maxUrls > 0 ? values . maxUrls : null ;
137+ if ( values . maxUrls ) {
138+ finalQuota . maxUrls = values . maxUrls > 0 ? values . maxUrls : null ;
139+ }
116140
117141 const { data, error } = await fetchApi < Response [ '/api/users/[id]' ] > ( `/api/users/${ user . id } ` , 'PATCH' , {
118142 ...( values . username !== user . username && { username : values . username } ) ,
@@ -143,22 +167,9 @@ export default function EditUserModal({
143167 }
144168 } ;
145169
146- useEffect ( ( ) => {
147- form . setValues ( {
148- username : user ?. username || '' ,
149- password : '' ,
150- role : user ?. role || 'USER' ,
151- avatar : null ,
152- fileType : user ?. quota ?. filesQuota || 'NONE' ,
153- maxFiles : user ?. quota ?. maxFiles || 0 ,
154- maxBytes : user ?. quota ?. maxBytes || '' ,
155- maxUrls : user ?. quota ?. maxUrls || 0 ,
156- } ) ;
157- } , [ user ] ) ;
158-
159170 return (
160171 < Modal centered title = { `Edit ${ user ?. username ?? '' } ` } onClose = { onClose } opened = { opened } >
161- < Text size = 'sm' c = 'dimmed' >
172+ < Text size = 'sm' mt = { - 5 } my = 'sm' c = 'dimmed' >
162173 Any fields that are blank will be omitted, and will not be updated.
163174 </ Text >
164175
@@ -171,12 +182,14 @@ export default function EditUserModal({
171182 autoComplete = 'username'
172183 { ...form . getInputProps ( 'username' ) }
173184 />
185+
174186 < PasswordInput
175187 label = 'Password'
176188 placeholder = 'Enter a password...'
177189 autoComplete = 'new-password'
178190 { ...form . getInputProps ( 'password' ) }
179191 />
192+
180193 < FileInput
181194 label = 'Avatar'
182195 placeholder = 'Select an avatar...'
@@ -209,42 +222,51 @@ export default function EditUserModal({
209222 />
210223
211224 < Divider />
212- < Title order = { 4 } > Quota</ Title >
225+ < Title order = { 5 } > Quota</ Title >
213226
214227 < Select
215228 label = 'File Quota Type'
216229 description = 'Whether to set a quota on files by total bytes or the total number of files.'
217230 data = { [
218231 { value : 'BY_BYTES' , label : 'By Bytes' } ,
219232 { value : 'BY_FILES' , label : 'By File Count' } ,
220- { value : 'NONE' , label : 'No File Quota' } ,
233+ { value : 'NONE' , label : 'No Files Quota' } ,
221234 ] }
222235 { ...form . getInputProps ( 'fileType' ) }
223236 />
224- { form . values . fileType === 'BY_FILES' ? (
225- < NumberInput
226- label = 'Max Files'
227- description = 'The maximum number of files the user can upload.'
228- placeholder = 'Enter a number...'
229- mx = 'lg'
230- min = { 0 }
231- { ...form . getInputProps ( 'maxFiles' ) }
232- />
233- ) : form . values . fileType === 'BY_BYTES' ? (
234- < TextInput
235- label = 'Max Bytes'
236- description = 'The maximum number of bytes the user can upload.'
237- placeholder = 'Enter a human readable byte-format...'
238- mx = 'lg'
239- { ...form . getInputProps ( 'maxBytes' ) }
240- />
241- ) : null }
237+
238+ { form . values . fileType !== 'NONE' && (
239+ < >
240+ { form . values . fileType === 'BY_FILES' && (
241+ < NumberInput
242+ label = 'Max Files'
243+ description = 'The maximum number of files the user can upload.'
244+ placeholder = 'Enter a number...'
245+ mx = 'lg'
246+ min = { 0 }
247+ { ...form . getInputProps ( 'maxFiles' ) }
248+ />
249+ ) }
250+
251+ { form . values . fileType === 'BY_BYTES' && (
252+ < TextInput
253+ label = 'Max Bytes'
254+ description = 'The maximum number of bytes the user can upload.'
255+ placeholder = 'Enter a human readable byte-format...'
256+ mx = 'lg'
257+ { ...form . getInputProps ( 'maxBytes' ) }
258+ />
259+ ) }
260+ </ >
261+ ) }
242262
243263 < NumberInput
244264 label = 'Max URLs'
245265 placeholder = 'Enter a number...'
266+ description = 'The maximum number of URLs the user can create. Leave as 0 for unlimited.'
246267 { ...form . getInputProps ( 'maxUrls' ) }
247268 />
269+ < Divider />
248270
249271 < Button
250272 type = 'submit'
0 commit comments