1
1
import { wrap } from '@suspensive/react'
2
2
import React from "react"
3
+ import * as R from 'remeda'
3
4
import styled from 'styled-components'
4
5
5
6
import Page from "components/common/Page"
@@ -8,6 +9,12 @@ import { useNavigate } from 'react-router'
8
9
import { useListSessionsQuery } from 'utils/hooks/useAPI'
9
10
import useTranslation from "utils/hooks/useTranslation"
10
11
12
+ const ENABLE_DETAILS = false
13
+
14
+ const TD_HEIGHT = 2.5
15
+ const TD_WIDTH = 12.5
16
+ const TD_WIDTH_MOBILE = 20
17
+
11
18
type TimeTableData = {
12
19
[ date : string ] : {
13
20
[ time : string ] : {
@@ -83,10 +90,11 @@ const getTimeTableData: (data: APIPretalxSessions) => TimeTableData = (data) =>
83
90
return timeTableData
84
91
}
85
92
86
- const SessionColumn : React . FC < { rowSpan : number , session : APIPretalxSessions [ 0 ] } > = ( { rowSpan, session } ) => {
93
+ const SessionColumn : React . FC < { rowSpan : number , colSpan ?: number , session : APIPretalxSessions [ 0 ] } > = ( { rowSpan, colSpan , session } ) => {
87
94
const navigate = useNavigate ( )
88
- return < td rowSpan = { rowSpan } >
89
- < SessionBox onClick = { ( ) => navigate ( `/session/${ session . code } ` ) } >
95
+ const clickable = ENABLE_DETAILS && R . isArray ( session . speakers ) && ! R . isEmpty ( session . speakers )
96
+ return < td rowSpan = { rowSpan } colSpan = { colSpan } >
97
+ < SessionBox onClick = { ( ) => clickable && navigate ( `/session/${ session . code } ` ) } className = { clickable ? 'clickable' : '' } >
90
98
< h6 > { session . title } </ h6 >
91
99
< SessionSpeakerContainer >
92
100
{ session . speakers . map ( ( speaker ) => < kbd key = { speaker . code } > { speaker . name } </ kbd > ) }
@@ -95,15 +103,6 @@ const SessionColumn: React.FC<{ rowSpan: number, session: APIPretalxSessions[0]
95
103
</ td >
96
104
}
97
105
98
- const BreakColumn : React . FC < { colSpan : number , hideText ?: boolean } > = ( { colSpan, hideText } ) => {
99
- const t = useTranslation ( )
100
- return < td colSpan = { colSpan } >
101
- < small style = { { color : 'rgba(255, 255, 255, 0.5)' } } > { ! hideText && t ( '휴식' ) } </ small >
102
- </ td >
103
- }
104
-
105
- const BlankColumn : React . FC = ( ) => < td > </ td >
106
-
107
106
export const SessionTimeTablePage : React . FC = ( ) => {
108
107
const t = useTranslation ( )
109
108
@@ -123,11 +122,13 @@ export const SessionTimeTablePage: React.FC = () => {
123
122
const timeTableData = getTimeTableData ( data )
124
123
const dates = Object . keys ( timeTableData ) . sort ( ( a , b ) => new Date ( a ) . getTime ( ) - new Date ( b ) . getTime ( ) )
125
124
const rooms : { [ room : string ] : number } = getRooms ( data ) . reduce ( ( acc , room ) => ( { ...acc , [ room ] : 0 } ) , { } )
126
- const sortedRoomList = Object . keys ( rooms ) . sort ( )
127
125
const roomCount = Object . keys ( rooms ) . length
126
+ const sortedRoomList = Object . keys ( rooms ) . sort ( )
128
127
129
128
const selectedDate = confDate || dates [ 0 ]
130
129
const selectedTableData = timeTableData [ selectedDate ]
130
+
131
+ let breakCount = 0
131
132
return < >
132
133
< hr />
133
134
< SessionDateTabContainer >
@@ -151,24 +152,59 @@ export const SessionTimeTablePage: React.FC = () => {
151
152
< tr > < td colSpan = { roomCount + 1 } > </ td > </ tr >
152
153
{
153
154
Object . entries ( selectedTableData ) . map ( ( [ time , roomData ] , i , a ) => {
155
+ const hasSession = Object . values ( rooms ) . some ( ( c ) => c >= 1 ) || Object . values ( roomData ) . some ( ( room ) => room !== undefined )
156
+
157
+ if ( ! hasSession ) {
158
+ if ( breakCount > 1 ) {
159
+ breakCount --
160
+ return < tr > </ tr >
161
+ } else {
162
+ // 지금부터 다음 세션이 존재하기 전까지의 휴식 시간을 계산합니다.
163
+ breakCount = 1
164
+ for ( let bi = i + 1 ; bi < a . length ; bi ++ ) {
165
+ if ( Object . values ( a [ bi ] [ 1 ] ) . some ( ( room ) => room !== undefined ) ) break
166
+ breakCount += 1
167
+ }
168
+
169
+ // I really hate this, but I can't think of a better way to do this.
170
+ const height = TD_HEIGHT * breakCount / ( breakCount <= 2 ? 1 : 3 )
171
+ return < tr >
172
+ < td style = { { height : `${ height } rem` , transform : `translateY(-${ height / 2 } rem)` } } > { time } </ td >
173
+ < td colSpan = { roomCount + 1 } rowSpan = { breakCount } style = { { height : `${ height } rem` } } >
174
+ < div style = { { display : 'flex' , flexDirection : 'column' , justifyContent : 'center' , alignItems : 'center' } } >
175
+ { i !== a . length - 1 && < small style = { { color : 'rgba(255, 255, 255, 0.5)' } } > { t ( '휴식' ) } </ small > }
176
+ </ div >
177
+ </ td >
178
+ </ tr >
179
+ }
180
+ }
181
+
182
+ // 만약 세션 타입이 아닌 발표가 존재하는 경우, 해당 줄에서는 colSpan이 roomCount인 column을 생성합니다.
183
+ const nonSessionTypeData = Object . values ( roomData ) . find ( ( room ) => room !== undefined && room . session . submission_type . en !== 'Session' )
184
+ if ( nonSessionTypeData ) {
185
+ Object . keys ( rooms ) . forEach ( ( room ) => rooms [ room ] = nonSessionTypeData . rowSpan - 1 )
186
+ return < tr >
187
+ < td > { time } </ td >
188
+ < SessionColumn rowSpan = { nonSessionTypeData . rowSpan } colSpan = { roomCount } session = { nonSessionTypeData . session } />
189
+ </ tr >
190
+ }
191
+
154
192
return < tr >
155
193
< td > { time } </ td >
156
194
{
157
- Object . values ( rooms ) . some ( ( c ) => c >= 1 ) || Object . values ( roomData ) . some ( ( room ) => room !== undefined )
158
- ? sortedRoomList . map ( ( room ) => {
159
- const roomDatum = roomData [ room ]
160
- if ( roomDatum === undefined ) {
161
- // 진행 중인 세션이 없는 경우, 해당 줄에서는 해당 room의 빈 column을 생성합니다.
162
- if ( rooms [ room ] <= 0 ) return < BlankColumn />
163
- // 진행 중인 세션이 있는 경우, 이번 줄에서는 해당 세션들만큼 column을 생성하지 않습니다.
164
- rooms [ room ] -= 1
165
- return null
166
- }
167
- // 세션이 여러 줄에 걸쳐있는 경우, n-1 줄만큼 해당 room에 column을 생성하지 않도록 합니다.
168
- if ( roomDatum . rowSpan > 1 ) rooms [ room ] = roomDatum . rowSpan - 1
169
- return < SessionColumn key = { room } rowSpan = { roomDatum . rowSpan } session = { roomDatum . session } />
170
- } )
171
- : < BreakColumn colSpan = { roomCount } hideText = { i === a . length - 1 } />
195
+ sortedRoomList . map ( ( room ) => {
196
+ const roomDatum = roomData [ room ]
197
+ if ( roomDatum === undefined ) {
198
+ // 진행 중인 세션이 없는 경우, 해당 줄에서는 해당 room의 빈 column을 생성합니다.
199
+ if ( rooms [ room ] <= 0 ) return < td > </ td >
200
+ // 진행 중인 세션이 있는 경우, 이번 줄에서는 해당 세션들만큼 column을 생성하지 않습니다.
201
+ rooms [ room ] -= 1
202
+ return null
203
+ }
204
+ // 세션이 여러 줄에 걸쳐있는 경우, n-1 줄만큼 해당 room에 column을 생성하지 않도록 합니다.
205
+ if ( roomDatum . rowSpan > 1 ) rooms [ room ] = roomDatum . rowSpan - 1
206
+ return < SessionColumn key = { room } rowSpan = { roomDatum . rowSpan } session = { roomDatum . session } />
207
+ } )
172
208
}
173
209
</ tr >
174
210
} )
@@ -189,9 +225,6 @@ export const SessionTimeTablePage: React.FC = () => {
189
225
)
190
226
}
191
227
192
- const TD_HEIGHT = 2.5
193
- const TD_WIDTH = 12.5
194
-
195
228
const SessionDateTabContainer = styled . div `
196
229
display: flex;
197
230
gap: 2rem;
@@ -262,6 +295,17 @@ const SessionTable = styled.table`
262
295
max-width: ${ TD_WIDTH } vw;
263
296
border-top: 1px solid rgba(255, 255, 255, 0.1);
264
297
}
298
+
299
+ small {
300
+ font-size: 0.8rem;
301
+ }
302
+
303
+ @media only screen and (max-width: 810px) {
304
+ td:not(:first-child) {
305
+ width: ${ TD_WIDTH_MOBILE } vw;
306
+ max-width: ${ TD_WIDTH_MOBILE } vw;
307
+ }
308
+ }
265
309
`
266
310
267
311
const SessionBox = styled . div `
@@ -272,19 +316,21 @@ const SessionBox = styled.div`
272
316
flex-direction: column;
273
317
justify-content: center;
274
318
align-items: center;
275
- border: 1px solid rgba(176, 168, 254, 0.75 );
319
+ border: 1px solid rgba(176, 168, 254, 0.3 );
276
320
border-radius: 0.5rem;
277
321
278
322
background-color: rgba(176, 168, 254, 0.1);
279
323
font-size: 1rem;
280
324
transition: all 0.25s ease;
281
325
282
- cursor: pointer;
326
+ &.clickable {
327
+ cursor: pointer;
328
+ }
283
329
284
330
h6 {
285
331
margin: 0;
286
332
color: rgba(255, 255, 255, 0.6);
287
- font-size: 0.9rem ;
333
+ font-size: 0.8rem ;
288
334
transition: all 0.25s ease;
289
335
}
290
336
@@ -300,6 +346,7 @@ const SessionBox = styled.div`
300
346
}
301
347
302
348
&:hover {
349
+ border: 1px solid rgba(176, 168, 254, 0.75);
303
350
background-color: rgba(176, 168, 254, 0.25);
304
351
transition: all 0.25s ease;
305
352
0 commit comments