@@ -4,7 +4,6 @@ import * as React from "react";
44import { Link } from "react-router-dom" ;
55import * as R from "remeda" ;
66
7- import PyCon2025Logo from "../../assets/pyconkr2025_logo.png" ;
87import * as Hooks from "../../hooks" ;
98import * as BackendAPISchemas from "../../schemas/backendAPI" ;
109import { ErrorFallback } from "../error_handler" ;
@@ -13,65 +12,72 @@ import { StyledDivider } from "./styled_divider";
1312
1413const EXCLUDE_CATEGORIES = [ "후원사" , "Sponsor" ] ;
1514
16- const SessionItem : React . FC < { session : BackendAPISchemas . SessionSchema ; enableLink ?: boolean } > = Suspense . with (
17- { fallback : < CircularProgress /> } ,
18- ( { session, enableLink } ) => {
19- const sessionTitle = session . title . replace ( "\\n" , "\n" ) ;
20-
21- let speakerImgSrc = session . image || "" ;
22- if ( ! speakerImgSrc && R . isArray ( session . speakers ) && ! R . isEmpty ( session . speakers ) ) {
23- for ( const speaker of session . speakers ) {
24- if ( speaker . image ) {
25- speakerImgSrc = speaker . image ;
26- break ;
27- }
15+ const SessionItem : React . FC < {
16+ session : BackendAPISchemas . SessionSchema ;
17+ enableLink ?: boolean ;
18+ fallbackImage ?: React . ReactNode ;
19+ getSessionUrl ?: ( session : BackendAPISchemas . SessionSchema ) => string ;
20+ } > = Suspense . with ( { fallback : < CircularProgress /> } , ( { session, enableLink, fallbackImage, getSessionUrl } ) => {
21+ const sessionTitle = session . title . replace ( "\\n" , "\n" ) ;
22+
23+ let speakerImgSrc = session . image || "" ;
24+ if ( ! speakerImgSrc && R . isArray ( session . speakers ) && ! R . isEmpty ( session . speakers ) ) {
25+ for ( const speaker of session . speakers ) {
26+ if ( speaker . image ) {
27+ speakerImgSrc = speaker . image ;
28+ break ;
2829 }
2930 }
31+ }
3032
31- const urlSafeTitle = session . title
32- . replace ( / / g, "-" )
33- . replace ( / ( [ . ] ) / g, "_" )
34- . replace ( / (? ! [ 0 - 9 A - Z a - z ㄱ - ㅣ 가 - 힣 - _ ] ) ./ g, "" ) ;
35- const sessionDetailedUrl = `/presentations/${ session . id } #${ urlSafeTitle } ` ;
36- const result = (
37- < SessionItemContainer direction = "row" >
38- < SessionImageContainer
39- children = { < SessionImage src = { speakerImgSrc } alt = "Session Image" loading = "lazy" errorFallback = { < SessionImageErrorFallback /> } /> }
40- />
41- < Stack direction = "column" sx = { { flexGrow : 1 , py : 0.5 , gap : 0.75 } } >
42- < SessionTitle children = { sessionTitle } />
43- { session . summary && < Typography variant = "subtitle1" sx = { { whiteSpace : "pre-wrap" } } children = { session . summary } /> }
44- < Stack direction = "row" spacing = { 0.5 } >
45- { session . speakers . map ( ( speaker ) => (
46- < Chip key = { speaker . id } size = "small" label = { speaker . nickname } />
47- ) ) }
48- </ Stack >
49- < Stack direction = "row" spacing = { 0.5 } >
50- { session . categories . map ( ( tag ) => (
51- < Chip key = { tag . id } variant = "outlined" color = "primary" size = "small" label = { tag . name } />
52- ) ) }
53- </ Stack >
33+ const sessionDetailedUrl = getSessionUrl ? getSessionUrl ( session ) : undefined ;
34+ const result = (
35+ < SessionItemContainer direction = "row" >
36+ < SessionImageContainer
37+ children = {
38+ < SessionImage
39+ src = { speakerImgSrc }
40+ alt = "Session Image"
41+ loading = "lazy"
42+ errorFallback = { < SessionImageErrorFallback > { fallbackImage } </ SessionImageErrorFallback > }
43+ />
44+ }
45+ />
46+ < Stack direction = "column" sx = { { flexGrow : 1 , py : 0.5 , gap : 0.75 } } >
47+ < SessionTitle children = { sessionTitle } />
48+ { session . summary && < Typography variant = "subtitle1" sx = { { whiteSpace : "pre-wrap" } } children = { session . summary } /> }
49+ < Stack direction = "row" spacing = { 0.5 } >
50+ { session . speakers . map ( ( speaker ) => (
51+ < Chip key = { speaker . id } size = "small" label = { speaker . nickname } />
52+ ) ) }
5453 </ Stack >
55- </ SessionItemContainer >
56- ) ;
57- return (
58- < >
59- { enableLink ? < Link to = { sessionDetailedUrl } style = { { textDecoration : "none" } } children = { result } /> : result }
60- < StyledDivider />
61- </ >
62- ) ;
63- }
64- ) ;
54+ < Stack direction = "row" spacing = { 0.5 } >
55+ { session . categories . map ( ( tag ) => (
56+ < Chip key = { tag . id } variant = "outlined" color = "primary" size = "small" label = { tag . name } />
57+ ) ) }
58+ </ Stack >
59+ </ Stack >
60+ </ SessionItemContainer >
61+ ) ;
62+ return (
63+ < >
64+ { enableLink && sessionDetailedUrl ? < Link to = { sessionDetailedUrl } style = { { textDecoration : "none" } } children = { result } /> : result }
65+ < StyledDivider />
66+ </ >
67+ ) ;
68+ } ) ;
6569
6670type SessionListPropType = {
6771 event ?: string ;
6872 types ?: string | string [ ] ;
6973 enableLink ?: boolean ;
74+ fallbackImage ?: React . ReactNode ;
75+ getSessionUrl ?: ( session : BackendAPISchemas . SessionSchema ) => string ;
7076} ;
7177
7278export const SessionList : React . FC < SessionListPropType > = ErrorBoundary . with (
7379 { fallback : ErrorFallback } ,
74- Suspense . with ( { fallback : < CircularProgress /> } , ( { event, types, enableLink } ) => {
80+ Suspense . with ( { fallback : < CircularProgress /> } , ( { event, types, enableLink, fallbackImage , getSessionUrl } ) => {
7581 const { language } = Hooks . Common . useCommonContext ( ) ;
7682 const backendAPIClient = Hooks . BackendAPI . useBackendClient ( ) ;
7783 const params = { ...( event && { event } ) , ...( types && { types : R . isString ( types ) ? types : types . join ( "," ) } ) } ;
@@ -122,7 +128,7 @@ export const SessionList: React.FC<SessionListPropType> = ErrorBoundary.with(
122128 ) }
123129 </ Box >
124130 { filteredSessions . map ( ( s ) => (
125- < SessionItem key = { s . id } session = { s } enableLink = { enableLink } />
131+ < SessionItem key = { s . id } session = { s } enableLink = { enableLink } fallbackImage = { fallbackImage } getSessionUrl = { getSessionUrl } />
126132 ) ) }
127133 </ Box >
128134 ) ;
@@ -194,10 +200,8 @@ const SessionImageErrorFallbackBox = styled(Box)(({ theme }) => ({
194200 justifyContent : "center" ,
195201} ) ) ;
196202
197- const SessionImageErrorFallback : React . FC = ( ) => (
198- < SessionImageErrorFallbackBox >
199- < img src = { PyCon2025Logo } alt = "PyCon 2025 Logo" style = { { width : "100%" , height : "100%" , objectFit : "cover" , borderRadius : "50%" } } />
200- </ SessionImageErrorFallbackBox >
203+ const SessionImageErrorFallback : React . FC < { children ?: React . ReactNode } > = ( { children } ) => (
204+ < SessionImageErrorFallbackBox > { children } </ SessionImageErrorFallbackBox >
201205) ;
202206
203207const SessionTitle = styled ( Typography ) ( {
0 commit comments