11import * as React from 'react'
2- import { useState } from 'react'
2+ import { useState , useRef } from 'react'
33import { Table } from './style/Table'
44import {
55 Button ,
@@ -51,6 +51,12 @@ const Countdown = ({
5151
5252const userTimeZone = new Intl . DateTimeFormat ( ) . resolvedOptions ( ) . timeZone
5353
54+ type AddSession = {
55+ name : string
56+ hour : number
57+ minute : number
58+ }
59+
5460export const Schedule = ( {
5561 conferenceName,
5662 conferenceDate,
@@ -67,7 +73,24 @@ export const Schedule = ({
6773 const [ updatedDay , updateDay ] = useState ( conferenceDate )
6874 const [ updatedTimeZone , updateTimeZone ] = useState ( eventTimezoneName )
6975 const [ updatedSessions , updateSessions ] = useState ( sessions )
70- const [ add , updateAdd ] = useState ( { name : '' , hour : 0 , minute : 0 } )
76+ const [ add , updateAdd ] = useState < AddSession > ( {
77+ name : '' ,
78+ hour : 0 ,
79+ minute : 0 ,
80+ } )
81+ const inputRef = useRef < HTMLInputElement > ( null )
82+ const isInputValid = ( ) =>
83+ add . name . length > 0 &&
84+ add . hour >= 0 &&
85+ add . hour <= 23 &&
86+ add . minute >= 0 &&
87+ add . minute <= 59
88+
89+ const addSession = ( add : AddSession ) =>
90+ updateSessions ( ( sessions ) => ( {
91+ ...sessions ,
92+ [ parseInt ( `${ add . hour } ${ add . minute } ` , 10 ) ] : add . name ,
93+ } ) )
7194
7295 const toUserTime = ( time : number ) => {
7396 const minutes = time % 100
@@ -100,7 +123,7 @@ export const Schedule = ({
100123 < Table >
101124 < thead >
102125 < tr >
103- < th colSpan = { 4 } >
126+ < th colSpan = { editing ? 3 : 4 } >
104127 { ! editing && `${ updatedName } : ${ updatedDay } ` }
105128 { editing && (
106129 < >
@@ -141,7 +164,7 @@ export const Schedule = ({
141164 </ th >
142165 </ tr >
143166 < tr >
144- < th >
167+ < th colSpan = { editing ? 2 : 1 } >
145168 Conf Time
146169 < br />
147170 { editing && (
@@ -152,99 +175,126 @@ export const Schedule = ({
152175 ) }
153176 { ! editing && < small > { updatedTimeZone } </ small > }
154177 </ th >
155- < th >
156- Your Time
157- < br />
158- < small > { userTimeZone } </ small >
159- </ th >
160- < th > Starts in</ th >
178+ { ! editing && (
179+ < >
180+ < th >
181+ Your Time
182+ < br />
183+ < small > { userTimeZone } </ small >
184+ </ th >
185+ < th > Starts in</ th >
186+ </ >
187+ ) }
161188 < th > Session</ th >
162189 </ tr >
163190 </ thead >
164191 < tbody >
165- { Object . entries ( updatedSessions ) . map ( ( [ time , name ] ) => (
166- < tr key = { time } >
167- < td className = { 'time' } >
168- { formatEventTime ( toEventTime ( ( time as unknown ) as number ) ) }
169- </ td >
170- < td className = { 'time' } >
171- { formatUserTime ( toUserTime ( ( time as unknown ) as number ) ) }
172- </ td >
173- < Countdown
174- key = { updatedDay }
175- startTime = { toUserTime ( ( time as unknown ) as number ) }
176- />
177- < td >
178- { name }
179- { editing && (
180- < DeleteButton >
181- < DeleteIcon
182- onClick = { ( ) => {
183- updateSessions ( ( sessions ) => {
184- const s = { ...sessions }
185- delete s [ ( time as unknown ) as number ]
186- return s
187- } )
188- } }
189- />
190- </ DeleteButton >
191- ) }
192- </ td >
193- </ tr >
194- ) ) }
195192 { editing && (
196193 < tr >
194+ < td >
195+ < AddButton
196+ disabled = { ! isInputValid ( ) }
197+ onClick = { ( ) => {
198+ addSession ( add )
199+ } }
200+ >
201+ < AddIcon />
202+ </ AddButton >
203+ </ td >
197204 < td className = "time" >
198205 < NumberInput
206+ ref = { inputRef }
199207 type = "number"
200208 min = { 0 }
201209 max = { 23 }
202210 value = { add . hour }
203- onChange = { ( { target : { value } } ) =>
204- updateAdd ( {
205- ...add ,
206- hour : parseInt ( value , 10 ) ,
207- } )
208- }
211+ onChange = { ( { target : { value } } ) => {
212+ try {
213+ const hour = parseInt ( value , 10 )
214+ updateAdd ( {
215+ ...add ,
216+ hour,
217+ } )
218+ } catch { }
219+ } }
209220 />
221+ { ':' }
210222 < NumberInput
211223 type = "number"
212224 min = { 0 }
213225 max = { 59 }
214226 value = { add . minute }
215- onChange = { ( { target : { value } } ) =>
216- updateAdd ( {
217- ...add ,
218- minute : parseInt ( value , 10 ) ,
219- } )
220- }
227+ onChange = { ( { target : { value } } ) => {
228+ try {
229+ const minute = parseInt ( value , 10 )
230+ updateAdd ( {
231+ ...add ,
232+ minute,
233+ } )
234+ } catch { }
235+ } }
221236 />
222237 </ td >
223- < td colSpan = { 2 } > </ td >
224238 < td >
225239 < Input
226240 type = "text"
227241 value = { add . name }
242+ onKeyUp = { ( { key } ) => {
243+ if ( key === 'Enter' ) {
244+ if ( isInputValid ( ) ) {
245+ addSession ( add )
246+ updateAdd ( {
247+ ...add ,
248+ name : '' ,
249+ } )
250+ inputRef . current ?. focus ( )
251+ }
252+ }
253+ } }
228254 onChange = { ( { target : { value } } ) =>
229255 updateAdd ( {
230256 ...add ,
231257 name : value ,
232258 } )
233259 }
234260 />
235- < AddButton >
236- < AddIcon
237- onClick = { ( ) => {
238- updateSessions ( ( sessions ) => ( {
239- ...sessions ,
240- [ parseInt ( `${ add . hour } ${ add . minute } ` , 10 ) ] : add . name ,
241- } ) )
242- } }
243- />
244- </ AddButton >
245261 </ td >
246262 </ tr >
247263 ) }
264+ { Object . entries ( updatedSessions ) . map ( ( [ time , name ] ) => (
265+ < tr key = { time } >
266+ { editing && (
267+ < td >
268+ < DeleteButton >
269+ < DeleteIcon
270+ onClick = { ( ) => {
271+ updateSessions ( ( sessions ) => {
272+ const s = { ...sessions }
273+ delete s [ ( time as unknown ) as number ]
274+ return s
275+ } )
276+ } }
277+ />
278+ </ DeleteButton >
279+ </ td >
280+ ) }
281+ < td className = { 'time' } >
282+ { formatEventTime ( toEventTime ( ( time as unknown ) as number ) ) }
283+ </ td >
284+ { ! editing && (
285+ < >
286+ < td className = { 'time' } >
287+ { formatUserTime ( toUserTime ( ( time as unknown ) as number ) ) }
288+ </ td >
289+ < Countdown
290+ key = { updatedDay }
291+ startTime = { toUserTime ( ( time as unknown ) as number ) }
292+ />
293+ </ >
294+ ) }
295+ < td > { name } </ td >
296+ </ tr >
297+ ) ) }
248298 </ tbody >
249299 </ Table >
250300 )
0 commit comments