Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add tab for the RSVPing to tavern #1083

Merged
merged 2 commits into from
Jan 10, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/app/[tab]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export default function Page({
}, [])

const { tab } = params
const validTabs = ['signpost', 'shipyard', 'wonderdome', 'shop']
const validTabs = ['signpost', 'shipyard', 'wonderdome', 'shop', 'tavern']
if (!validTabs.includes(tab)) return notFound()

const { magic_auth_token } = searchParams
Expand Down
4 changes: 3 additions & 1 deletion src/app/harbor/shop/shopkeeper.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,9 @@ export const ShopkeeperComponent = ({ balance, cursed }) => {
break
case 'pause':
if (arg[0]) {
await new Promise((resolve) => setTimeout(resolve, parseFloat(arg[0])))
await new Promise((resolve) =>
setTimeout(resolve, parseFloat(arg[0])),
)
} else {
await new Promise((resolve) => setTimeout(resolve, 1000))
}
Expand Down
6 changes: 6 additions & 0 deletions src/app/harbor/tabs/tabs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'
import Shipyard from '../shipyard/shipyard'
import Battles from '../battles/battles'
import Shop from '../shop/shop'
import Tavern from '../tavern/tavern'
import { useEffect } from 'react'
import SignPost from '../signpost/signpost'
import { tour } from './tour'
Expand Down Expand Up @@ -211,6 +212,11 @@ export default function Harbor({
path: 'shop',
component: <Shop session={session} />,
},
{
name: <>Tavern 🍻</>,
path: 'tavern',
component: <Tavern />,
},
]

let usPrices = false
Expand Down
87 changes: 87 additions & 0 deletions src/app/harbor/tavern/tavern.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
'use client'

import { useEffect } from 'react'
import useLocalStorageState from '../../../../lib/useLocalStorageState'
import { setTavernRsvpStatus, getTavernRsvpStatus } from '@/app/utils/tavern'
import { Card } from '@/components/ui/card'

const RsvpStatusSwitcher = () => {
const [rsvpStatus, setRsvpStatus] = useLocalStorageState(
'cache.rsvpStatus',
'none',
)

useEffect(() => {
// set rsvp status
getTavernRsvpStatus().then((status) => setRsvpStatus(status))
}, [])

const onOptionChangeHandler = (e) => {
setRsvpStatus(e.target.value)
setTavernRsvpStatus(e.target.value)
}

return (
<div className="text-center mb-6 mt-12" id="region-select">
<label>Will you join?</label>
<select
onChange={onOptionChangeHandler}
value={rsvpStatus}
className="ml-2 text-gray-600 rounded-sm"
>
<option disabled>Select</option>
<option value="none">Nope, can't do neither</option>
<option value="organizer">I can organize a tavern near me</option>
<option value="participant">I want to attend a tavern near me</option>
</select>
</div>
)
}

export default function Tavern() {
return (
<div className="container mx-auto px-4 py-8 text-white relative">
<div className="text-white">
<h1 className="font-heading text-5xl mb-6 text-center relative w-fit mx-auto">
Mystic Tavern
</h1>
<Card className="mb-8 p-6">
<p className="mb-4">
On January 31st, thousands of ships will sail back to port, weathered and weary from their months-long voyage upon the High Seas. And yet, their journey—your journey—ends not at the dock… but in the firelit alcoves of the ✨Mystic Tavern✨.
</p>
<p className="mb-4">
Join your fellow sailors to share tales and make merry over flagons of milk, to boast of your booty and exclaim the exploits of your greatest ships! Oh, and since most pirates don’t own cars, Hack Club’s <a href="#" target="_blank">gas fund</a> will cover your transportation.
</p>
<p className="mb-4">
The tavern is not a single location, but a manifestation of pirate camaraderie known to appear wherever an intrepid sailor focuses their spirit. <strong>We need captains in every city to step up and make their local Mystic Tavern their final and most selfless ship.</strong>
</p>
<p className="mb-4">
Should you wish to organize such a gathering of shipmates, here are some things that will be asked of you:
</p>
<ul className="list-disc ml-6 mb-4">
<li>
Pick a date during the third week of February
</li>
<li>
Find a local venue (coffee shop, restaurant, library, park, whatever)
</li>
<li>
Manage signups and communications for pirates in your area
</li>
<li>
Receive and distribute special shirts at the event
</li>
<li>
Make it memorable for people!
</li>
</ul>
<p className="mb-4">
So RSVP today to meet your local hearties at a tavern near you. Better yet, volunteer to make one happen! Because like, Hack Club is made of real people. You should meet each other, you’re pretty cool 😉
</p>
</Card>

<RsvpStatusSwitcher />
</div>
</div>
)
}
45 changes: 45 additions & 0 deletions src/app/utils/tavern.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
'use server'

import Airtable from 'airtable'
import { getSession } from './auth'

Airtable.configure({
apiKey: process.env.AIRTABLE_API_KEY,
endpointUrl: process.env.AIRTABLE_ENDPOINT_URL,
})

type RsvpStatus = 'none' | 'organizer' | 'participant'
export const setTavernRsvpStatus = async (rsvpStatus: RsvpStatus) => {
// check auth
const session = await getSession()
if (!session) {
return
}
if (!session.personId) {
return
}

// update status
const base = Airtable.base(process.env.BASE_ID)
const result = await base('people').update(session.personId, {
tavern_rsvp_status: rsvpStatus,
})

return result.get('tavern_rsvp_status')
}

export const getTavernRsvpStatus = async () => {
// check auth
const session = await getSession()
if (!session) {
return
}
if (!session.personId) {
return
}

// get status
const base = Airtable.base(process.env.BASE_ID)
const record = await base('people').find(session.personId)
return record.get('tavern_rsvp_status') as RsvpStatus
}
9 changes: 8 additions & 1 deletion src/middleware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -212,5 +212,12 @@ export async function middleware(request: NextRequest) {
}

export const config = {
matcher: ['/signpost', '/shipyard', '/wonderdome', '/shop', '/api/cron/'],
matcher: [
'/signpost',
'/shipyard',
'/wonderdome',
'/shop',
'/tavern',
'/api/cron/',
],
}
Loading