update: registration - remove food payment, add Herrnhof Villa, extend to 7 nights

- Remove food as a payment option; add note about follow-up email for food
- Restructure accommodation into two venues: Commons Hub and Herrnhof Villa
- Herrnhof Villa options: single, double (3 configs), and triple rooms
- Update event dates from Aug 16-22 to Aug 16-23 (7 nights) across all pages
- Update pricing: Commons Hub €274.40/€351.40, Herrnhof €40-€95 per person
- Update transparency page with new accommodation breakdown and food TBA
- Update API route and confirmation email to match

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Jeff Emmett 2026-03-06 12:37:43 -08:00
parent e007df4959
commit b209f2f14b
10 changed files with 212 additions and 162 deletions

View File

@ -203,7 +203,7 @@ export default function AboutPage() {
<div className="container mx-auto max-w-3xl text-center"> <div className="container mx-auto max-w-3xl text-center">
<h2 className="text-3xl md:text-4xl font-bold mb-6 text-balance">Be Part of the Sixth Edition</h2> <h2 className="text-3xl md:text-4xl font-bold mb-6 text-balance">Be Part of the Sixth Edition</h2>
<p className="text-lg text-muted-foreground mb-8 text-pretty"> <p className="text-lg text-muted-foreground mb-8 text-pretty">
Join us August 16-22, 2026 in the Austrian Alps for an unforgettable week of connection, collaboration, and Join us August 16-23, 2026 in the Austrian Alps for an unforgettable week of connection, collaboration, and
commons-building. commons-building.
</p> </p>
@ -229,7 +229,7 @@ export default function AboutPage() {
<p className="text-sm text-muted-foreground"> <p className="text-sm text-muted-foreground">
Crypto Commons Gathering Crypto Commons Gathering
<br /> <br />
August 16-22, 2026 August 16-23, 2026
</p> </p>
</div> </div>

View File

@ -13,9 +13,17 @@ function getMollie() {
// Dynamic pricing configuration (in EUR) // Dynamic pricing configuration (in EUR)
const TICKET_PRICE = 80 // €80 early bird const TICKET_PRICE = 80 // €80 early bird
const DORM_PRICE = 235.2 // €235.20 (€39.20/night x 6)
const DOUBLE_PRICE = 301.2 // €301.20 (€50.20/night x 6) // Accommodation prices per person for 7 nights
const FOOD_PRICE = 135 // €135 (6 days) const ACCOMMODATION_PRICES: Record<string, { label: string; price: number }> = {
"ch-multi": { label: "Bed in shared room (Commons Hub)", price: 274.40 },
"ch-double": { label: "Bed in double room (Commons Hub)", price: 351.40 },
"hh-single": { label: "Single — double bed (Herrnhof)", price: 95 },
"hh-double-separate": { label: "Double — double + single bed (Herrnhof)", price: 60 },
"hh-double-shared": { label: "Double — shared double bed (Herrnhof)", price: 50 },
"hh-double-couch": { label: "Double — couch + single in living room (Herrnhof)", price: 40 },
"hh-triple": { label: "Triple — shared double + single bed (Herrnhof)", price: 50 },
}
// Public base URL // Public base URL
const BASE_URL = process.env.NEXT_PUBLIC_BASE_URL || "https://cryptocommonsgather.ing" const BASE_URL = process.env.NEXT_PUBLIC_BASE_URL || "https://cryptocommonsgather.ing"
@ -25,8 +33,7 @@ export async function POST(request: NextRequest) {
const formData = await request.formData() const formData = await request.formData()
const registrationDataStr = formData.get("registrationData") as string const registrationDataStr = formData.get("registrationData") as string
const includeAccommodation = formData.get("includeAccommodation") === "true" const includeAccommodation = formData.get("includeAccommodation") === "true"
const accommodationType = (formData.get("accommodationType") as string) || "dorm" const accommodationType = (formData.get("accommodationType") as string) || "ch-multi"
const includeFood = formData.get("includeFood") === "true"
const registrationData = registrationDataStr ? JSON.parse(registrationDataStr) : null const registrationData = registrationDataStr ? JSON.parse(registrationDataStr) : null
@ -35,15 +42,11 @@ export async function POST(request: NextRequest) {
const descriptionParts = ["CCG 2026 Ticket (€80)"] const descriptionParts = ["CCG 2026 Ticket (€80)"]
if (includeAccommodation) { if (includeAccommodation) {
const isDorm = accommodationType === "dorm" const accom = ACCOMMODATION_PRICES[accommodationType]
const accomPrice = isDorm ? DORM_PRICE : DOUBLE_PRICE if (accom) {
total += accomPrice total += accom.price
descriptionParts.push(`${isDorm ? "Dorm" : "Double Room"} (€${accomPrice.toFixed(2)})`) descriptionParts.push(`${accom.label} (€${accom.price.toFixed(2)})`)
} }
if (includeFood) {
total += FOOD_PRICE
descriptionParts.push(`Food Package (€${FOOD_PRICE})`)
} }
// Build metadata for webhook // Build metadata for webhook
@ -59,7 +62,6 @@ export async function POST(request: NextRequest) {
(registrationData.dietaryOther ? `, ${registrationData.dietaryOther}` : "") (registrationData.dietaryOther ? `, ${registrationData.dietaryOther}` : "")
metadata.crewConsent = registrationData.crewConsent || "" metadata.crewConsent = registrationData.crewConsent || ""
metadata.accommodation = includeAccommodation ? accommodationType : "none" metadata.accommodation = includeAccommodation ? accommodationType : "none"
metadata.food = includeFood ? "yes" : "no"
} }
const payment = await getMollie().payments.create({ const payment = await getMollie().payments.create({

View File

@ -140,7 +140,7 @@ export default function GalleryPage() {
<p className="text-sm text-muted-foreground"> <p className="text-sm text-muted-foreground">
Crypto Commons Gathering Crypto Commons Gathering
<br /> <br />
August 16-22, 2026 August 16-23, 2026
</p> </p>
</div> </div>

View File

@ -11,7 +11,7 @@ export const metadata: Metadata = {
metadataBase: new URL("https://cryptocommonsgather.ing"), metadataBase: new URL("https://cryptocommonsgather.ing"),
title: "Crypto Commons Gathering 2026 | CCG", title: "Crypto Commons Gathering 2026 | CCG",
description: description:
"The sixth annual hack-ademic confluence of commons praxis and the latest cryptographic technologies in the Austrian Alps. August 16-22, 2026.", "The sixth annual hack-ademic confluence of commons praxis and the latest cryptographic technologies in the Austrian Alps. August 16-23, 2026.",
generator: "v0.app", generator: "v0.app",
icons: { icons: {
icon: [ icon: [
@ -23,7 +23,7 @@ export const metadata: Metadata = {
openGraph: { openGraph: {
title: "Crypto Commons Gathering 2026 | CCG", title: "Crypto Commons Gathering 2026 | CCG",
description: description:
"The sixth annual hack-ademic confluence of commons praxis and the latest cryptographic technologies in the Austrian Alps. August 16-22, 2026.", "The sixth annual hack-ademic confluence of commons praxis and the latest cryptographic technologies in the Austrian Alps. August 16-23, 2026.",
url: "https://cryptocommonsgather.ing", url: "https://cryptocommonsgather.ing",
siteName: "Crypto Commons Gathering", siteName: "Crypto Commons Gathering",
images: [ images: [
@ -41,7 +41,7 @@ export const metadata: Metadata = {
card: "summary_large_image", card: "summary_large_image",
title: "Crypto Commons Gathering 2026 | CCG", title: "Crypto Commons Gathering 2026 | CCG",
description: description:
"The sixth annual hack-ademic confluence of commons praxis and the latest cryptographic technologies in the Austrian Alps. August 16-22, 2026.", "The sixth annual hack-ademic confluence of commons praxis and the latest cryptographic technologies in the Austrian Alps. August 16-23, 2026.",
images: ["/og-image.jpg"], images: ["/og-image.jpg"],
}, },
} }

View File

@ -136,7 +136,7 @@ END:VCALENDAR`
</h1> </h1>
<div className="inline-block mb-6 px-6 py-2 bg-primary/20 border-2 border-primary/40 rounded-full backdrop-blur-sm"> <div className="inline-block mb-6 px-6 py-2 bg-primary/20 border-2 border-primary/40 rounded-full backdrop-blur-sm">
<p className="text-lg md:text-xl font-mono font-semibold text-primary">August 16-22, 2026</p> <p className="text-lg md:text-xl font-mono font-semibold text-primary">August 16-23, 2026</p>
</div> </div>
<p className="text-xl md:text-2xl text-foreground/90 mb-8 max-w-2xl mx-auto text-pretty leading-relaxed font-medium"> <p className="text-xl md:text-2xl text-foreground/90 mb-8 max-w-2xl mx-auto text-pretty leading-relaxed font-medium">
@ -594,7 +594,7 @@ END:VCALENDAR`
<div className="text-center md:text-left"> <div className="text-center md:text-left">
<h3 className="font-bold text-lg mb-2">CCG + Valley: The Full Experience</h3> <h3 className="font-bold text-lg mb-2">CCG + Valley: The Full Experience</h3>
<p className="text-sm text-muted-foreground max-w-lg"> <p className="text-sm text-muted-foreground max-w-lg">
Come for CCG's unconference week (Aug 16-22), then flow straight into Valley of the Commons Come for CCG's unconference week (Aug 16-23), then flow straight into Valley of the Commons
(Aug 24 Sep 20). Same mountains, same community, deeper roots. Perfect for digital workers, (Aug 24 Sep 20). Same mountains, same community, deeper roots. Perfect for digital workers,
post-corporate professionals, and anyone seeking grounded, cooperative ways of living. post-corporate professionals, and anyone seeking grounded, cooperative ways of living.
</p> </p>
@ -619,7 +619,7 @@ END:VCALENDAR`
<p className="text-sm text-muted-foreground"> <p className="text-sm text-muted-foreground">
Crypto Commons Gathering Crypto Commons Gathering
<br /> <br />
August 16-22, 2026 August 16-23, 2026
</p> </p>
</div> </div>

View File

@ -16,8 +16,8 @@ export default function RegisterPage() {
const [step, setStep] = useState<"form" | "payment">("form") const [step, setStep] = useState<"form" | "payment">("form")
const [isSubmitting, setIsSubmitting] = useState(false) const [isSubmitting, setIsSubmitting] = useState(false)
const [includeAccommodation, setIncludeAccommodation] = useState(true) const [includeAccommodation, setIncludeAccommodation] = useState(true)
const [accommodationType, setAccommodationType] = useState<"dorm" | "double">("dorm") const [accommodationVenue, setAccommodationVenue] = useState<"commons-hub" | "herrnhof">("commons-hub")
const [includeFood, setIncludeFood] = useState(true) const [accommodationType, setAccommodationType] = useState("ch-multi")
const [formData, setFormData] = useState({ const [formData, setFormData] = useState({
name: "", name: "",
contact: "", contact: "",
@ -29,14 +29,21 @@ export default function RegisterPage() {
crewConsent: "", crewConsent: "",
}) })
const baseTicketPrice = 80 // Early bird price €80 const baseTicketPrice = 80 // Early bird price €80
const dormPrice = 235.20 // €39.20/night x 6 nights
const doublePrice = 301.20 // €50.20/night x 6 nights const accommodationPrices: Record<string, { label: string; price: number }> = {
const foodPrice = 135 // 6 days of meals "ch-multi": { label: "Bed in shared room (Commons Hub)", price: 274.40 },
const accommodationPrice = accommodationType === "dorm" ? dormPrice : doublePrice "ch-double": { label: "Bed in double room (Commons Hub)", price: 351.40 },
"hh-single": { label: "Single — double bed (Herrnhof)", price: 95 },
"hh-double-separate": { label: "Double — double + single bed (Herrnhof)", price: 60 },
"hh-double-shared": { label: "Double — shared double bed (Herrnhof)", price: 50 },
"hh-double-couch": { label: "Double — couch + single in living room (Herrnhof)", price: 40 },
"hh-triple": { label: "Triple — shared double + single bed (Herrnhof)", price: 50 },
}
const accommodationPrice = accommodationPrices[accommodationType]?.price ?? 0
const totalPrice = const totalPrice =
baseTicketPrice + baseTicketPrice +
(includeAccommodation ? accommodationPrice : 0) + (includeAccommodation ? accommodationPrice : 0)
(includeFood ? foodPrice : 0)
const handleSubmit = async (e: React.FormEvent) => { const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault() e.preventDefault()
@ -150,82 +157,133 @@ export default function RegisterPage() {
<div className="flex-1"> <div className="flex-1">
<div className="flex justify-between items-start"> <div className="flex justify-between items-start">
<Label htmlFor="include-accommodation" className="font-medium cursor-pointer"> <Label htmlFor="include-accommodation" className="font-medium cursor-pointer">
Accommodation at the Commons Hub (6 nights) Accommodation (7 nights, Aug 1623)
</Label> </Label>
{includeAccommodation && ( {includeAccommodation && (
<span className="text-lg font-semibold whitespace-nowrap ml-4">{accommodationPrice.toFixed(2)}</span> <span className="text-lg font-semibold whitespace-nowrap ml-4">{accommodationPrice.toFixed(2)}</span>
)} )}
</div> </div>
{includeAccommodation ? ( {includeAccommodation ? (
<div className="mt-2"> <div className="mt-3 space-y-4">
{/* Venue selection */}
<RadioGroup <RadioGroup
value={accommodationType} value={accommodationVenue}
onValueChange={(value) => setAccommodationType(value as "dorm" | "double")} onValueChange={(value: string) => {
const venue = value as "commons-hub" | "herrnhof"
setAccommodationVenue(venue)
setAccommodationType(venue === "commons-hub" ? "ch-multi" : "hh-single")
}}
className="space-y-2" className="space-y-2"
> >
<div className="flex items-center space-x-2"> <div className="flex items-center space-x-2">
<RadioGroupItem value="dorm" id="dorm" /> <RadioGroupItem value="commons-hub" id="venue-ch" />
<Label htmlFor="dorm" className="font-normal cursor-pointer text-sm"> <Label htmlFor="venue-ch" className="font-medium cursor-pointer text-sm">
Dorm bed (39.20/night 235.20 total) Commons Hub
</Label> </Label>
</div> </div>
<div className="flex items-center space-x-2"> <div className="flex items-center space-x-2">
<RadioGroupItem value="double" id="double" /> <RadioGroupItem value="herrnhof" id="venue-hh" />
<Label htmlFor="double" className="font-normal cursor-pointer text-sm"> <Label htmlFor="venue-hh" className="font-medium cursor-pointer text-sm">
Double room (50.20/night per person 301.20 total) Herrnhof Villa
</Label> </Label>
</div> </div>
</RadioGroup> </RadioGroup>
<p className="text-xs text-muted-foreground mt-2">
30 beds on-site. Nearby options (Herrnhof.at, Gasthof Kobald) also available see{" "} {/* Sub-options per venue */}
<Link href="/transparency" className="text-primary hover:underline">Transparency</Link> page. {accommodationVenue === "commons-hub" ? (
</p> <div className="pl-6 border-l-2 border-primary/20">
<p className="text-xs text-muted-foreground mb-2">
30 beds on-site at the main venue. Basic, communal accommodation.
</p>
<RadioGroup
value={accommodationType}
onValueChange={setAccommodationType}
className="space-y-2"
>
<div className="flex items-center space-x-2">
<RadioGroupItem value="ch-multi" id="ch-multi" />
<Label htmlFor="ch-multi" className="font-normal cursor-pointer text-sm">
Bed in shared room 274.40 (39.20/night)
</Label>
</div>
<div className="flex items-center space-x-2">
<RadioGroupItem value="ch-double" id="ch-double" />
<Label htmlFor="ch-double" className="font-normal cursor-pointer text-sm">
Bed in double room 351.40 (50.20/night)
</Label>
</div>
</RadioGroup>
</div>
) : (
<div className="pl-6 border-l-2 border-primary/20">
<p className="text-xs text-muted-foreground mb-2">
Historic 19th-century mansion with newly renovated apartments, sauna,
and river swimming platform. Prices per person for 7 nights (incl. city tax &amp; VAT).
</p>
<RadioGroup
value={accommodationType}
onValueChange={setAccommodationType}
className="space-y-2"
>
<div className="flex items-center space-x-2">
<RadioGroupItem value="hh-single" id="hh-single" />
<Label htmlFor="hh-single" className="font-normal cursor-pointer text-sm">
Single double bed 95
</Label>
</div>
<div className="flex items-center space-x-2">
<RadioGroupItem value="hh-double-separate" id="hh-double-separate" />
<Label htmlFor="hh-double-separate" className="font-normal cursor-pointer text-sm">
Double double + single bed 60/person
</Label>
</div>
<div className="flex items-center space-x-2">
<RadioGroupItem value="hh-double-shared" id="hh-double-shared" />
<Label htmlFor="hh-double-shared" className="font-normal cursor-pointer text-sm">
Double shared double bed 50/person
</Label>
</div>
<div className="flex items-center space-x-2">
<RadioGroupItem value="hh-double-couch" id="hh-double-couch" />
<Label htmlFor="hh-double-couch" className="font-normal cursor-pointer text-sm">
Double couch + single in living room 40/person
</Label>
</div>
<div className="flex items-center space-x-2">
<RadioGroupItem value="hh-triple" id="hh-triple" />
<Label htmlFor="hh-triple" className="font-normal cursor-pointer text-sm">
Triple shared double + single bed 50/person
</Label>
</div>
</RadioGroup>
<p className="text-xs text-muted-foreground mt-2">
For whole-apartment quotes, contact{" "}
<a href="mailto:office@commons-hub.at" className="text-primary hover:underline">office@commons-hub.at</a>.
</p>
</div>
)}
</div> </div>
) : ( ) : (
<p className="text-sm text-muted-foreground mt-1"> <p className="text-sm text-muted-foreground mt-1">
I'll arrange my own accommodation I&apos;ll arrange my own accommodation
</p> </p>
)} )}
</div> </div>
</div> </div>
</div> </div>
{/* Food */} {/* Food note */}
<div className="py-4 border-b border-border"> <div className="py-4 border-b border-border">
<div className="flex items-start gap-3"> <p className="text-sm text-muted-foreground">
<Checkbox <span className="font-medium text-foreground">Food:</span>{" "}
id="include-food" We&apos;ll follow up via email with food options and pricing closer to the event.
checked={includeFood} Your dietary preferences from step 1 have been noted.
onCheckedChange={(checked) => setIncludeFood(checked as boolean)} </p>
className="mt-1"
/>
<div className="flex-1">
<div className="flex justify-between items-start">
<Label htmlFor="include-food" className="font-medium cursor-pointer">
Food for the week (6 days)
</Label>
{includeFood && (
<span className="text-lg font-semibold whitespace-nowrap ml-4">{foodPrice.toFixed(2)}</span>
)}
</div>
{includeFood ? (
<p className="text-sm text-muted-foreground mt-1">
Breakfast buffet, catered lunches &amp; dinners (vegetarian/vegan + meat options),
coffee &amp; tea throughout the day.
</p>
) : (
<p className="text-sm text-muted-foreground mt-1">
I'll arrange my own meals
</p>
)}
</div>
</div>
</div> </div>
{(includeAccommodation || includeFood) && ( {includeAccommodation && (
<p className="text-xs text-muted-foreground bg-muted/50 rounded-lg p-3"> <p className="text-xs text-muted-foreground bg-muted/50 rounded-lg p-3">
We'll follow up with you closer to the event to confirm accommodation and food details, We&apos;ll follow up closer to the event to confirm room assignments and accommodation details.
including room assignments and any dietary needs.
</p> </p>
)} )}
@ -234,7 +292,7 @@ export default function RegisterPage() {
<div> <div>
<div className="font-bold text-lg">Total Amount</div> <div className="font-bold text-lg">Total Amount</div>
<div className="text-sm text-muted-foreground"> <div className="text-sm text-muted-foreground">
Ticket{includeAccommodation ? " + accommodation" : ""}{includeFood ? " + food" : ""} Ticket{includeAccommodation ? " + accommodation" : ""}
</div> </div>
</div> </div>
<span className="text-2xl font-bold text-primary">{totalPrice.toFixed(2)}</span> <span className="text-2xl font-bold text-primary">{totalPrice.toFixed(2)}</span>
@ -255,7 +313,6 @@ export default function RegisterPage() {
<input type="hidden" name="registrationData" value={JSON.stringify(formData)} /> <input type="hidden" name="registrationData" value={JSON.stringify(formData)} />
<input type="hidden" name="includeAccommodation" value={includeAccommodation ? "true" : "false"} /> <input type="hidden" name="includeAccommodation" value={includeAccommodation ? "true" : "false"} />
<input type="hidden" name="accommodationType" value={accommodationType} /> <input type="hidden" name="accommodationType" value={accommodationType} />
<input type="hidden" name="includeFood" value={includeFood ? "true" : "false"} />
<div className="space-y-4"> <div className="space-y-4">
<p className="text-sm text-muted-foreground"> <p className="text-sm text-muted-foreground">
@ -294,7 +351,7 @@ export default function RegisterPage() {
<p className="text-sm text-muted-foreground"> <p className="text-sm text-muted-foreground">
Crypto Commons Gathering Crypto Commons Gathering
<br /> <br />
August 16-22, 2026 August 16-23, 2026
</p> </p>
</div> </div>
@ -416,7 +473,7 @@ export default function RegisterPage() {
<main className="container mx-auto px-4 py-12 max-w-3xl"> <main className="container mx-auto px-4 py-12 max-w-3xl">
<div className="text-center mb-12"> <div className="text-center mb-12">
<h1 className="text-4xl md:text-5xl font-bold mb-4">Register for CCG 2026</h1> <h1 className="text-4xl md:text-5xl font-bold mb-4">Register for CCG 2026</h1>
<p className="text-xl text-muted-foreground">August 16-22, 2026 at the Commons Hub in Austria</p> <p className="text-xl text-muted-foreground">August 16-23, 2026 at the Commons Hub in Austria</p>
</div> </div>
<Card> <Card>
@ -606,7 +663,7 @@ export default function RegisterPage() {
<p className="text-sm text-muted-foreground"> <p className="text-sm text-muted-foreground">
Crypto Commons Gathering Crypto Commons Gathering
<br /> <br />
August 16-22, 2026 August 16-23, 2026
</p> </p>
</div> </div>

View File

@ -223,7 +223,7 @@ export default function SponsorshipsPage() {
<p className="text-sm text-muted-foreground"> <p className="text-sm text-muted-foreground">
Crypto Commons Gathering Crypto Commons Gathering
<br /> <br />
August 16-22, 2026 August 16-23, 2026
</p> </p>
</div> </div>

View File

@ -48,7 +48,7 @@ export default function SuccessPage() {
<p className="text-sm text-muted-foreground"> <p className="text-sm text-muted-foreground">
Crypto Commons Gathering Crypto Commons Gathering
<br /> <br />
August 16-22, 2026 August 16-23, 2026
</p> </p>
</div> </div>

View File

@ -95,33 +95,72 @@ export default function FinancialTransparencyPage() {
</CardHeader> </CardHeader>
<CardContent className="space-y-4"> <CardContent className="space-y-4">
<p className="text-sm text-muted-foreground mb-4"> <p className="text-sm text-muted-foreground mb-4">
The Commons Hub offers 30 beds on-site. Accommodation is not included in the ticket price: Accommodation is not included in the ticket price. All prices below are for the full 7 nights (Aug 1623).
</p> </p>
<div className="space-y-3">
<h4 className="font-semibold mb-3">Commons Hub (on-site)</h4>
<p className="text-xs text-muted-foreground mb-3">30 beds at the main venue. Basic, communal accommodation.</p>
<div className="space-y-3 mb-6">
<div className="bg-muted/50 p-6 rounded-lg"> <div className="bg-muted/50 p-6 rounded-lg">
<div className="flex items-baseline gap-3 mb-2"> <div className="flex items-baseline gap-3 mb-2">
<span className="text-3xl font-bold">39.20</span> <span className="text-3xl font-bold">274.40</span>
<span className="text-muted-foreground">per night</span> <span className="text-muted-foreground">per person / 7 nights</span>
</div> </div>
<p className="text-sm text-muted-foreground">26 beds in dorms</p> <p className="text-sm text-muted-foreground">Bed in shared room (39.20/night)</p>
</div> </div>
<div className="bg-muted/50 p-6 rounded-lg"> <div className="bg-muted/50 p-6 rounded-lg">
<div className="flex items-baseline gap-3 mb-2"> <div className="flex items-baseline gap-3 mb-2">
<span className="text-3xl font-bold">50.20</span> <span className="text-3xl font-bold">351.40</span>
<span className="text-muted-foreground">per night per person</span> <span className="text-muted-foreground">per person / 7 nights</span>
</div> </div>
<p className="text-sm text-muted-foreground">4 beds in double rooms</p> <p className="text-sm text-muted-foreground">Bed in double room (50.20/night)</p>
</div> </div>
</div> </div>
<h4 className="font-semibold mb-3">Herrnhof Villa (nearby)</h4>
<p className="text-xs text-muted-foreground mb-3">
Historic 19th-century mansion with newly renovated apartments, sauna, and river swimming platform.
All prices per person for 7 nights (incl. city tax &amp; VAT).
</p>
<div className="space-y-3 mb-6">
<div className="bg-muted/50 p-4 rounded-lg">
<div className="flex justify-between items-baseline">
<span className="text-sm font-medium">Single double bed</span>
<span className="text-lg font-bold">95</span>
</div>
</div>
<div className="bg-muted/50 p-4 rounded-lg">
<div className="flex justify-between items-baseline">
<span className="text-sm font-medium">Double double + single bed</span>
<span className="text-lg font-bold">60<span className="text-sm font-normal text-muted-foreground">/person</span></span>
</div>
</div>
<div className="bg-muted/50 p-4 rounded-lg">
<div className="flex justify-between items-baseline">
<span className="text-sm font-medium">Double shared double bed</span>
<span className="text-lg font-bold">50<span className="text-sm font-normal text-muted-foreground">/person</span></span>
</div>
</div>
<div className="bg-muted/50 p-4 rounded-lg">
<div className="flex justify-between items-baseline">
<span className="text-sm font-medium">Double couch + single in living room</span>
<span className="text-lg font-bold">40<span className="text-sm font-normal text-muted-foreground">/person</span></span>
</div>
</div>
<div className="bg-muted/50 p-4 rounded-lg">
<div className="flex justify-between items-baseline">
<span className="text-sm font-medium">Triple shared double + single bed</span>
<span className="text-lg font-bold">50<span className="text-sm font-normal text-muted-foreground">/person</span></span>
</div>
</div>
<p className="text-xs text-muted-foreground">
For whole-apartment quotes, contact <a href="mailto:office@commons-hub.at" className="text-primary hover:underline">office@commons-hub.at</a>.
</p>
</div>
<div className="pt-4"> <div className="pt-4">
<h4 className="font-semibold mb-3">Additional accommodation nearby:</h4> <h4 className="font-semibold mb-3">Other accommodation nearby:</h4>
<ul className="space-y-2 text-sm text-muted-foreground"> <ul className="space-y-2 text-sm text-muted-foreground">
<li className="flex items-start gap-2">
<CheckCircle2 className="w-4 h-4 text-primary mt-0.5 flex-shrink-0" />
<span>
<strong>Herrnhof.at</strong> comfortable apartments, ideal for teams
</span>
</li>
<li className="flex items-start gap-2"> <li className="flex items-start gap-2">
<CheckCircle2 className="w-4 h-4 text-primary mt-0.5 flex-shrink-0" /> <CheckCircle2 className="w-4 h-4 text-primary mt-0.5 flex-shrink-0" />
<span> <span>
@ -139,57 +178,9 @@ export default function FinancialTransparencyPage() {
<CardTitle className="text-2xl">Food</CardTitle> <CardTitle className="text-2xl">Food</CardTitle>
</CardHeader> </CardHeader>
<CardContent className="space-y-4"> <CardContent className="space-y-4">
<p className="text-sm text-muted-foreground mb-4"> <p className="text-sm text-muted-foreground">
Food is not included in the ticket price and is provided by the Commons Hub: Food is not included in the ticket price. We&apos;ll follow up via email with food options and pricing closer to the event.
</p> </p>
<div className="space-y-4">
<div className="bg-muted/50 p-6 rounded-lg">
<h4 className="font-semibold mb-3">What's Included:</h4>
<ul className="space-y-2">
<li className="flex items-start gap-2">
<CheckCircle2 className="w-5 h-5 text-primary mt-0.5 flex-shrink-0" />
<span className="text-sm">A rich vegetarian breakfast buffet</span>
</li>
<li className="flex items-start gap-2">
<CheckCircle2 className="w-5 h-5 text-primary mt-0.5 flex-shrink-0" />
<span className="text-sm">Coffee & tea throughout the day</span>
</li>
<li className="flex items-start gap-2">
<CheckCircle2 className="w-5 h-5 text-primary mt-0.5 flex-shrink-0" />
<span className="text-sm">Catered lunches (vegetarian/vegan and meat-based options)</span>
</li>
<li className="flex items-start gap-2">
<CheckCircle2 className="w-5 h-5 text-primary mt-0.5 flex-shrink-0" />
<span className="text-sm">Catered dinners from Aug 17-21</span>
</li>
<li className="flex items-start gap-2">
<CheckCircle2 className="w-5 h-5 text-primary mt-0.5 flex-shrink-0" />
<span className="text-sm">
Self-made dinners on Aug 16 & 22, prepared by community kitchen team
</span>
</li>
</ul>
</div>
<div className="bg-muted/50 p-6 rounded-lg">
<h4 className="font-semibold mb-2">Estimated Cost:</h4>
<div className="space-y-2 text-sm">
<div className="flex justify-between">
<span className="text-muted-foreground">First 3 days (fully catered)</span>
<span className="font-semibold">35/day</span>
</div>
<div className="flex justify-between">
<span className="text-muted-foreground">Last 3 days (self-organized)</span>
<span className="font-semibold">~10/day</span>
</div>
<div className="flex justify-between pt-2 border-t">
<span className="font-semibold">Total for 6 days</span>
<span className="text-2xl font-bold text-primary">135</span>
</div>
</div>
</div>
</div>
</CardContent> </CardContent>
</Card> </Card>
@ -200,7 +191,7 @@ export default function FinancialTransparencyPage() {
</CardHeader> </CardHeader>
<CardContent className="space-y-4"> <CardContent className="space-y-4">
<p className="text-muted-foreground mb-6"> <p className="text-muted-foreground mb-6">
For the full event (August 16-22, 2026), here's what you can expect to pay with early bird pricing: For the full event (August 16-23, 2026), here's what you can expect to pay with early bird pricing:
</p> </p>
<div className="space-y-3"> <div className="space-y-3">
@ -209,22 +200,22 @@ export default function FinancialTransparencyPage() {
<span className="text-lg font-semibold">80</span> <span className="text-lg font-semibold">80</span>
</div> </div>
<div className="flex justify-between items-center py-3 border-b border-border"> <div className="flex justify-between items-center py-3 border-b border-border">
<span className="font-medium">Accommodation (6 nights, dorm)</span> <span className="font-medium">Accommodation (7 nights, shared room)</span>
<span className="text-lg font-semibold">235.20</span> <span className="text-lg font-semibold">274.40</span>
</div> </div>
<div className="flex justify-between items-center py-3 border-b border-border"> <div className="flex justify-between items-center py-3 border-b border-border">
<span className="font-medium">Food (6 days)</span> <span className="font-medium">Food</span>
<span className="text-lg font-semibold">135</span> <span className="text-sm text-muted-foreground italic">TBA details coming soon</span>
</div> </div>
<div className="flex justify-between items-center py-4 bg-primary/10 -mx-6 px-6 mt-4"> <div className="flex justify-between items-center py-4 bg-primary/10 -mx-6 px-6 mt-4">
<span className="font-bold text-lg">Total (Early bird)</span> <span className="font-bold text-lg">Total (Early bird, excl. food)</span>
<span className="text-2xl font-bold text-primary">450.20</span> <span className="text-2xl font-bold text-primary">354.40</span>
</div> </div>
</div> </div>
<p className="text-sm text-muted-foreground italic pt-4"> <p className="text-sm text-muted-foreground italic pt-4">
*With regular pricing (120 ticket), total would be 490.20. With late pricing (150 ticket), total *With regular pricing (120 ticket), total would be 394.40. With late pricing (150 ticket), total
would be 520.20. would be 424.40. Herrnhof Villa accommodation starts from 40/person for the week.
</p> </p>
</CardContent> </CardContent>
</Card> </Card>

View File

@ -48,7 +48,7 @@ export async function sendPaymentConfirmation(
<p>Dear ${data.name},</p> <p>Dear ${data.name},</p>
<p>Your payment of <strong>${data.amountPaid}</strong> has been confirmed. You are now registered for <strong>Crypto Commons Gathering 2026</strong> in Austria's H&ouml;llental Valley, August 16&ndash;22, 2026.</p> <p>Your payment of <strong>${data.amountPaid}</strong> has been confirmed. You are now registered for <strong>Crypto Commons Gathering 2026</strong> in Austria's H&ouml;llental Valley, August 16&ndash;23, 2026.</p>
<div style="background: #fffbeb; padding: 20px; border-radius: 8px; margin: 24px 0; border-left: 3px solid #f59e0b;"> <div style="background: #fffbeb; padding: 20px; border-radius: 8px; margin: 24px 0; border-left: 3px solid #f59e0b;">
<h3 style="margin-top: 0; color: #92400e;">Registration Details</h3> <h3 style="margin-top: 0; color: #92400e;">Registration Details</h3>
@ -66,7 +66,7 @@ export async function sendPaymentConfirmation(
</div> </div>
<h3 style="color: #92400e;">Food &amp; Accommodation</h3> <h3 style="color: #92400e;">Food &amp; Accommodation</h3>
<p>If you haven't yet decided on food and accommodation, there's still time! The <strong>Commons Hub</strong> (our main venue with 30 on-site beds) and the nearby <strong><a href="https://herrnhof.at" style="color: #f59e0b;">Herrnhof</a></strong> are the most convenient and affordable options &mdash; right in the heart of the gathering. Other nearby options are also available; check the <a href="https://cryptocommonsgather.ing/directions" style="color: #f59e0b;">Directions page</a> for details.</p> <p>We'll follow up separately via email with food options and pricing. If you haven't yet decided on accommodation, there's still time! The <strong>Commons Hub</strong> (our main venue with 30 on-site beds) and the nearby <strong><a href="https://herrnhof.at" style="color: #f59e0b;">Herrnhof Villa</a></strong> are the most convenient options &mdash; right in the heart of the gathering. Other nearby options are also available; check the <a href="https://cryptocommonsgather.ing/directions" style="color: #f59e0b;">Directions page</a> for details.</p>
<h3 style="color: #92400e;">What's Next?</h3> <h3 style="color: #92400e;">What's Next?</h3>
<ul style="line-height: 1.8;"> <ul style="line-height: 1.8;">