mirror of
https://github.com/supabase/supabase.git
synced 2026-10-18 15:49:09 +03:00
* lw11 ga ticketing * add @types/animejs * build new game word * og ticket layout * ticket og layout * lw11 ticketing flow * remove unused assets * clean up old LW code * smol cleanup * update lw11 og function * update lw11 og function * prepare * main layout * layout * update naming * fix lw11 canvas resize * lw announcement countdown banner * hp badge * update lw page * cleanup * update banners * update ticket shape * update share string * update launch time * avatar in ticket * update lw11-og handler * mask ticket glow * update game with input-otp * clean up game * update ticketing page title * update * update awards * special event * update constants * fix mobile inputs bug * update announcements * dots grid * remove 2024 * gst * fix ticket user page * less stacked layout * lw * update secret ticket * update sharing layout * max width to ticket container * update tweet text * clean up merge * npm i * update hero announcement * update footer * update types * fix types * Update apps/www/lib/constants.ts * Update apps/www/lib/constants.ts * Update apps/www/lib/constants.ts * Apply suggestions from code review * update og * og * special announcement * special announcement * fix favicon * url timestamp for cache * cache * favicon * remove file * fix title * game only when signed in * user ticket nme * day * switch to /special-announcent * update /special-announcement * update /special-announcement * skip build * redirect * fix theme in /special-announcement * fix mobile ticket form * image not draggable * cleanup * restore latest manifest * update secret ticket tweet * secret share * update text * fix secret share * typo * remove comment * update deprecated icon * restore input.stories --------- Co-authored-by: Ant Wilson <awalias@users.noreply.github.com>
104 lines
3.7 KiB
TypeScript
104 lines
3.7 KiB
TypeScript
import Link from 'next/link'
|
|
import React, { useEffect, useState } from 'react'
|
|
import { Badge } from 'ui'
|
|
import useConfData from '../hooks/use-conf-data'
|
|
import { SupabaseClient } from '@supabase/supabase-js'
|
|
|
|
export interface Meetup {
|
|
id?: any
|
|
title: string
|
|
isLive: boolean
|
|
link: string
|
|
display_info: string
|
|
start_at: string
|
|
}
|
|
|
|
const LW8Meetups = ({ meetups }: { meetups?: Meetup[] }) => {
|
|
const { supabase } = useConfData()
|
|
const [meets, setMeets] = useState<Meetup[]>(meetups ?? [])
|
|
const [realtimeChannel, setRealtimeChannel] = useState<ReturnType<
|
|
SupabaseClient['channel']
|
|
> | null>(null)
|
|
|
|
useEffect(() => {
|
|
// Listen to realtime changes
|
|
if (supabase && !realtimeChannel) {
|
|
const channel = supabase
|
|
.channel('changes')
|
|
.on(
|
|
'postgres_changes',
|
|
{
|
|
event: 'UPDATE',
|
|
schema: 'public',
|
|
table: 'lw8_meetups',
|
|
},
|
|
async () => {
|
|
const { data: newMeets } = await supabase.from('lw8_meetups').select('*')
|
|
setMeets(newMeets!)
|
|
}
|
|
)
|
|
.subscribe()
|
|
setRealtimeChannel(channel)
|
|
}
|
|
|
|
return () => {
|
|
// Cleanup realtime subscription on unmount
|
|
realtimeChannel?.unsubscribe()
|
|
}
|
|
}, [])
|
|
|
|
return (
|
|
<div className="max-w-6xl mx-auto grid grid-cols-1 xl:grid-cols-12 gap-8 xl:gap-8">
|
|
<div className="col-span-1 xl:col-span-4 flex flex-col justify-center max-w-lg">
|
|
<h2 className="text-2xl sm:text-3xl xl:text-4xl tracking-[-.5px]">Community meetups</h2>
|
|
<p className="text-[#9296AA] text-base py-3 xl:max-w-md">
|
|
We celebrated LW8 with our first-ever live community meetups across various locations.
|
|
</p>
|
|
</div>
|
|
<div className="col-span-1 xl:col-span-7 xl:col-start-6 w-full max-w-4xl flex flex-col justify-between items-stretch">
|
|
{meets &&
|
|
meets
|
|
?.sort((a, b) => (new Date(a.start_at) > new Date(b.start_at) ? 1 : -1))
|
|
.map(({ display_info, link, isLive, title }: Meetup) => (
|
|
<Link
|
|
key={title}
|
|
href={link ?? '#'}
|
|
target="_blank"
|
|
className={[
|
|
'w-full group py-0 flex items-center gap-2 md:gap-4 text-lg sm:text-2xl xl:text-4xl border-b border-[#111718]',
|
|
'hover:text-foreground',
|
|
isLive ? 'text-foreground-light' : 'text-[#56646B]',
|
|
!link && 'pointer-events-none',
|
|
].join(' ')}
|
|
>
|
|
<div className="flex items-center gap-2 md:gap-4 py-2 md:py-0">
|
|
<span>{title}</span>
|
|
{isLive && <Badge>Live now</Badge>}
|
|
<span className="hidden md:inline opacity-0 -translate-x-2 transition-all md:group-hover:opacity-100 group-hover:translate-x-0">
|
|
<svg
|
|
width="47"
|
|
height="47"
|
|
viewBox="0 0 47 47"
|
|
fill="none"
|
|
xmlns="http://www.w3.org/2000/svg"
|
|
>
|
|
<path
|
|
d="M33.0387 16.2422L40.6691 23.8727M40.6691 23.8727L33.0387 31.5031M40.6691 23.8727L6.33203 23.8727"
|
|
stroke="currentColor"
|
|
strokeWidth="2"
|
|
strokeLinecap="round"
|
|
strokeLinejoin="round"
|
|
/>
|
|
</svg>
|
|
</span>
|
|
</div>
|
|
{display_info && <span className="text-sm text-right flex-1">{display_info}</span>}
|
|
</Link>
|
|
))}
|
|
</div>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
export default LW8Meetups
|