Changing to supercast.

main
Thomas Hintz 2 years ago
parent f80d7efb9d
commit ce5f902493

@ -1,11 +1,9 @@
import UserMenu from '@/components/UserMenu';
import ReactorsLink from '@/components/ReactorsLink';
import NavBar from '@/components/NavBar'
export default function ExtraLayout({children}) {
return (
<>
<NavBar userMenu={(<UserMenu />)} reactorsLink={(<ReactorsLink />)} />
<NavBar />
<div className="lg:pt-16">
{children}
</div>

@ -1,27 +0,0 @@
import Link from 'next/link';
import { redirect } from 'next/navigation';
import { cookies } from 'next/headers';
import db from '@/db';
async function getSession() {
const cookieStore = cookies();
const sessionId = cookieStore.get('session');
if (!sessionId) {
return false;
}
const { user_id: userId } = await db.get('select user_id from sessions where session_id=?;', sessionId.value);
if (!userId) {
return false;
}
return userId;
};
export default async function Layout({ children }) {
const userId = await getSession();
if (!userId) {
redirect('/reactors');
}
return children;
};

@ -1,52 +0,0 @@
import { cookies } from 'next/headers';
import db from '@/db';
import { accountFeedURL } from '@/paths';
import { Container } from '@/components/Container';
async function getSession() {
const cookieStore = cookies();
const sessionId = cookieStore.get('session');
if (!sessionId) {
return false;
}
const dbRes = await db.get('select user_id from sessions where session_id=?;', sessionId.value);
const { user_id: userId } = dbRes ? dbRes : { user_id: false };
if (!userId) {
return false;
}
return userId;
};
export default async function Page() {
const userId = await getSession();
const { uuid } = await db.get('select uuid from subscriptions where user_id=?', userId);
return (
<div className="pt-16 pb-12 sm:pb-4 lg:pt-12">
<Container>
<h1 className="text-2xl font-bold leading-7 text-slate-900">
The Reactors
</h1>
<p>Thank you so much for your support! It makes this show possible!</p>
<div className="overflow-hidden rounded-lg bg-white shadow">
<div className="border-b border-gray-200 bg-white px-4 py-5 sm:px-6">
<h3 className="text-base font-semibold leading-6 text-gray-900">Your Personal Podcast Feed</h3>
</div>
<div className="px-4 py-5 sm:p-6">
<dl className="space-y-10">
<div>
<dt className="text-base font-semibold leading-7 text-gray-900">Copy/Paste URL into your podcast app:</dt>
<dd className="mt-2 text-base leading-7 text-gray-600"><a href={accountFeedURL(uuid)}>{accountFeedURL(uuid)}</a></dd>
</div>
<div>
<dt className="text-base font-semibold leading-7 text-gray-900">Instructions For Common Podcast Apps:</dt>
<dd className="mt-2 text-base leading-7 text-gray-600"><a href="/todo">Here</a></dd>
</div>
</dl>
</div>
</div>
</Container>
</div>
);
};

@ -1,143 +0,0 @@
export const dynamic = 'force-dynamic';
import Link from 'next/link'
import Stripe from 'stripe';
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY);
import { XCircleIcon } from '@heroicons/react/20/solid'
import { Container } from '@/components/Container';
// /reactors/create-account?csi=cs_test_a1pBB0FI8GUKnWYlCVn0RKUYXV8FRroacXjI5WVhWPlFJilm46lZwdjgac
export default async function Page({ searchParams }) {
const unexpectedError = searchParams['unexpected_error'];
const msg = searchParams['msg'];
const csi = searchParams['csi'];
const patreonMagicKey = searchParams['patreon_magic_key'];
const session = csi && await stripe.checkout.sessions.retrieve(csi);
const email = (csi && session && session.customer_details.email) || searchParams['email'];
if (unexpectedError) {
return (
<>
Unexpected Error sorry about that! Please contact us via <Link href="/contact">Contact</Link> and we will get it figured out!
</>
);
}
return (
<div className="pt-16 pb-12 sm:pb-4 lg:pt-12">
<Container>
<h1 className="text-2xl font-bold leading-7 text-slate-900">
The Reactors - Create Account
</h1>
<div className="divide-y divide-slate-100 sm:mt-4 lg:mt-8 lg:border-t lg:border-slate-100">
<p>
Thank you so much for signing up to become a Reactor! We just need a password now to create an account for you!
</p>
{msg && (
<div className="rounded-md bg-red-50 p-4 mt-8">
<div className="flex">
<div className="flex-shrink-0">
<XCircleIcon className="h-5 w-5 text-red-400" aria-hidden="true" />
</div>
<div className="ml-3">
<h3 className="text-sm font-medium text-red-800">There was an error with your submission</h3>
<div className="mt-2 text-sm text-red-700">
{msg}
</div>
</div>
</div>
</div>
)}
<form className="space-y-8" method="POST" action="/api/create-account">
<input
name="csi"
value={csi}
type="hidden"
/>
<input
name="patreon_magic_key"
value={patreonMagicKey}
type="hidden"
/>
<div className="space-y-8">
<div className="pt-8">
<div className="mt-6 grid grid-cols-1 gap-y-6 gap-x-4 sm:grid-cols-6">
<div className="sm:col-span-3">
<label htmlFor="emailprefilled" className="block text-sm font-medium text-gray-700">
Email address
</label>
<div className="mt-1">
<input
id="emailprefilled"
name="emailprefilled"
type="email"
defaultValue={email}
disabled
title="Email Address (required)"
className="block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm"
/>
<input
type="hidden"
name="email"
value={email}
/>
</div>
</div>
</div>
<div className="mt-6 grid grid-cols-1 gap-y-6 gap-x-4 sm:grid-cols-6">
<div className="sm:col-span-3">
<label htmlFor="password" className="block text-sm font-medium text-gray-700">
Password
</label>
<div className="mt-1">
<input
id="password"
name="password"
type="password"
required
minlength="12"
title="Password (required)"
className="block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm"
/>
</div>
</div>
<div className="sm:col-span-3">
<label htmlFor="passwordagain" className="block text-sm font-medium text-gray-700">
Password (again)
</label>
<div className="mt-1">
<input
id="passwordagain"
name="passwordagain"
type="password"
required
minlength="12"
title="Password (required)"
className="block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm"
/>
</div>
</div>
</div>
</div>
</div>
<div className="pt-5">
<div className="flex justify-end">
<button
type="submit"
className="ml-3 inline-flex justify-center rounded-md border border-transparent bg-indigo-600 py-2 px-4 text-sm font-medium text-white shadow-sm hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2"
>
Create Account
</button>
</div>
</div>
</form>
</div>
</Container>
</div>
);
};

@ -1,276 +0,0 @@
import Image from 'next/image';
import Link from 'next/link';
import { Container } from '@/components/Container';
import { CheckIcon } from '@heroicons/react/20/solid'
import reactorsBackground from '@/images/reactors3.jpeg';
import reactorsBackground2 from '@/images/reactors4.jpeg';
const features = [
{
name: 'Ad-Free Episodes',
description: 'Enjoy the podcast the way its meant to be enjoyed: just good, pure fun!'
},
{
name: 'The After-Show',
description: 'The After-Show, when the reactor really heats up! Regular, subscriber-only bonus content!',
},
{
name: 'Thank you for your financial support!',
description: 'It makes this show possible!',
}
];
const tiers = [
{
name: 'Monthly (USD)',
id: 'tier-monthly',
href: process.env.SUB_MONTHLY_URL,
price: '$10',
priceUnit: 'monthly',
description: '',
features: features.map(({ name }) => name),
},
{
name: 'Annual (USD)',
id: 'tier-annual',
href: process.env.SUB_ANNUAL_URL,
price: '$100',
priceUnit: 'yearly',
description: '',
features: [{ name: 'Save $20 by going yearly!' }, ...features].map(({ name }) => name),
},
];
const faqs = [
{
question: 'How do I listen to subscriber-exclusive podcasts and content?',
answer: `You will be provided with a unique podcast feed that you will be able to add to your favorite podcast player. We support Apple Podcasts, Spotify, Overcast, Podcast Addict, Pocket Casts, Podcast Republic, Downcast, RSSRadio, Podkicker, and more. Unfortunately we aren't able to support Stitcher, or any other podcast player that doesn't support importing private feeds.`,
},
{
question: 'How do I get in touch?',
answer: (<span>Send us a message on the <Link href="/contact-us" className="font-semibold text-indigo-600 hover:text-indigo-500">Contact Us</Link> page.</span>)
},
{
question: 'How do I cancel my subscription?',
answer: (<span>You can cancel your subsription at any time from your <Link href="/reactors/account" className="font-semibold text-indigo-600 hover:text-indigo-500">account page</Link>.</span>)
},
{
question: 'Why do you have a discounted subscription if it offers the same benefits?',
answer: `Good question! The main point of the subscription is to support the show but we also don't want to create benefits for only the more well-off or those living in wealthier locations. However, we are residents of the United States which has a higher cost of living so offering really low cost subscriptions doesn't provide a lot of benefit to us, after processing fees and administrative overhead, which is why the discounted subscription is annual only.`
}
]
export default async function Page() {
return (
<div className="relative isolate overflow-hidden pt-14">
<Image
src={reactorsBackground}
alt="artistic rendering of an atom"
className="absolute inset-0 -z-10 h-screen w-full object-cover"
/>
<div
className="absolute inset-x-0 -top-40 -z-10 transform-gpu overflow-hidden blur-3xl sm:-top-80"
aria-hidden="true"
>
<div
className="relative left-[calc(50%-11rem)] aspect-[1155/678] w-[36.125rem] -translate-x-1/2 rotate-[30deg] bg-gradient-to-tr from-[#ff80b5] to-[#9089fc] opacity-20 sm:left-[calc(50%-30rem)] sm:w-[72.1875rem]"
style={{
clipPath:
'polygon(74.1% 44.1%, 100% 61.6%, 97.5% 26.9%, 85.5% 0.1%, 80.7% 2%, 72.5% 32.5%, 60.2% 62.4%, 52.4% 68.1%, 47.5% 58.3%, 45.2% 34.5%, 27.5% 76.7%, 0.1% 64.9%, 17.9% 100%, 27.6% 76.8%, 76.1% 97.7%, 74.1% 44.1%)',
}}
/>
</div>
<div className="mx-auto max-w-2xl py-32 sm:py-48 lg:py-56">
<div className="text-center">
<h1 className="text-4xl font-bold tracking-tight text-white sm:text-6xl drop-shadow-md">
Join The Reactors!
</h1>
<p className="mt-6 text-lg leading-8 text-gray-300 drop-shadow-md">
The <strong>BEST</strong> way to support the show and gain access to subscriber-only bonus content!
</p>
<div className="mt-10 flex items-center justify-center gap-x-6">
<a
href="#pricing"
className="rounded-md bg-indigo-500 px-3.5 py-2.5 text-sm font-semibold text-white shadow-sm hover:bg-indigo-400 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-400 drop-shadow-md"
>
Join!
</a>
<a
href="#pricing"
className="rounded-md bg-slate-500 px-3.5 py-2.5 text-sm font-semibold text-white shadow-sm hover:bg-slate-400 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-400 drop-shadow-md"
>
Learn more <span aria-hidden="true"></span>
</a>
</div>
<div className="mt-4 flex items-center justify-center gap-x-6">
<Link
href="/reactors/sign-in"
className="text-white p-2 drop-shadow-md underline backdrop-brightness-90"
>
Already have an account? Sign In
</Link>
</div>
</div>
</div>
<div
className="absolute inset-x-0 top-[calc(100%-13rem)] -z-10 transform-gpu overflow-hidden blur-3xl sm:top-[calc(100%-30rem)]"
aria-hidden="true"
>
<div
className="relative left-[calc(50%+3rem)] aspect-[1155/678] w-[36.125rem] -translate-x-1/2 bg-gradient-to-tr from-[#ff80b5] to-[#9089fc] opacity-20 sm:left-[calc(50%+36rem)] sm:w-[72.1875rem]"
style={{
clipPath:
'polygon(74.1% 44.1%, 100% 61.6%, 97.5% 26.9%, 85.5% 0.1%, 80.7% 2%, 72.5% 32.5%, 60.2% 62.4%, 52.4% 68.1%, 47.5% 58.3%, 45.2% 34.5%, 27.5% 76.7%, 0.1% 64.9%, 17.9% 100%, 27.6% 76.8%, 76.1% 97.7%, 74.1% 44.1%)',
}}
/>
</div>
<div className="isolate overflow-hidden bg-gray-900" id="pricing">
<div className="mx-auto max-w-7xl px-6 pb-96 pt-24 text-center sm:pt-32 lg:px-8">
<div className="mx-auto max-w-4xl">
<h2 className="text-base font-semibold leading-7 text-indigo-400">Pricing</h2>
<p className="mt-2 text-4xl font-bold tracking-tight text-white sm:text-5xl">
We are better, <br className="hidden sm:inline lg:hidden" />
together
</p>
</div>
<div className="relative mt-6">
<p className="mx-auto max-w-2xl text-lg leading-8 text-white/60">
Support the show and join us in navigating this software journey.
</p>
<svg
viewBox="0 0 1208 1024"
className="absolute -top-10 left-1/2 -z-10 h-[64rem] -translate-x-1/2 [mask-image:radial-gradient(closest-side,white,transparent)] sm:-top-12 md:-top-20 lg:-top-12 xl:top-0"
>
<ellipse cx={604} cy={512} fill="url(#6d1bd035-0dd1-437e-93fa-59d316231eb0)" rx={604} ry={512} />
<defs>
<radialGradient id="6d1bd035-0dd1-437e-93fa-59d316231eb0">
<stop stopColor="#7775D6" />
<stop offset={1} stopColor="#E935C1" />
</radialGradient>
</defs>
</svg>
</div>
</div>
<div className="flow-root bg-white pb-24 sm:pb-32">
<div className="-mt-80">
<div className="mx-auto max-w-7xl px-6 lg:px-8">
<div className="mx-auto grid max-w-md grid-cols-1 gap-8 lg:max-w-4xl lg:grid-cols-2">
{tiers.map((tier) => (
<div
key={tier.id}
className="flex flex-col justify-between rounded-3xl bg-white p-8 shadow-xl ring-1 ring-gray-900/10 sm:p-10"
>
<div>
<h3 id={tier.id} className="text-base font-semibold leading-7 text-indigo-600">
{tier.name}
</h3>
<div className="mt-4 flex items-baseline gap-x-2">
<span className="text-5xl font-bold tracking-tight text-gray-900">{tier.price}</span>
<span className="text-base font-bold leading-7 text-gray-600">/{tier.priceUnit}</span>
</div>
<p className="mt-6 text-base leading-7 text-gray-600">{tier.description}</p>
<ul role="list" className="mt-10 space-y-4 text-sm leading-6 text-gray-600">
{tier.features.map((feature) => (
<li key={feature} className="flex gap-x-3">
<CheckIcon className="h-6 w-5 flex-none text-indigo-600" aria-hidden="true" />
{feature}
</li>
))}
</ul>
</div>
<a
href={tier.href}
aria-describedby={tier.id}
className="mt-8 block rounded-md bg-indigo-600 px-3.5 py-2 text-center text-sm font-semibold leading-6 text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600"
>
Join today!
</a>
</div>
))}
<div className="flex flex-col items-start gap-x-8 gap-y-6 rounded-3xl p-8 ring-1 ring-gray-900/10 sm:gap-y-10 sm:p-10 lg:col-span-2 lg:flex-row lg:items-center">
<div className="lg:min-w-0 lg:flex-1">
<h3 className="text-lg font-semibold leading-8 tracking-tight text-indigo-600">Discounted</h3>
<p className="mt-1 text-base leading-7 text-gray-600">
Can&apos;t afford a full-priced subscription right now? Or live in a place with a lower cost-of-living? The discounted subscription includes all of the benefits of a full subscription at a reduced price ($20 USD annually) and still helps support the show!
</p>
</div>
<a
href={process.env.SUB_DISCOUNT_URL}
className="rounded-md px-3.5 py-2 text-sm font-semibold leading-6 text-indigo-600 ring-1 ring-inset ring-indigo-200 hover:ring-indigo-300 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600"
>
Join discounted <span aria-hidden="true">&rarr;</span>
</a>
</div>
</div>
</div>
</div>
</div>
</div>
<div className="overflow-hidden bg-white py-24 sm:py-32" id="learn-more">
<div className="mx-auto max-w-7xl px-6 lg:px-8">
<div className="mx-auto grid max-w-2xl grid-cols-1 gap-x-8 gap-y-16 sm:gap-y-20 lg:mx-0 lg:max-w-none lg:grid-cols-2">
<div className="lg:ml-auto lg:pl-4 lg:pt-4">
<div className="lg:max-w-lg">
<h2 className="text-base font-semibold leading-7 text-indigo-600">The Reactors</h2>
<p className="mt-2 text-3xl font-bold tracking-tight text-gray-900 sm:text-4xl">Exclusive Content & Community</p>
<p className="mt-6 text-lg leading-8 text-gray-600">
Join <i>The Reactors</i> to directly support the show and gain access to ad-free, bonus content and The Reactors community!
</p>
<dl className="mt-10 max-w-xl space-y-8 text-base leading-7 text-gray-600 lg:max-w-none">
{features.map((feature) => (
<div key={feature.name} className="relative pl-9">
<dt className="inline font-semibold text-gray-900">
<CheckIcon className="absolute left-1 top-1 h-5 w-5 text-indigo-600" aria-hidden="true" />
{feature.name}
</dt>{' '}
<dd className="inline">{feature.description}</dd>
</div>
))}
</dl>
</div>
</div>
<div className="flex items-start justify-end lg:order-first">
<Image
src={reactorsBackground2}
alt="artistic atom above a hand"
className="w-[48rem] max-w-none rounded-xl shadow-xl ring-1 ring-gray-400/10 sm:w-[57rem]"
width={2432}
height={1442}
/>
</div>
</div>
</div>
</div>
<div className="bg-white">
<div className="mx-auto max-w-7xl px-6 py-24 sm:pt-32 lg:px-8 lg:py-40">
<div className="lg:grid lg:grid-cols-12 lg:gap-8">
<div className="lg:col-span-5">
<h2 className="text-2xl font-bold leading-10 tracking-tight text-gray-900">Frequently asked questions</h2>
<p className="mt-4 text-base leading-7 text-gray-600">
Cant find the answer youre looking for? Reach out to our{' '}
<Link href="/contact-us" className="font-semibold text-indigo-600 hover:text-indigo-500">
customer support
</Link>{' '}
team.
</p>
</div>
<div className="mt-10 lg:col-span-7 lg:mt-0">
<dl className="space-y-10">
{faqs.map((faq) => (
<div key={faq.question}>
<dt className="text-base font-semibold leading-7 text-gray-900">{faq.question}</dt>
<dd className="mt-2 text-base leading-7 text-gray-600">{faq.answer}</dd>
</div>
))}
</dl>
</div>
</div>
</div>
</div>
</div>
);
};

@ -1,14 +0,0 @@
import { Container } from '@/components/Container';
export default async function Page() {
return (
<div className="pt-16 pb-12 sm:pb-4 lg:pt-12">
<Container>
<h1 className="text-2xl font-bold leading-7 text-slate-900">
The Reactors
</h1>
<a href="https://buy.stripe.com/test_3cs01j768d65gso289">Level I</a>
</Container>
</div>
);
};

@ -1,132 +0,0 @@
export const dynamic = 'force-dynamic';
import Link from 'next/link'
import Stripe from 'stripe';
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY);
import { XCircleIcon } from '@heroicons/react/20/solid'
import { Container } from '@/components/Container';
// /reactors/create-account?csi=cs_test_a1pBB0FI8GUKnWYlCVn0RKUYXV8FRroacXjI5WVhWPlFJilm46lZwdjgac
export default async function Page({ searchParams }) {
const unexpectedError = searchParams['unexpected_error'];
const msg = searchParams['msg'];
const csi = searchParams['csi'];
const session = csi && await stripe.checkout.sessions.retrieve(csi);
const email = (csi && session && session.customer_details.email) || searchParams['email'];
if (unexpectedError) {
return (
<>
Unexpected Error sorry about that! Please contact us via <Link href="/contact">Contact</Link> and we will get it figured out!
</>
);
}
return (
<div className="pt-16 pb-12 sm:pb-4 lg:pt-12">
<Container>
<h1 className="text-2xl font-bold leading-7 text-slate-900">
The Reactors - Sign In
</h1>
<div className="divide-y divide-slate-100 sm:mt-4 lg:mt-8 lg:border-t lg:border-slate-100">
{msg && (
<div className="rounded-md bg-red-50 p-4 mt-8">
<div className="flex">
<div className="flex-shrink-0">
<XCircleIcon className="h-5 w-5 text-red-400" aria-hidden="true" />
</div>
<div className="ml-3">
<h3 className="text-sm font-medium text-red-800">There was an error with your submission</h3>
<div className="mt-2 text-sm text-red-700" data-cy="error-message">
{msg}
</div>
</div>
</div>
</div>
)}
<div className="flex min-h-full flex-col justify-center py-12 sm:px-6 lg:px-8">
<div className="sm:mx-auto sm:w-full sm:max-w-md">
<h2 className="mt-6 text-center text-3xl font-bold tracking-tight text-gray-900">Sign in to your account</h2>
<p className="mt-2 text-center text-sm text-gray-600">
Or{' '}
<Link href='/reactors' className="font-medium text-indigo-600 hover:text-indigo-500">
sign up to become a Reactor!
</Link>
</p>
</div>
<div className="mt-8 sm:mx-auto sm:w-full sm:max-w-md">
<div className="bg-white py-8 px-4 shadow sm:rounded-lg sm:px-10 bg-gray-50">
<form className="space-y-6" method="POST" action="/api/sign-in">
<div>
<label htmlFor="email" className="block text-sm font-medium text-gray-700">
Email address
</label>
<div className="mt-1">
<input
id="email"
name="email"
type="email"
autoComplete="email"
defaultValue={email}
required
className="block w-full appearance-none rounded-md border border-gray-300 px-3 py-2 placeholder-gray-400 shadow-sm focus:border-indigo-500 focus:outline-none focus:ring-indigo-500 sm:text-sm"
/>
</div>
</div>
<div>
<label htmlFor="password" className="block text-sm font-medium text-gray-700">
Password
</label>
<div className="mt-1">
<input
id="password"
name="password"
type="password"
autoComplete="current-password"
required
className="block w-full appearance-none rounded-md border border-gray-300 px-3 py-2 placeholder-gray-400 shadow-sm focus:border-indigo-500 focus:outline-none focus:ring-indigo-500 sm:text-sm"
/>
</div>
</div>
<div className="flex items-center justify-between">
<div className="flex items-center">
<input
id="remember_me"
name="remember_me"
type="checkbox"
className="h-4 w-4 rounded border-gray-300 text-indigo-600 focus:ring-indigo-500"
defaultValue="checked"
/>
<label htmlFor="remember_me" className="ml-2 block text-sm text-gray-900">
Remember me
</label>
</div>
<div className="text-sm">
<a href="#" className="font-medium text-indigo-600 hover:text-indigo-500">
Forgot your password?
</a>
</div>
</div>
<div>
<button
type="submit"
className="flex w-full justify-center rounded-md border border-transparent bg-indigo-600 py-2 px-4 text-sm font-medium text-white shadow-sm hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2"
>
Sign in
</button>
</div>
</form>
</div>
</div>
</div>
</div>
</Container>
</div>
);
};

@ -3,8 +3,6 @@ import Image from 'next/image'
import Link from 'next/link'
import UserMenu from '@/components/UserMenu';
import ReactorsLink from '@/components/ReactorsLink';
import NavBar from '@/components/NavBar'
import posterImage from '@/images/poster.png'
@ -177,7 +175,7 @@ function Layout({ children }) {
return (
<>
<NavBar userMenu={(<UserMenu />)} reactorsLink={(<ReactorsLink />)} />
<NavBar />
<header className="bg-slate-50 lg:fixed lg:inset-y-0 lg:left-0 lg:flex lg:w-112 lg:items-start lg:overflow-y-auto xl:w-120 lg:mt-16">
<div className="hidden lg:sticky lg:top-0 lg:flex lg:w-16 lg:flex-none lg:items-center lg:whitespace-nowrap lg:py-12 lg:text-sm lg:leading-7 lg:[writing-mode:vertical-rl]">
<span className="font-mono text-slate-500">Hosted by</span>

@ -1,72 +0,0 @@
import Link from 'next/link';
import { BookOpenIcon, BanknotesIcon } from '@heroicons/react/24/outline'
import { Container } from '@/components/Container';
const features = [
{
name: 'Buy My Book!',
link: '/book',
description:
'If you want to learn more in-depth how React work then this is definitely the best way to support the show!',
icon: BookOpenIcon,
},
{
name: 'Tip!',
link: 'https://buy.stripe.com/cN25nl5x2fZO4M0cMN',
description:
'Another great way to directly support the show is to send us a one-time tip! Thank you so much!',
icon: BanknotesIcon,
}
];
export const metadata = {
title: 'Support the Show!',
description: 'Show your support for the show with these options!'
};
export default async function Page() {
return (
<div className="pt-16 pb-12 sm:pb-4 lg:pt-12">
<Container>
<h1 className="text-2xl font-bold leading-7 text-slate-900">
Support
</h1>
</Container>
<div className="divide-y divide-slate-100 sm:mt-4 lg:mt-8 lg:border-t lg:border-slate-100">
<div className="bg-white py-24 sm:py-32">
<div className="mx-auto max-w-7xl px-6 lg:px-8">
<div className="mx-auto max-w-2xl lg:text-center">
<h2 className="text-lg font-semibold leading-8 tracking-tight text-indigo-600">Support the Show!</h2>
<p className="mt-2 text-3xl font-bold tracking-tight text-gray-900 sm:text-4xl">
Like <i>The React Show</i>? These are the best ways to support us!
</p>
</div>
<div className="mx-auto mt-16 max-w-2xl sm:mt-20 lg:mt-24 lg:max-w-4xl">
<dl className="grid max-w-xl grid-cols-1 gap-y-10 gap-x-8 lg:max-w-none lg:grid-cols-2 lg:gap-y-16">
{features.map((feature) => (
<div key={feature.name} className="relative pl-16">
<dt className="text-base font-semibold leading-7 text-gray-900">
<div className="absolute top-0 left-0 flex h-10 w-10 items-center justify-center rounded-lg bg-indigo-600">
<Link href={feature.link}><feature.icon className="h-6 w-6 text-white" aria-hidden="true" /></Link>
</div>
<Link
href={feature.link}
className="underline font-bold leading-6 text-pink-500 hover:text-pink-700 active:text-pink-900"
>
{feature.name}
</Link>
</dt>
<dd className="mt-2 text-base leading-7 text-gray-600">{feature.description}</dd>
</div>
))}
</dl>
</div>
</div>
</div>
</div>
</div>
);
}

@ -1,7 +1,5 @@
'use client';
import { Suspense } from 'react';
import Image from 'next/image';
import { usePathname } from 'next/navigation';
@ -22,7 +20,7 @@ function classNames(...classes) {
return classes.filter(Boolean).join(' ')
}
export default function NavBar({ userMenu, reactorsLink }) {
export default function NavBar() {
const pathname = usePathname();
return (
<Disclosure as="nav" className="bg-gray-800 fixed w-full z-20">
@ -66,20 +64,6 @@ export default function NavBar({ userMenu, reactorsLink }) {
</div>
<div className="hidden sm:ml-6 sm:block">
<div className="flex space-x-4">
<Suspense fallback={(
<Link
href="/reactors"
className={classNames(
'/reactors' === pathname ? 'bg-gray-900 text-white' : 'text-gray-300 hover:bg-gray-700 hover:text-white',
'rounded-md px-3 py-2 text-sm font-medium'
)}
aria-current={'/reactors' === pathname ? 'page' : undefined}
>
Reactors
</Link>
)}>
{reactorsLink}
</Suspense>
{navigation.map((item) => (
<Link
key={item.name}
@ -97,39 +81,18 @@ export default function NavBar({ userMenu, reactorsLink }) {
</div>
</div>
<div className="absolute inset-y-0 right-0 flex items-center pr-2 sm:static sm:inset-auto sm:ml-6 sm:pr-0">
{/* Profile dropdown */}
<Menu as="div" className="relative ml-3">
<Suspense fallback={(
<UserCircleIcon
className="h-8 w-8 rounded-full text-white animate-spin"
/>
)}>
{userMenu}
</Suspense>
</Menu>
<Link
href="/support"
className="bg-indigo-600 hover:bg-indigo-700 text-white rounded-md px-3 py-2 text-base font-medium"
>
Support
</Link>
</div>
</div>
</div>
<Disclosure.Panel className="sm:hidden">
<div className="flex flex-col space-y-4 px-2 pb-3 pt-2">
<Disclosure.Button>
<Suspense fallback={(
<Link
href="/reactors"
className={classNames(
'/reactors' === pathname ? 'bg-gray-900 text-white' : 'text-gray-300 hover:bg-gray-700 hover:text-white',
'block rounded-md px-3 py-2 text-base font-medium'
)}
aria-current={'/reactors' === pathname ? 'page' : undefined}
>
Reactors
</Link>
)}>
{reactorsLink}
</Suspense>
</Disclosure.Button>
{navigation.map((item) => (
<Disclosure.Button key={item.name}>
<Link

@ -1,45 +0,0 @@
'use server';
import Link from 'next/link';
import UserMenuClient from '@/components/UserMenuClient';
import { cookies } from 'next/headers';
import db from '@/db';
async function getSession() {
const cookieStore = cookies();
const sessionId = cookieStore.get('session');
if (!sessionId) {
return false;
}
const { user_id: userId } = await db.get('select user_id from sessions where session_id=?;', sessionId.value);
if (!userId) {
return false;
}
return userId;
};
export default async function ReactorsLink() {
const userId = await getSession();
if (userId) {
return (
<Link
href="/reactors/account"
className="text-gray-300 hover:bg-gray-700 hover:text-white rounded-md px-3 py-2 text-base font-medium"
>
Reactors
</Link>
)
} else {
return (
<Link
href="/reactors"
className="text-gray-300 hover:bg-gray-700 hover:text-white rounded-md px-3 py-2 text-base font-medium"
>
Reactors
</Link>
);
}
};

@ -1,70 +0,0 @@
'use server';
import Link from 'next/link';
import UserMenuClient from '@/components/UserMenuClient';
import { cookies } from 'next/headers';
import db from '@/db';
const signedInNavigation = [
{ name: 'Account', href: '/reactors/account' },
{ name: 'Sign Out', href: '/' },
]
async function getSession() {
const cookieStore = cookies();
const sessionId = cookieStore.get('session');
if (!sessionId) {
return false;
}
const { user_id: userId } = await db.get('select user_id from sessions where session_id=?;', sessionId.value);
if (!userId) {
return false;
}
return userId;
};
export default async function UserMenu() {
const userId = await getSession();
return (
<UserMenuClient>
{userId ? (
<>
<Link
href="/reactors/account"
className="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 active:bg-gray-100"
>
Account
</Link>
<form
method="POST"
action="/api/sign-out"
className="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 active:bg-gray-100"
>
<button
type="submit">
Sign Out
</button>
</form>
</>
) : (
<>
<Link
href="/reactors/sign-in"
className="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 active:bg-gray-100"
>
Sign In
</Link>
<Link
href="/reactors"
className="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 active:bg-gray-100"
>
Create Account
</Link>
</>
)}
</UserMenuClient>
);
};

@ -1,72 +0,0 @@
'use client';
import { Fragment } from 'react'
import { Disclosure, Menu, Transition } from '@headlessui/react'
import { Bars3Icon, UserCircleIcon, XMarkIcon } from '@heroicons/react/24/outline'
function classNames(...classes) {
return classes.filter(Boolean).join(' ')
}
export default function UserMenu({ children }) {
return (
<>
<div>
<Menu.Button className="flex rounded-full bg-gray-800 text-sm focus:outline-none focus:ring-2 focus:ring-white focus:ring-offset-2 focus:ring-offset-gray-800">
<span className="sr-only">Open user menu</span>
<UserCircleIcon
className="h-8 w-8 rounded-full text-white"
/>
</Menu.Button>
</div>
<Transition
as={Fragment}
enter="transition ease-out duration-100"
enterFrom="transform opacity-0 scale-95"
enterTo="transform opacity-100 scale-100"
leave="transition ease-in duration-75"
leaveFrom="transform opacity-100 scale-100"
leaveTo="transform opacity-0 scale-95"
>
<Menu.Items className="absolute right-0 z-10 mt-2 w-48 origin-top-right rounded-md bg-white py-1 shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none">
{children.map((link, i) => (
<Menu.Item key={i}>
{link}
</Menu.Item>
))}
</Menu.Items>
</Transition>
</>
);
};
/* <Menu.Item>
* {({ active }) => (
* <a
* href="#"
* className={classNames(active ? 'bg-gray-100' : '', 'block px-4 py-2 text-sm text-gray-700')}
* >
* Your Profile
* </a>
* )}
* </Menu.Item>
* <Menu.Item>
* {({ active }) => (
* <a
* href="#"
* className={classNames(active ? 'bg-gray-100' : '', 'block px-4 py-2 text-sm text-gray-700')}
* >
* Settings
* </a>
* )}
* </Menu.Item>
* <Menu.Item>
* {({ active }) => (
* <a
* href="#"
* className={classNames(active ? 'bg-gray-100' : '', 'block px-4 py-2 text-sm text-gray-700')}
* >
* Sign out
* </a>
* )}
* </Menu.Item> */

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 185 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 582 KiB

Loading…
Cancel
Save