4 Commits

Author SHA1 Message Date
823ac4f5c8 Add news post for February 2024 potluck
All checks were successful
Build Production Image / Build Production Image (push) Successful in 59s
2024-02-27 19:59:42 -08:00
292cefb945 Update events
All checks were successful
Build Production Image / Build Production Image (push) Successful in 54s
2024-02-03 14:33:30 -08:00
7f3499aba1 Fix table heading on board of directors 2024-02-01 19:59:28 -08:00
f62e434dff Fix club membership form in dark mode
All checks were successful
Build Production Image / Build Production Image (push) Successful in 53s
2024-02-01 19:55:11 -08:00
10 changed files with 150 additions and 26 deletions

View File

@ -66,7 +66,7 @@ export default function Club() {
<table className="min-w-full divide-y divide-gray-300"> <table className="min-w-full divide-y divide-gray-300">
<thead> <thead>
<tr> <tr>
<th scope="col" className="py-3.5 pl-4 pr-3 sm:pl-0">Name</th> <TableHeading>Name</TableHeading>
<TableHeading>Position</TableHeading> <TableHeading>Position</TableHeading>
</tr> </tr>
</thead> </thead>

View File

@ -2,12 +2,12 @@
import { type Metadata } from 'next' import { type Metadata } from 'next'
import Image from 'next/image' import Image from 'next/image'
import Link from 'next/link' import Link from 'next/link'
import dynamic from "next/dynamic";
import clsx from 'clsx' import clsx from 'clsx'
import { Container } from '@/components/Container' import { Container } from '@/components/Container'
import { UserPlusIcon, GiftIcon, EnvelopeIcon, UserGroupIcon } from '@heroicons/react/24/solid' import { UserPlusIcon, GiftIcon, EnvelopeIcon, UserGroupIcon } from '@heroicons/react/24/solid'
import interiorEmptyImage from '@/images/photos/interior-empty.jpg' import interiorEmptyImage from '@/images/photos/interior-empty.jpg'
import { ClubPayment } from './payment';
function SocialLink({ function SocialLink({
className, className,
@ -43,6 +43,15 @@ export const metadata: Metadata = {
// TODO: Replace interiorEmptyImage with a photo from a potluck // TODO: Replace interiorEmptyImage with a photo from a potluck
export default function Club() { export default function Club() {
// Dynamic import since ClubPayment uses `document`
const ClubPayment = dynamic(
() => {
return import("./payment");
},
{ ssr: false }
);
return ( return (
<Container className="mt-16 sm:mt-32"> <Container className="mt-16 sm:mt-32">
<div className="grid grid-cols-1 gap-y-16 lg:grid-cols-2 lg:grid-rows-[auto_1fr] lg:gap-y-12"> <div className="grid grid-cols-1 gap-y-16 lg:grid-cols-2 lg:grid-rows-[auto_1fr] lg:gap-y-12">

View File

@ -1,6 +1,6 @@
"use client" "use client"
import React, { useEffect, useState, FormEvent } from 'react'; import React, { useEffect, useState, FormEvent, useCallback } from 'react';
import { AddressElement, Elements } from '@stripe/react-stripe-js'; import { AddressElement, Elements } from '@stripe/react-stripe-js';
import { Appearance, StripeAddressElementOptions, StripeElementsOptions, loadStripe } from '@stripe/stripe-js'; import { Appearance, StripeAddressElementOptions, StripeElementsOptions, loadStripe } from '@stripe/stripe-js';
import { import {
@ -166,7 +166,7 @@ function CheckoutForm({
{/* Membership Type */} {/* Membership Type */}
<RadioGroup value={selectedMembershipLevel} onChange={setSelectedMembershipLevel} className="space-y-3"> <RadioGroup value={selectedMembershipLevel} onChange={setSelectedMembershipLevel} className="space-y-3">
<RadioGroup.Label className="text-base font-semibold leading-6 text-gray-900"> <RadioGroup.Label className="text-base font-semibold leading-6 text-gray-900 dark:text-white">
Select a membership type Select a membership type
</RadioGroup.Label> </RadioGroup.Label>
@ -177,8 +177,8 @@ function CheckoutForm({
value={membership} value={membership}
className={({ active }) => className={({ active }) =>
classNames( classNames(
active ? 'border-indigo-600 ring-2 ring-indigo-600' : 'border-gray-300', active ? 'border-indigo-600 ring-2 ring-indigo-600' : 'border-gray-200 dark:border-gray-500',
'relative flex cursor-pointer rounded-lg border bg-white p-4 shadow-sm focus:outline-none' 'relative flex cursor-pointer rounded-lg border bg-white hover:bg-gray-50 hover:dark:bg-zinc-600 dark:bg-zinc-700 p-4 shadow-sm focus:outline-none'
) )
} }
> >
@ -186,7 +186,7 @@ function CheckoutForm({
<> <>
<span className="flex flex-1 items-center justify-between "> <span className="flex flex-1 items-center justify-between ">
<span className="flex flex-col"> <span className="flex flex-col">
<RadioGroup.Label as="span" className="block text-sm font-medium text-gray-900"> <RadioGroup.Label as="span" className="block text-sm font-medium text-gray-900 dark:text-white">
{membership.title} {membership.title}
</RadioGroup.Label> </RadioGroup.Label>
<RadioGroup.Description as="span" className="mt-1 flex items-center text-sm text-gray-500"> <RadioGroup.Description as="span" className="mt-1 flex items-center text-sm text-gray-500">
@ -194,7 +194,7 @@ function CheckoutForm({
</RadioGroup.Description> </RadioGroup.Description>
</span> </span>
<RadioGroup.Description as="span" className="ml-8 text-sm font-medium"> <RadioGroup.Description as="span" className="ml-8 text-sm font-medium">
<span className="text-gray-900">${membership.price}</span> <span className="text-gray-900 dark:text-white">${membership.price}</span>
<span className="text-gray-500">/yr</span> <span className="text-gray-500">/yr</span>
</RadioGroup.Description> </RadioGroup.Description>
</span> </span>
@ -215,7 +215,7 @@ function CheckoutForm({
{/* Additional donation */} {/* Additional donation */}
<RadioGroup value={selectedAdditionalDonation} onChange={setSelectedAdditionalDonation} className="space-y-3"> <RadioGroup value={selectedAdditionalDonation} onChange={setSelectedAdditionalDonation} className="space-y-3">
<RadioGroup.Label className="text-base font-semibold leading-6 text-gray-900"> <RadioGroup.Label className="text-base font-semibold leading-6 text-gray-900 dark:text-white">
Additional donation Additional donation
</RadioGroup.Label> </RadioGroup.Label>
<div className="grid grid-cols-3 gap-3 sm:grid-cols-5"> <div className="grid grid-cols-3 gap-3 sm:grid-cols-5">
@ -228,9 +228,9 @@ function CheckoutForm({
'cursor-pointer focus:outline-none', 'cursor-pointer focus:outline-none',
option === -1 ? 'col-span-2' : '', option === -1 ? 'col-span-2' : '',
checked checked
? 'ring-2 ring-indigo-600 ring-offset-2' ? 'ring-2 ring-indigo-600'
: 'ring-1 ring-inset ring-gray-300 bg-white text-gray-900 hover:bg-gray-50', : 'ring-1 ring-inset ring-gray-200 dark:ring-gray-500 text-gray-900 dark:text-white hover:bg-gray-50 hover:dark:bg-zinc-600',
'flex items-center justify-center rounded-md py-3 px-3 text-sm font-semibold sm:flex-1' 'flex items-center justify-center rounded-md py-3 px-3 text-sm font-semibold sm:flex-1 bg-white dark:bg-zinc-700'
) )
} }
> >
@ -250,7 +250,7 @@ function CheckoutForm({
min="0" min="0"
step="1" step="1"
onChange={(e) => setCustomAmount(e.target.value)} onChange={(e) => setCustomAmount(e.target.value)}
className="block w-full rounded-md border-0 py-1.5 pl-7 pr-12 text-gray-900 ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-1 focus:ring-inset focus:ring-gray-500 sm:text-sm sm:leading-6" className="block w-full rounded-md border-0 py-1.5 pl-7 pr-12 text-gray-900 dark:text-white dark:bg-zinc-700 ring-1 ring-inset ring-gray-200 dark:ring-gray-500 placeholder:text-gray-400 focus:ring-1 focus:ring-inset focus:ring-gray-500 sm:text-sm sm:leading-6"
placeholder="Custom" placeholder="Custom"
aria-describedby="price-currency" aria-describedby="price-currency"
/> />
@ -274,12 +274,12 @@ function CheckoutForm({
</RadioGroup> </RadioGroup>
<div className="space-y-3"> <div className="space-y-3">
<h2 className="text-base font-semibold leading-6 text-gray-900"> <h2 className="text-base font-semibold leading-6 text-gray-900 dark:text-white">
About you About you
</h2> </h2>
<div className="rounded-md mb-3 px-3 pb-1.5 pt-2.5 shadow-sm ring-1 ring-inset ring-gray-300 focus-within:ring-2 focus-within:ring-indigo-600"> <div className="rounded-md mb-3 px-3 pb-1.5 pt-2.5 shadow-sm ring-1 ring-inset ring-gray-200 dark:ring-gray-500 focus-within:ring-2 focus-within:ring-indigo-600 dark:bg-zinc-700 dark:text-white">
<label htmlFor="name" className="block text-xs font-medium text-gray-900"> <label htmlFor="name" className="block text-xs font-medium text-gray-900 dark:text-zinc-400">
Email Email
</label> </label>
<input <input
@ -288,7 +288,7 @@ function CheckoutForm({
id="email" id="email"
value={email} value={email}
onChange={(e) => setEmail(e.target.value)} onChange={(e) => setEmail(e.target.value)}
className="block w-full border-0 p-0 text-gray-900 placeholder:text-gray-400 focus:ring-0 sm:text-sm sm:leading-6" className="block w-full border-0 p-0 dark:bg-zinc-700 text-gray-900 dark:text-white placeholder:text-gray-400 focus:ring-0 sm:text-sm sm:leading-6"
placeholder="you@example.com" placeholder="you@example.com"
/> />
</div> </div>
@ -296,7 +296,7 @@ function CheckoutForm({
</div> </div>
<div className="space-y-3"> <div className="space-y-3">
<h2 className="text-base font-semibold leading-6 text-gray-900"> <h2 className="text-base font-semibold leading-6 text-gray-900 dark:text-white">
Payment Payment
</h2> </h2>
<div className="mt-1 text-sm text-gray-500"> <div className="mt-1 text-sm text-gray-500">
@ -329,9 +329,37 @@ function CheckoutForm({
); );
} }
export function ClubPayment() { const DEFAULT_OPTIONS = {
config: { attributes: true, childList: true, subtree: true },
};
function useMutationObservable(targetEl: Node, cb: MutationCallback, options = DEFAULT_OPTIONS) {
const [observer, setObserver] = useState<MutationObserver | null>(null);
useEffect(() => {
const obs = new MutationObserver(cb);
setObserver(obs);
}, [cb, options, setObserver]);
useEffect(() => {
if (!observer) return;
const { config } = options;
observer.observe(targetEl, config);
return () => {
if (observer) {
observer.disconnect();
}
};
}, [observer, targetEl, options]);
}
export default function ClubPayment() {
const [clientSecret, setClientSecret] = useState(''); const [clientSecret, setClientSecret] = useState('');
const [paymentIntent, setPaymentIntent] = useState(''); const [paymentIntent, setPaymentIntent] = useState('');
const htmlEl = document.getElementsByTagName('html')[0];
const darkTheme = htmlEl.classList.contains("dark");
useEffect(() => { useEffect(() => {
// Create PaymentIntent as soon as the page loads using our local API // Create PaymentIntent as soon as the page loads using our local API
fetch('api/stripe_intent', { fetch('api/stripe_intent', {
@ -349,15 +377,36 @@ export function ClubPayment() {
}); });
}, []); }, []);
const styles = getComputedStyle(htmlEl);
const appearance: Appearance = { const appearance: Appearance = {
theme: 'stripe', theme: 'stripe',
variables: {
colorBackground: styles.getPropertyValue('--stripe-background'),
colorText: styles.getPropertyValue('--stripe-foreground'),
},
labels: 'floating', labels: 'floating',
}; };
const cb = useCallback(
() => {
const updatedHtmlEl = document.getElementsByTagName('html')[0];
const updatedDarkTheme = updatedHtmlEl.classList.contains("dark");
if (updatedDarkTheme !== darkTheme) {
location.reload();
}
},
[darkTheme]
)
useMutationObservable(htmlEl, cb);
const options: StripeElementsOptions = { const options: StripeElementsOptions = {
clientSecret, clientSecret,
appearance appearance,
} }
return <> return <>
{clientSecret && ( {clientSecret && (
<Elements options={options} <Elements options={options}

Binary file not shown.

After

Width:  |  Height:  |  Size: 307 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 474 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 413 KiB

View File

@ -0,0 +1,58 @@
import { ArticleLayout } from '@/components/ArticleLayout'
import Image from 'next/image'
import boddingtonStore from './Boddingtons_Store_West_Sound.jpg'
import westSoundMainStreet from './West_Sound_Main_Street.jpg'
import westSound from './West_Sound.jpg'
export const article = {
author: 'Tony Grosinger',
date: '2024-02-17',
title: 'February 2024 Potluck',
description: "The second potluck of the year, with a slidshow of Orcas history from John Wachter.",
}
export const metadata = {
title: article.title,
description: article.description,
}
export default (props) => <ArticleLayout article={article} {...props} />
This month after the potluck dinner, the community club was treated to a
slideshow presentation from John Wachter. He showed us almost 100 photos from
all over Orcas Island, many of which dated back to the early 1900's.
<div className="not-prose flex flex-col items-center">
<Image src={boddingtonStore} alt="Boddington's Store at the end of Crow Valley Road" />
<span className="mt-2 text-sm text-zinc-400 dark:text-zinc-500">
Boddington's Store at the end of Crow Valley Road.
</span>
</div>
Many of these images were available to us thanks to the [Orcas Island Historical
Society](https://www.orcasmuseums.org/), and several of the photos were also
passed down by John's family.
<div className="not-prose flex flex-col items-center">
<Image src={westSoundMainStreet} alt="West Sound Main Street" />
<span className="mt-2 text-sm text-zinc-400 dark:text-zinc-500">
West Sound Main Street
</span>
</div>
A recurring observation was both how many more buildings there were in West
Sound, and how few trees there were on the island!
<div className="not-prose flex flex-col items-center">
<Image src={westSound} alt="West Sound and the south end of Turtleback" />
<span className="mt-2 text-sm text-zinc-400 dark:text-zinc-500">
West Sound and the south end of Turtleback
</span>
</div>
If you have ideas for presentations or activities at upcoming potlucks, please <a
target="_blank" href="mailto:board@westsoundhall.org">send us a message</a>.
Thank you John, the Historical Society, and Peter Fisher for preserving and
sharing this history.

View File

@ -41,8 +41,4 @@ the hall available for rental by the community, and even added the hall to the
WA Heritage Register. There&apos;s so much more to the hall than just potlucks, WA Heritage Register. There&apos;s so much more to the hall than just potlucks,
and this website hopes to share this with the West Sound Community. and this website hopes to share this with the West Sound Community.
If you&apos;d like to follow along, please <a target="_blank"
href="https://orcas.community/mailinglists/7">sign up for email
announcements</a> when new blog posts are published.
Thanks for being a part of the West Sound Community! Thanks for being a part of the West Sound Community!

View File

@ -13,8 +13,8 @@
{ {
"title": "Town Hall Meeting", "title": "Town Hall Meeting",
"date": "2024-03-06", "date": "2024-03-06",
"startTime": "6:00pm", "startTime": "5:00pm",
"endTime": "8:00pm" "endTime": "7:00pm"
}, },
{ {
"title": "March Potluck", "title": "March Potluck",

View File

@ -2,3 +2,15 @@
@import 'tailwindcss/components'; @import 'tailwindcss/components';
@import './prism.css'; @import './prism.css';
@import 'tailwindcss/utilities'; @import 'tailwindcss/utilities';
:root {
/* Your default theme */
--stripe-background: #FFFFFF;
--stripe-foreground: #000000;
}
.dark {
--stripe-background: #3f3f46;
--stripe-foreground: #E4E4E7;
}