@@ -186,23 +186,48 @@ const ImageConfetti = ({ imagePath, duration = 3000 }) => {
186186} ;
187187
188188export default function ConfettiWrapper ( ) {
189+ enum confettiTrigger {
190+ wit = "wit" ,
191+ socraticaW25 = "socraticaW25" ,
192+ }
193+
194+ const images = [
195+ {
196+ trigger : confettiTrigger . wit ,
197+ imagePath : "/images/wit.png" ,
198+ invertedImagePath : "/images/wit.png" ,
199+ urlParam : "wit" ,
200+ trackingEvent : "Wit_Confetti" ,
201+ } ,
202+ {
203+ trigger : confettiTrigger . socraticaW25 ,
204+ imagePath : "/images/ss.png" ,
205+ invertedImagePath : "/images/ss-inverted.png" ,
206+ urlParam : "socraticaW25" ,
207+ trackingEvent : "SocraticaSymposiumW25_Confetti" ,
208+ } ,
209+ ] ;
210+
189211 const pathname = usePathname ( ) ;
190212 const [ showConfetti , setShowConfetti ] = useState ( false ) ;
191213 const [ isDarkMode , setIsDarkMode ] = useState ( false ) ;
214+ const [ activeImage , setActiveImage ] = useState < ( typeof images ) [ 0 ] | null > (
215+ null ,
216+ ) ;
192217
193218 // Use a ref to track if we've already shown confetti in this page load
194219 const [ hasShownThisSession , setHasShownThisSession ] = useState ( false ) ;
195220
196- // Preload both images
221+ // Preload all images
197222 useEffect ( ( ) => {
198223 if ( typeof window === "undefined" ) return ;
199224
200- // Preload both versions of the image
201- const regularImg = new Image ( ) ;
202- regularImg . src = "/images/ss.png" ;
203-
204- const invertedImg = new Image ( ) ;
205- invertedImg . src = "/images/ss-inverted.png" ;
225+ images . forEach ( ( imageConfig ) => {
226+ const regularImg = new Image ( ) ;
227+ const invertedImg = new Image ( ) ;
228+ regularImg . src = imageConfig . imagePath ;
229+ invertedImg . src = imageConfig . invertedImagePath ;
230+ } ) ;
206231 } , [ ] ) ;
207232
208233 useEffect ( ( ) => {
@@ -230,53 +255,58 @@ export default function ConfettiWrapper() {
230255 // Check if browser environment
231256 if ( typeof window === "undefined" ) return ;
232257
233- // Check URL parameters for ss trigger
258+ // Check URL parameters for any configured triggers
234259 const searchParams = new URLSearchParams ( window . location . search ) ;
235- const ssParam = searchParams . get ( "socraticaW25" ) ;
236260
237- // Only run once on page load when ss=true and not shown yet
238- if ( ssParam === "true" && ! hasShownThisSession && ! showConfetti ) {
261+ // Find which image config matches the current URL params (homepage only)
262+ const matchedConfig =
263+ pathname === "/"
264+ ? images . find ( ( config ) => {
265+ const paramValue = searchParams . get ( config . urlParam ) ;
266+ return paramValue === "true" ;
267+ } )
268+ : null ;
269+
270+ // Only run once on page load when matched and not shown yet
271+ if ( matchedConfig && ! hasShownThisSession && ! showConfetti ) {
239272 // Mark that we've shown it this session
240273 setHasShownThisSession ( true ) ;
274+ setActiveImage ( matchedConfig ) ;
241275
242276 // Show confetti
243277 setShowConfetti ( true ) ;
244278
245279 // Track confetti display with Umami
246- if (
247- pathname === "/socraticaW25" ||
248- pathname . startsWith ( "/socraticaW25/" )
249- ) {
250- // Create a tracking element if it doesn't exist
251- const trackingElement = document . createElement ( "div" ) ;
252- trackingElement . setAttribute (
253- "data-umami-event" ,
254- "SocraticaSymposiumW25_Confetti" ,
255- ) ;
256- trackingElement . setAttribute ( "data-umami-event-path" , pathname ) ;
257- trackingElement . setAttribute (
258- "data-umami-event-triggered-by" ,
259- "url-param" ,
260- ) ;
261- trackingElement . style . display = "none" ;
262- document . body . appendChild ( trackingElement ) ;
263-
264- // Clean up the tracking element after a brief delay
265- setTimeout ( ( ) => {
266- if ( document . body . contains ( trackingElement ) ) {
267- document . body . removeChild ( trackingElement ) ;
268- }
269- } , 100 ) ;
270- }
280+ const trackingElement = document . createElement ( "div" ) ;
281+ trackingElement . setAttribute (
282+ "data-umami-event" ,
283+ matchedConfig . trackingEvent ,
284+ ) ;
285+ trackingElement . setAttribute ( "data-umami-event-path" , pathname ) ;
286+ trackingElement . setAttribute (
287+ "data-umami-event-triggered-by" ,
288+ "url-param" ,
289+ ) ;
290+ trackingElement . style . display = "none" ;
291+ document . body . appendChild ( trackingElement ) ;
292+
293+ // Clean up the tracking element after a brief delay
294+ setTimeout ( ( ) => {
295+ if ( document . body . contains ( trackingElement ) ) {
296+ document . body . removeChild ( trackingElement ) ;
297+ }
298+ } , 100 ) ;
271299
272300 // Hide confetti after it finishes (4 seconds total: 2.5s active + 1.5s fade out)
273301 setTimeout ( ( ) => setShowConfetti ( false ) , 4000 ) ;
274302 }
275303 } , [ pathname , showConfetti , hasShownThisSession ] ) ;
276304
277- return showConfetti ? (
305+ return showConfetti && activeImage ? (
278306 < ImageConfetti
279- imagePath = { isDarkMode ? "/images/ss-inverted.png" : "/images/ss.png" }
307+ imagePath = {
308+ isDarkMode ? activeImage . invertedImagePath : activeImage . imagePath
309+ }
280310 duration = { 2500 }
281311 />
282312 ) : null ;
0 commit comments