diff --git a/.eslintrc.cjs b/.eslintrc.cjs index f0bcf77..872a7c1 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -14,6 +14,7 @@ const config = { "plugin:prettier/recommended" ], "rules": { + "@typescript-eslint/no-unsafe-call": "off", "@typescript-eslint/no-explicit-any": "off", "@typescript-eslint/array-type": "off", "@typescript-eslint/consistent-type-definitions": "off", diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml index 25da3f3..edfd05e 100644 --- a/.github/workflows/checks.yml +++ b/.github/workflows/checks.yml @@ -12,14 +12,16 @@ jobs: services: postgres: - image: postgres + image: postgres:latest env: - POSTGRES_PASSWORD: postgres - options: >- - --health-cmd pg_isready - --health-interval 10s - --health-timeout 5s - --health-retries 5 + POSTGRES_USER: test + POSTGRES_PASSWORD: test + POSTGRES_DB: db + POSTGRESQL_FSYNC: "off" + ports: + - 5432:5432 + # needed because the postgres container does not provide a healthcheck + options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5 steps: - name: Checkout @@ -70,16 +72,20 @@ jobs: run: ${{ steps.detect-package-manager.outputs.manager }} run lint env: SKIP_ENV_VALIDATION: true - DATABASE_URL: postgres://postgres:postgres@localhost:5432/postgres + DATABASE_URL: postgres://test:test@localhost:5432/db - name: Lint Prisma run: ${{ steps.detect-package-manager.outputs.manager }} run lint:prisma env: - SKIP_ENV_VALIDATION: true - DATABASE_URL: postgres://postgres:postgres@localhost:5432/postgres + DATABASE_URL: postgres://test:test@localhost:5432/db + + - name: Can run Migrations + run: ${{ steps.detect-package-manager.outputs.manager }} run db:push + env: + DATABASE_URL: postgres://test:test@localhost:5432/db - name: Build - run: ${{ steps.detect-package-manager.outputs.manager }} run build + run: ${{ steps.detect-package-manager.outputs.manager }} run build -d env: SKIP_ENV_VALIDATION: true - DATABASE_URL: postgres://postgres:postgres@localhost:5432/postgres \ No newline at end of file + DATABASE_URL: postgres://test:test@localhost:5432/db \ No newline at end of file diff --git a/src/app/actions/createMembership.ts b/src/app/actions/createMembership.ts index 2b8b7bf..4372336 100644 --- a/src/app/actions/createMembership.ts +++ b/src/app/actions/createMembership.ts @@ -4,9 +4,9 @@ import { MembershipStatus } from "@prisma/client" import { type ServerActionState, ServerActionStatus } from "@/app/actions/types" import { db } from "@/services/db" -import { stripe } from "@/services/stripe" +import { canUseStripe, stripe } from "@/services/stripe" -const MEMBERSHIP_PRICE_ID = "price_1P3HNlCXdJySzBrwlcoAQqS2" +const MEMBERSHIP_PRICE_ID = "price_1P3HNlCXdJySzBrwlcoAQqS2" // TODO: Remove the hardcoded price ID export interface FormProps { email: string @@ -20,6 +20,16 @@ export async function createMembership( prevState: ServerActionState, data: FormProps, ): Promise { + if (!canUseStripe()) { + return { + errors: [ + { + message: "Stripe is not configured", + }, + ], + status: ServerActionStatus.Error, + } + } // Avoid double membership creation if (prevState.nextStep === "providePayment") return prevState @@ -30,6 +40,18 @@ export async function createMembership( }, }) + // No template, return error + if (!membershipTemplate) { + return { + errors: [ + { + message: "Membership template not found", + }, + ], + status: ServerActionStatus.Error, + } + } + // Check for user let user = await db.user.findFirst({ where: { @@ -52,7 +74,7 @@ export async function createMembership( // User is not linked to Stripe, creates it if (!user.stripeCustomerId) { // Create customer to Stripe and link it to user - const stripeCustomer = await stripe.customers.create({ + const stripeCustomer = await stripe().customers.create({ email: data.email, name: `${data.firstName} ${data.lastName}`.trim(), }) @@ -97,7 +119,7 @@ export async function createMembership( }) // Create Stripe subscription - const stripeSubscription = await stripe.subscriptions.create({ + const stripeSubscription = await stripe().subscriptions.create({ customer: user.stripeCustomerId, expand: ["latest_invoice.payment_intent"], items: [ @@ -123,7 +145,8 @@ export async function createMembership( nextStep: "providePayment", payload: { // eslint-disable-next-line - clientSecret: (stripeSubscription?.latest_invoice as any)?.payment_intent?.client_secret, + clientSecret: (stripeSubscription?.latest_invoice as any)?.payment_intent + ?.client_secret, membershipId: membership.id, }, status: ServerActionStatus.Success, diff --git a/src/app/actions/createMembershipTemplate.ts b/src/app/actions/createMembershipTemplate.ts index a9aef89..bb9072e 100644 --- a/src/app/actions/createMembershipTemplate.ts +++ b/src/app/actions/createMembershipTemplate.ts @@ -1,19 +1,16 @@ -"use server"; +"use server" -import { - type ServerActionState, - ServerActionStatus, -} from "@/app/actions/types"; -import { db } from "@/services/db"; -import { PricePeriod, type PriceUnit } from "@prisma/client"; +import { type ServerActionState, ServerActionStatus } from "@/app/actions/types" +import { db } from "@/services/db" +import { PricePeriod, type PriceUnit } from "@prisma/client" export interface FormProps { - title: string; - description?: string; - features?: string; - priceAmount: number; - priceUnit: PriceUnit; - stripePriceId: string; + title: string + description?: string + features?: string + priceAmount: number + priceUnit: PriceUnit + stripePriceId: string } export async function createMembershipTemplate( @@ -35,10 +32,10 @@ export async function createMembershipTemplate( createdAt: new Date(), updatedAt: new Date(), }, - }); + }) return { status: ServerActionStatus.Success, payload: membershipTemplate, - }; + } } diff --git a/src/app/actions/editMembershipTemplate.ts b/src/app/actions/editMembershipTemplate.ts index 82cc522..34145e4 100644 --- a/src/app/actions/editMembershipTemplate.ts +++ b/src/app/actions/editMembershipTemplate.ts @@ -1,20 +1,17 @@ -"use server"; +"use server" -import { - type ServerActionState, - ServerActionStatus, -} from "@/app/actions/types"; -import { db } from "@/services/db"; -import { PricePeriod, type PriceUnit } from "@prisma/client"; +import { type ServerActionState, ServerActionStatus } from "@/app/actions/types" +import { db } from "@/services/db" +import { PricePeriod, type PriceUnit } from "@prisma/client" export interface FormProps { - id: string; - title: string; - description?: string; - features?: string; - priceAmount: number; - priceUnit: PriceUnit; - stripePriceId: string; + id: string + title: string + description?: string + features?: string + priceAmount: number + priceUnit: PriceUnit + stripePriceId: string } export async function editMembershipTemplate( @@ -38,10 +35,10 @@ export async function editMembershipTemplate( stripePriceId: data.stripePriceId, updatedAt: new Date(), }, - }); + }) return { status: ServerActionStatus.Success, payload: membershipTemplate, - }; + } } diff --git a/src/app/actions/validateUserEmail.ts b/src/app/actions/validateUserEmail.ts index b46d921..8b22ea4 100644 --- a/src/app/actions/validateUserEmail.ts +++ b/src/app/actions/validateUserEmail.ts @@ -1,16 +1,16 @@ -"use server"; +"use server" -import { MembershipStatus } from "@prisma/client"; +import { MembershipStatus } from "@prisma/client" -import { db } from "@/services/db"; +import { db } from "@/services/db" export interface ServerActionState { - checked: boolean; - valid: boolean; - email?: string; + checked: boolean + valid: boolean + email?: string } interface FormProps { - email: string; + email: string } export async function validateUserEmail( prevState: ServerActionState, @@ -20,14 +20,14 @@ export async function validateUserEmail( where: { email: data.email, }, - }); + }) // No user means that is not valid if (!user) return { checked: true, valid: false, - }; + } // User without membership means that is not valid const membership = await db.membership.findFirst({ @@ -37,16 +37,16 @@ export async function validateUserEmail( }, userId: user.id, }, - }); + }) if (!membership) return { checked: true, valid: false, - }; + } return { checked: true, email: data.email, valid: true, - }; + } } diff --git a/src/app/admin/@authenticated/membership/layout.tsx b/src/app/admin/@authenticated/membership/layout.tsx index c9d37fc..c043431 100644 --- a/src/app/admin/@authenticated/membership/layout.tsx +++ b/src/app/admin/@authenticated/membership/layout.tsx @@ -1,16 +1,16 @@ -import { find } from "lodash"; +import { find } from "lodash" -import { adminMenuTreeConfig } from "@/app/admin/const"; -import { LinkWithActive } from "@/components/molecules/linkWithActive"; +import { adminMenuTreeConfig } from "@/app/admin/const" +import { LinkWithActive } from "@/components/molecules/linkWithActive" interface AdminAuthenticatedLayoutInterface { - children: React.ReactNode; + children: React.ReactNode } export default async function AdminAuthenticatedLayout({ children, }: AdminAuthenticatedLayoutInterface) { - const settingsChildren = find(adminMenuTreeConfig, { id: "membership" })!; + const settingsChildren = find(adminMenuTreeConfig, { id: "membership" })! return ( <> @@ -28,5 +28,5 @@ export default async function AdminAuthenticatedLayout({
{children}
- ); + ) } diff --git a/src/app/admin/@authenticated/membership/manage/@modal/(.)create/client.tsx b/src/app/admin/@authenticated/membership/manage/@modal/(.)create/client.tsx index 3ccd78e..bccd744 100644 --- a/src/app/admin/@authenticated/membership/manage/@modal/(.)create/client.tsx +++ b/src/app/admin/@authenticated/membership/manage/@modal/(.)create/client.tsx @@ -1,28 +1,28 @@ -"use client"; +"use client" -import { AdminMembershipCRUDForm } from "@/app/admin/@authenticated/membership/manage/form"; -import { CRUDFormIntent } from "@/modules/crudForm/types"; -import { useToast } from "@/components/ui/use-toast"; -import { useRouter } from "next/navigation"; +import { AdminMembershipCRUDForm } from "@/app/admin/@authenticated/membership/manage/form" +import { CRUDFormIntent } from "@/modules/crudForm/types" +import { useToast } from "@/components/ui/use-toast" +import { useRouter } from "next/navigation" export function AdminMembershipCreateModalClient() { - const { toast } = useToast(); - const router = useRouter(); + const { toast } = useToast() + const router = useRouter() const onSubmit = () => { toast({ title: "Success", description: "Membership Template created", variant: "success", - }); - router.back(); - router.refresh(); - }; + }) + router.back() + router.refresh() + } return ( - ); + ) } diff --git a/src/app/admin/@authenticated/membership/manage/@modal/(.)create/page.tsx b/src/app/admin/@authenticated/membership/manage/@modal/(.)create/page.tsx index 78b7392..f952a97 100644 --- a/src/app/admin/@authenticated/membership/manage/@modal/(.)create/page.tsx +++ b/src/app/admin/@authenticated/membership/manage/@modal/(.)create/page.tsx @@ -1,11 +1,11 @@ -import { Modal } from "@/components/molecules/modal"; -import { AdminMembershipCRUDForm } from "@/app/admin/@authenticated/membership/manage/form"; -import { CRUDFormIntent } from "@/modules/crudForm/types"; +import { Modal } from "@/components/molecules/modal" +import { AdminMembershipCRUDForm } from "@/app/admin/@authenticated/membership/manage/form" +import { CRUDFormIntent } from "@/modules/crudForm/types" export default function AdminMembershipModalCreatePage() { return ( - ); + ) } diff --git a/src/app/admin/@authenticated/membership/manage/@modal/(.)edit/[id]/client.tsx b/src/app/admin/@authenticated/membership/manage/@modal/(.)edit/[id]/client.tsx index 2a9e594..6fdfaab 100644 --- a/src/app/admin/@authenticated/membership/manage/@modal/(.)edit/[id]/client.tsx +++ b/src/app/admin/@authenticated/membership/manage/@modal/(.)edit/[id]/client.tsx @@ -1,30 +1,30 @@ -"use client"; +"use client" -import { AdminMembershipCRUDForm } from "@/app/admin/@authenticated/membership/manage/form"; -import { CRUDFormIntent } from "@/modules/crudForm/types"; -import { type MembershipTemplate } from "@prisma/client"; -import { useToast } from "@/components/ui/use-toast"; -import { useRouter } from "next/navigation"; +import { AdminMembershipCRUDForm } from "@/app/admin/@authenticated/membership/manage/form" +import { CRUDFormIntent } from "@/modules/crudForm/types" +import { type MembershipTemplate } from "@prisma/client" +import { useToast } from "@/components/ui/use-toast" +import { useRouter } from "next/navigation" interface AdminMembershipEditPageClient { - previousValues: MembershipTemplate; + previousValues: MembershipTemplate } export function AdminMembershipEditModalClient({ previousValues, }: AdminMembershipEditPageClient) { - const { toast } = useToast(); - const router = useRouter(); + const { toast } = useToast() + const router = useRouter() const onSubmit = () => { toast({ title: "Success", description: "Membership Template updated", variant: "success", - }); - router.back(); - router.refresh(); - }; + }) + router.back() + router.refresh() + } return ( - ); + ) } diff --git a/src/app/admin/@authenticated/membership/manage/@modal/(.)edit/[id]/page.tsx b/src/app/admin/@authenticated/membership/manage/@modal/(.)edit/[id]/page.tsx index c172d00..bc12e39 100644 --- a/src/app/admin/@authenticated/membership/manage/@modal/(.)edit/[id]/page.tsx +++ b/src/app/admin/@authenticated/membership/manage/@modal/(.)edit/[id]/page.tsx @@ -1,29 +1,29 @@ -import { Modal } from "@/components/molecules/modal"; -import { db } from "@/services/db"; -import { AdminMembershipEditModalClient } from "@/app/admin/@authenticated/membership/manage/@modal/(.)edit/[id]/client"; +import { Modal } from "@/components/molecules/modal" +import { db } from "@/services/db" +import { AdminMembershipEditModalClient } from "@/app/admin/@authenticated/membership/manage/@modal/(.)edit/[id]/client" const getData = (id: string) => { return db.membershipTemplate.findUnique({ where: { id, }, - }); -}; + }) +} interface AdminMembershipEditPageProps { params: { - id: string; - }; + id: string + } } export default async function AdminMembershipModalEditPage({ params, }: AdminMembershipEditPageProps) { - const membershipTemplate = await getData(params.id); + const membershipTemplate = await getData(params.id) return ( - ); + ) } diff --git a/src/app/admin/@authenticated/membership/manage/@modal/create/client.tsx b/src/app/admin/@authenticated/membership/manage/@modal/create/client.tsx index 5ca9722..13599fb 100644 --- a/src/app/admin/@authenticated/membership/manage/@modal/create/client.tsx +++ b/src/app/admin/@authenticated/membership/manage/@modal/create/client.tsx @@ -1,28 +1,28 @@ -"use client"; +"use client" -import { AdminMembershipCRUDForm } from "@/app/admin/@authenticated/membership/manage/form"; -import { CRUDFormIntent } from "@/modules/crudForm/types"; -import { useToast } from "@/components/ui/use-toast"; -import { useRouter } from "next/navigation"; +import { AdminMembershipCRUDForm } from "@/app/admin/@authenticated/membership/manage/form" +import { CRUDFormIntent } from "@/modules/crudForm/types" +import { useToast } from "@/components/ui/use-toast" +import { useRouter } from "next/navigation" export function AdminMembershipCreatePageClient() { - const { toast } = useToast(); - const router = useRouter(); + const { toast } = useToast() + const router = useRouter() const onSubmit = () => { toast({ title: "Success", description: "Membership Template created", variant: "success", - }); - router.replace("/admin/membership/manage"); - router.refresh(); - }; + }) + router.replace("/admin/membership/manage") + router.refresh() + } return ( - ); + ) } diff --git a/src/app/admin/@authenticated/membership/manage/@modal/create/page.tsx b/src/app/admin/@authenticated/membership/manage/@modal/create/page.tsx index 5b03c8a..f7ec616 100644 --- a/src/app/admin/@authenticated/membership/manage/@modal/create/page.tsx +++ b/src/app/admin/@authenticated/membership/manage/@modal/create/page.tsx @@ -1,9 +1,9 @@ -import { AdminMembershipCreatePageClient } from "@/app/admin/@authenticated/membership/manage/@modal/create/client"; +import { AdminMembershipCreatePageClient } from "@/app/admin/@authenticated/membership/manage/@modal/create/client" export default function AdminMembershipCreatePage() { return (
- ); + ) } diff --git a/src/app/admin/@authenticated/membership/manage/@modal/default.tsx b/src/app/admin/@authenticated/membership/manage/@modal/default.tsx index 8ee23ba..01a4a7f 100644 --- a/src/app/admin/@authenticated/membership/manage/@modal/default.tsx +++ b/src/app/admin/@authenticated/membership/manage/@modal/default.tsx @@ -1,3 +1,3 @@ export default function AdminMembershipModalDefault() { - return null; + return null } diff --git a/src/app/admin/@authenticated/membership/manage/@modal/edit/[id]/client.tsx b/src/app/admin/@authenticated/membership/manage/@modal/edit/[id]/client.tsx index c0e5a3f..274b87d 100644 --- a/src/app/admin/@authenticated/membership/manage/@modal/edit/[id]/client.tsx +++ b/src/app/admin/@authenticated/membership/manage/@modal/edit/[id]/client.tsx @@ -1,30 +1,30 @@ -"use client"; +"use client" -import { AdminMembershipCRUDForm } from "@/app/admin/@authenticated/membership/manage/form"; -import { CRUDFormIntent } from "@/modules/crudForm/types"; -import { type MembershipTemplate } from "@prisma/client"; -import { useToast } from "@/components/ui/use-toast"; -import { useRouter } from "next/navigation"; +import { AdminMembershipCRUDForm } from "@/app/admin/@authenticated/membership/manage/form" +import { CRUDFormIntent } from "@/modules/crudForm/types" +import { type MembershipTemplate } from "@prisma/client" +import { useToast } from "@/components/ui/use-toast" +import { useRouter } from "next/navigation" interface AdminMembershipEditPageClient { - previousValues: MembershipTemplate; + previousValues: MembershipTemplate } export function AdminMembershipEditPageClient({ previousValues, }: AdminMembershipEditPageClient) { - const { toast } = useToast(); - const router = useRouter(); + const { toast } = useToast() + const router = useRouter() const onSubmit = () => { toast({ title: "Success", description: "Membership Template updated", variant: "success", - }); - router.replace("/admin/membership/manage"); - router.refresh(); - }; + }) + router.replace("/admin/membership/manage") + router.refresh() + } return ( - ); + ) } diff --git a/src/app/admin/@authenticated/membership/manage/@modal/edit/[id]/page.tsx b/src/app/admin/@authenticated/membership/manage/@modal/edit/[id]/page.tsx index 720953e..4508194 100644 --- a/src/app/admin/@authenticated/membership/manage/@modal/edit/[id]/page.tsx +++ b/src/app/admin/@authenticated/membership/manage/@modal/edit/[id]/page.tsx @@ -1,28 +1,28 @@ -import { db } from "@/services/db"; -import { AdminMembershipEditPageClient } from "@/app/admin/@authenticated/membership/manage/@modal/edit/[id]/client"; +import { db } from "@/services/db" +import { AdminMembershipEditPageClient } from "@/app/admin/@authenticated/membership/manage/@modal/edit/[id]/client" const getData = (id: string) => { return db.membershipTemplate.findUnique({ where: { id, }, - }); -}; + }) +} interface AdminMembershipEditPageProps { params: { - id: string; - }; + id: string + } } export default async function AdminMembershipEditPage({ params, }: AdminMembershipEditPageProps) { - const membershipTemplate = await getData(params.id); + const membershipTemplate = await getData(params.id) return (
- ); + ) } diff --git a/src/app/admin/@authenticated/membership/manage/default.tsx b/src/app/admin/@authenticated/membership/manage/default.tsx index 8ee23ba..01a4a7f 100644 --- a/src/app/admin/@authenticated/membership/manage/default.tsx +++ b/src/app/admin/@authenticated/membership/manage/default.tsx @@ -1,3 +1,3 @@ export default function AdminMembershipModalDefault() { - return null; + return null } diff --git a/src/app/admin/@authenticated/membership/manage/form.tsx b/src/app/admin/@authenticated/membership/manage/form.tsx index 973fcb7..2675c2d 100644 --- a/src/app/admin/@authenticated/membership/manage/form.tsx +++ b/src/app/admin/@authenticated/membership/manage/form.tsx @@ -1,6 +1,6 @@ "use client" -import { useForm } from "react-hook-form" +import { type SubmitHandler, useForm } from "react-hook-form" import { z } from "zod" import { zodResolver } from "@hookform/resolvers/zod" import { @@ -71,7 +71,7 @@ export function AdminMembershipCRUDForm({ ? {} : { ...previousValues, - features: previousValues?.features.join(","), + features: previousValues?.features?.join(",") || "", priceAmount: previousValues.priceAmount / 100, }, resolver: zodResolver(formSchema), @@ -89,7 +89,13 @@ export function AdminMembershipCRUDForm({ }, [membershipTemplateState, onSuccess, onSuccessFired]) return ( -
+ >, + ) as any + } + > {CRUDFormIntent.Edit && (
{modal}
{children}
- ); + ) } diff --git a/src/app/admin/@authenticated/membership/manage/page.tsx b/src/app/admin/@authenticated/membership/manage/page.tsx index 332103f..050d07b 100644 --- a/src/app/admin/@authenticated/membership/manage/page.tsx +++ b/src/app/admin/@authenticated/membership/manage/page.tsx @@ -5,12 +5,12 @@ import { TableHead, TableHeader, TableRow, -} from "@/components/ui/table"; -import { db } from "@/services/db"; -import { type MembershipTemplate } from "@prisma/client"; -import { Button } from "@/components/ui/button"; -import { Pencil1Icon } from "@radix-ui/react-icons"; -import Link from "next/link"; +} from "@/components/ui/table" +import { db } from "@/services/db" +import { type MembershipTemplate } from "@prisma/client" +import { Button } from "@/components/ui/button" +import { Pencil1Icon } from "@radix-ui/react-icons" +import Link from "next/link" async function getData() { return db.membershipTemplate.findMany({ @@ -19,11 +19,11 @@ async function getData() { id: "desc", }, ], - }); + }) } export default async function AdminMembershipPage() { - const membershipTemplates = await getData(); + const membershipTemplates = await getData() return ( <> @@ -69,7 +69,7 @@ export default async function AdminMembershipPage() { - ); + ) } function FormatPrice({ element }: any) { @@ -77,7 +77,7 @@ function FormatPrice({ element }: any) { currency: element.priceUnit, minimumFractionDigits: 2, style: "currency", - }); + }) - return {moneyFormatter.format(element.priceAmount / 100)}; + return {moneyFormatter.format(element.priceAmount / 100)} } diff --git a/src/app/admin/@authenticated/membership/pending-review/page.tsx b/src/app/admin/@authenticated/membership/pending-review/page.tsx index ee470ec..59486a8 100644 --- a/src/app/admin/@authenticated/membership/pending-review/page.tsx +++ b/src/app/admin/@authenticated/membership/pending-review/page.tsx @@ -1,4 +1,4 @@ -import { Paragraph } from "@/components/ui/typography"; +import { Paragraph } from "@/components/ui/typography" export default async function AdminMembershipPage() { return ( @@ -7,5 +7,5 @@ export default async function AdminMembershipPage() { Table memberships that need reviews - ); + ) } diff --git a/src/app/admin/@authenticated/page.tsx b/src/app/admin/@authenticated/page.tsx index f507d93..5ee0a9c 100644 --- a/src/app/admin/@authenticated/page.tsx +++ b/src/app/admin/@authenticated/page.tsx @@ -1,13 +1,13 @@ -import Link from "next/link"; +import Link from "next/link" -import { Placeholder } from "@/components/devtool/placeholder"; -import { Button } from "@/components/ui/button"; -import { Card, CardContent, CardHeader } from "@/components/ui/card"; -import { LinkLabel, Paragraph, SectionTitle } from "@/components/ui/typography"; -import { getServerAuthSession } from "@/server/auth"; +import { Placeholder } from "@/components/devtool/placeholder" +import { Button } from "@/components/ui/button" +import { Card, CardContent, CardHeader } from "@/components/ui/card" +import { LinkLabel, Paragraph, SectionTitle } from "@/components/ui/typography" +import { getServerAuthSession } from "@/server/auth" export default async function AdminHomePage() { - const session = await getServerAuthSession(); + const session = await getServerAuthSession() return ( <> @@ -127,5 +127,5 @@ export default async function AdminHomePage() { - ); + ) } diff --git a/src/app/admin/@authenticated/settings/advanced/page.tsx b/src/app/admin/@authenticated/settings/advanced/page.tsx index dcbdbf0..17af347 100644 --- a/src/app/admin/@authenticated/settings/advanced/page.tsx +++ b/src/app/admin/@authenticated/settings/advanced/page.tsx @@ -5,5 +5,5 @@ export default async function AdminUsersPage() {

Advanced

- ); + ) } diff --git a/src/app/admin/@authenticated/settings/branding/page.tsx b/src/app/admin/@authenticated/settings/branding/page.tsx index 9a90b39..f3a0299 100644 --- a/src/app/admin/@authenticated/settings/branding/page.tsx +++ b/src/app/admin/@authenticated/settings/branding/page.tsx @@ -5,5 +5,5 @@ export default async function AdminUsersPage() {

Branding

- ); + ) } diff --git a/src/app/admin/@authenticated/settings/layout.tsx b/src/app/admin/@authenticated/settings/layout.tsx index 970aafe..5d57f85 100644 --- a/src/app/admin/@authenticated/settings/layout.tsx +++ b/src/app/admin/@authenticated/settings/layout.tsx @@ -1,16 +1,16 @@ -import { find } from "lodash"; +import { find } from "lodash" -import { adminMenuTreeConfig } from "@/app/admin/const"; -import { LinkWithActive } from "@/components/molecules/linkWithActive"; +import { adminMenuTreeConfig } from "@/app/admin/const" +import { LinkWithActive } from "@/components/molecules/linkWithActive" interface AdminAuthenticatedLayoutInterface { - children: React.ReactNode; + children: React.ReactNode } export default async function AdminAuthenticatedLayout({ children, }: AdminAuthenticatedLayoutInterface) { - const settingsChildren = find(adminMenuTreeConfig, { id: "settings" })!; + const settingsChildren = find(adminMenuTreeConfig, { id: "settings" })! return ( <> @@ -28,5 +28,5 @@ export default async function AdminAuthenticatedLayout({
{children}
- ); + ) } diff --git a/src/app/admin/@authenticated/settings/page.tsx b/src/app/admin/@authenticated/settings/page.tsx index e02fe05..5e0daf2 100644 --- a/src/app/admin/@authenticated/settings/page.tsx +++ b/src/app/admin/@authenticated/settings/page.tsx @@ -1,4 +1,4 @@ -import { Button } from "@/components/ui/button"; +import { Button } from "@/components/ui/button" import { Card, CardContent, @@ -6,8 +6,8 @@ import { CardFooter, CardHeader, CardTitle, -} from "@/components/ui/card"; -import { Input } from "@/components/ui/input"; +} from "@/components/ui/card" +import { Input } from "@/components/ui/input" export default async function AdminPage() { return ( @@ -27,5 +27,5 @@ export default async function AdminPage() { - ); + ) } diff --git a/src/app/admin/@authenticated/settings/statute/page.tsx b/src/app/admin/@authenticated/settings/statute/page.tsx index 0f63cdb..d12fe7b 100644 --- a/src/app/admin/@authenticated/settings/statute/page.tsx +++ b/src/app/admin/@authenticated/settings/statute/page.tsx @@ -5,5 +5,5 @@ export default async function AdminUsersPage() {

Statute & Legal

- ); + ) } diff --git a/src/app/admin/@authenticated/users/page.tsx b/src/app/admin/@authenticated/users/page.tsx index 9da9ce1..fbb3ae6 100644 --- a/src/app/admin/@authenticated/users/page.tsx +++ b/src/app/admin/@authenticated/users/page.tsx @@ -5,5 +5,5 @@ export default async function AdminUsersPage() {

Users

- ); + ) } diff --git a/src/app/admin/@unauthenticated/components/logout.tsx b/src/app/admin/@unauthenticated/components/logout.tsx index ba9b7a6..cc233eb 100644 --- a/src/app/admin/@unauthenticated/components/logout.tsx +++ b/src/app/admin/@unauthenticated/components/logout.tsx @@ -1,6 +1,6 @@ -"use client"; +"use client" -import { signOut } from "next-auth/react"; +import { signOut } from "next-auth/react" export function Logout() { return ( @@ -12,5 +12,5 @@ export function Logout() { > Logout - ); + ) } diff --git a/src/app/admin/@unauthenticated/page.tsx b/src/app/admin/@unauthenticated/page.tsx index 13b0db4..d7e3988 100644 --- a/src/app/admin/@unauthenticated/page.tsx +++ b/src/app/admin/@unauthenticated/page.tsx @@ -1,11 +1,11 @@ -import { DiscordSignIn } from "@/app/admin/@unauthenticated/components/discordSignIn"; +import { DiscordSignIn } from "@/app/admin/@unauthenticated/components/discordSignIn" import { Card, CardDescription, CardFooter, CardHeader, CardTitle, -} from "@/components/ui/card"; +} from "@/components/ui/card" export default function AdminLogin() { return ( @@ -20,5 +20,5 @@ export default function AdminLogin() { - ); + ) } diff --git a/src/app/api/auth/[...nextauth]/route.ts b/src/app/api/auth/[...nextauth]/route.ts index e133977..0b9ff58 100644 --- a/src/app/api/auth/[...nextauth]/route.ts +++ b/src/app/api/auth/[...nextauth]/route.ts @@ -1,7 +1,7 @@ -import NextAuth from "next-auth"; +import NextAuth from "next-auth" -import { authOptions } from "@/server/auth"; +import { authOptions } from "@/server/auth" -const nextHandler = NextAuth(authOptions); +const nextHandler = NextAuth(authOptions) -export { nextHandler as GET, nextHandler as POST }; +export { nextHandler as GET, nextHandler as POST } diff --git a/src/app/documents/layout.tsx b/src/app/documents/layout.tsx index 58817fb..7cb23b0 100644 --- a/src/app/documents/layout.tsx +++ b/src/app/documents/layout.tsx @@ -1,12 +1,12 @@ -import Image from "next/image"; -import Link from "next/link"; +import Image from "next/image" +import Link from "next/link" -import logo from "@/images/logo-white.svg"; +import logo from "@/images/logo-white.svg" export default function LegalLayout({ children, }: { - children: React.ReactNode; + children: React.ReactNode }) { return ( <> @@ -28,5 +28,5 @@ export default function LegalLayout({
{children}
- ); + ) } diff --git a/src/app/documents/legal/privacy-policy/page.tsx b/src/app/documents/legal/privacy-policy/page.tsx index 9b8ff61..6630024 100644 --- a/src/app/documents/legal/privacy-policy/page.tsx +++ b/src/app/documents/legal/privacy-policy/page.tsx @@ -40,5 +40,5 @@ export default function PrivacyPolicyPage() { at nulla.

- ); + ) } diff --git a/src/app/documents/legal/statute/page.tsx b/src/app/documents/legal/statute/page.tsx index f3a0738..4721188 100644 --- a/src/app/documents/legal/statute/page.tsx +++ b/src/app/documents/legal/statute/page.tsx @@ -40,5 +40,5 @@ export default function StatutePage() { at nulla.

- ); + ) } diff --git a/src/app/documents/legal/terms-of-service/page.tsx b/src/app/documents/legal/terms-of-service/page.tsx index e8f3c1e..aab9e98 100644 --- a/src/app/documents/legal/terms-of-service/page.tsx +++ b/src/app/documents/legal/terms-of-service/page.tsx @@ -40,5 +40,5 @@ export default function TermsOfServicePage() { at nulla.

- ); + ) } diff --git a/src/app/layout.tsx b/src/app/layout.tsx index a858674..220b340 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -1,22 +1,22 @@ -import "@/styles/globals.css"; +import "@/styles/globals.css" -import { Inter } from "next/font/google"; +import { Inter } from "next/font/google" -import NextAuthProvider from "@/context/NextAuthProvider"; +import NextAuthProvider from "@/context/NextAuthProvider" const inter = Inter({ subsets: ["latin"], variable: "--font-sans", -}); +}) export const metadata = { description: "Generated by create-t3-app", icons: [{ rel: "icon", url: "/favicon.ico" }], title: "Create T3 App", -}; +} interface LayoutInterface { - children: React.ReactNode; + children: React.ReactNode } export default async function RootLayout({ children }: LayoutInterface) { @@ -26,5 +26,5 @@ export default async function RootLayout({ children }: LayoutInterface) { {children} - ); + ) } diff --git a/src/app/members/@authenticated/announcements/page.tsx b/src/app/members/@authenticated/announcements/page.tsx index bd9013c..2fe52b3 100644 --- a/src/app/members/@authenticated/announcements/page.tsx +++ b/src/app/members/@authenticated/announcements/page.tsx @@ -3,5 +3,5 @@ export default async function MembersAnnouncementsPage() {

Announcements

- ); + ) } diff --git a/src/app/members/@authenticated/membership/page.tsx b/src/app/members/@authenticated/membership/page.tsx index e5bd59a..02e9eeb 100644 --- a/src/app/members/@authenticated/membership/page.tsx +++ b/src/app/members/@authenticated/membership/page.tsx @@ -3,5 +3,5 @@ export default async function MembersMembershipPage() {

Membership

- ); + ) } diff --git a/src/app/members/@authenticated/page.tsx b/src/app/members/@authenticated/page.tsx index db29166..c02e78f 100644 --- a/src/app/members/@authenticated/page.tsx +++ b/src/app/members/@authenticated/page.tsx @@ -1,10 +1,10 @@ import { MembershipTemplateCard } from "@/components/molecules/membershipTemplateCard" import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card" import { getServerAuthSession } from "@/server/auth" -import { MembershipStatus, PricePeriod, PriceUnit } from "@prisma/client" +import { MembershipStatus } from "@prisma/client" import { db } from "@/services/db" -function getData(userId) { +function getData(userId: string | undefined) { return db.membership.findFirst({ where: { status: { @@ -20,7 +20,7 @@ function getData(userId) { export default async function MembershipPortalHomePage() { const session = await getServerAuthSession() - const membership = await getData(session?.user.id!) + const membership = await getData(session?.user.id) return ( <> diff --git a/src/app/members/@unauthenticated/page.tsx b/src/app/members/@unauthenticated/page.tsx index b70e7c4..a9979c4 100644 --- a/src/app/members/@unauthenticated/page.tsx +++ b/src/app/members/@unauthenticated/page.tsx @@ -1,24 +1,24 @@ -"use client"; +"use client" -import { zodResolver } from "@hookform/resolvers/zod"; -import { ExclamationTriangleIcon } from "@radix-ui/react-icons"; -import Link from "next/link"; -import { signIn } from "next-auth/react"; -import { useEffect, useState } from "react"; -import { useFormState } from "react-dom"; -import { useForm } from "react-hook-form"; -import { z } from "zod"; +import { zodResolver } from "@hookform/resolvers/zod" +import { ExclamationTriangleIcon } from "@radix-ui/react-icons" +import Link from "next/link" +import { signIn } from "next-auth/react" +import { useEffect, useState } from "react" +import { useFormState } from "react-dom" +import { useForm } from "react-hook-form" +import { z } from "zod" -import { validateUserEmail } from "@/app/actions/validateUserEmail"; -import { StatefulButton } from "@/components/molecules/statefulButton"; -import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert"; +import { validateUserEmail } from "@/app/actions/validateUserEmail" +import { StatefulButton } from "@/components/molecules/statefulButton" +import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert" import { Card, CardContent, CardDescription, CardHeader, CardTitle, -} from "@/components/ui/card"; +} from "@/components/ui/card" import { Form, FormControl, @@ -26,12 +26,12 @@ import { FormItem, FormLabel, FormMessage, -} from "@/components/ui/form"; -import { Input } from "@/components/ui/input"; +} from "@/components/ui/form" +import { Input } from "@/components/ui/input" const formSchema = z.object({ email: z.string().email(), -}); +}) export default function MembershipPortalLoginPage() { const form = useForm>({ @@ -39,33 +39,33 @@ export default function MembershipPortalLoginPage() { email: "", }, resolver: zodResolver(formSchema), - }); - const [working, setWorking] = useState(false); - const [requestedMagicLink, setRequestedMagicLink] = useState(false); + }) + const [working, setWorking] = useState(false) + const [requestedMagicLink, setRequestedMagicLink] = useState(false) const [validateUserEmailState, validateUserEmailAction] = useFormState( validateUserEmail, { checked: false, valid: false, }, - ); + ) useEffect(() => { const handler = async () => { if (!requestedMagicLink && validateUserEmailState.valid) { - setWorking(true); + setWorking(true) const reply = await signIn("email", { email: validateUserEmailState.email, redirect: false, - }); - console.log(reply); - setRequestedMagicLink(true); - setWorking(false); + }) + console.log(reply) + setRequestedMagicLink(true) + setWorking(false) } - }; + } - void handler(); - }, [requestedMagicLink, validateUserEmailState]); + void handler() + }, [requestedMagicLink, validateUserEmailState]) return (
@@ -149,5 +149,5 @@ export default function MembershipPortalLoginPage() {
- ); + ) } diff --git a/src/app/members/const.ts b/src/app/members/const.ts index 4f22712..727174e 100644 --- a/src/app/members/const.ts +++ b/src/app/members/const.ts @@ -14,4 +14,4 @@ export const membersMenuTreeConfig = [ label: "Announcements", url: "/members/announcements", }, -]; +] diff --git a/src/app/members/layout.tsx b/src/app/members/layout.tsx index 470b5c8..6e544c7 100644 --- a/src/app/members/layout.tsx +++ b/src/app/members/layout.tsx @@ -1,12 +1,12 @@ -import "@/styles/globals.css"; +import "@/styles/globals.css" -import Image from "next/image"; -import Link from "next/link"; -import React from "react"; +import Image from "next/image" +import Link from "next/link" +import React from "react" -import { membersMenuTreeConfig } from "@/app/members/const"; -import { LogoutButton } from "@/components/molecules/logoutButton"; -import { Button } from "@/components/ui/button"; +import { membersMenuTreeConfig } from "@/app/members/const" +import { LogoutButton } from "@/components/molecules/logoutButton" +import { Button } from "@/components/ui/button" import { DropdownMenu, DropdownMenuContent, @@ -14,32 +14,32 @@ import { DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger, -} from "@/components/ui/dropdown-menu"; -import { Sheet, SheetContent, SheetTrigger } from "@/components/ui/sheet"; -import logo from "@/images/logo.svg"; -import { usernameToInitials } from "@/lib/utils"; -import { getServerAuthSession } from "@/server/auth"; +} from "@/components/ui/dropdown-menu" +import { Sheet, SheetContent, SheetTrigger } from "@/components/ui/sheet" +import logo from "@/images/logo.svg" +import { usernameToInitials } from "@/lib/utils" +import { getServerAuthSession } from "@/server/auth" export const metadata = { description: "Generated by create-t3-app", icons: [{ rel: "icon", url: "/favicon.ico" }], title: "Create T3 App", -}; +} interface LayoutInterface { - authenticated: React.ReactNode; - unauthenticated: React.ReactNode; + authenticated: React.ReactNode + unauthenticated: React.ReactNode } export default async function RootLayout({ authenticated, unauthenticated, }: LayoutInterface) { - const session = await getServerAuthSession(); - const isLoggedIn = session !== null; + const session = await getServerAuthSession() + const isLoggedIn = session !== null if (!isLoggedIn) { - return unauthenticated; + return unauthenticated } else { return (
@@ -133,6 +133,6 @@ export default async function RootLayout({
- ); + ) } } diff --git a/src/app/signup/form.tsx b/src/app/signup/form.tsx index e8e3e53..93c88db 100644 --- a/src/app/signup/form.tsx +++ b/src/app/signup/form.tsx @@ -37,7 +37,6 @@ import { Input } from "@/components/ui/input" import checkmark from "@/images/checkmark.svg" import { type MembershipTemplate } from "@prisma/client" import { ScrollArea, ScrollBar } from "@/components/ui/scroll-area" -import { Debug } from "@/components/devtool/debug" const formSchema = z.object({ email: z.string().email(), @@ -284,38 +283,41 @@ export default function SignupForm({ membershipTemplates }: SignupFormProps) {
- {membershipTemplates.map((membershipTemplate) => ( -
{ - form.setValue( - "membershipTemplateId", - membershipTemplate.id, - { - shouldTouch: true, - shouldDirty: true, - }, - ) - }} - > - ( +
{ + form.setValue( + "membershipTemplateId", + membershipTemplate.id, + { + shouldTouch: true, + shouldDirty: true, + }, + ) }} - description={membershipTemplate.description} - /> -
- ))} + > + +
+ ), + )}
diff --git a/src/app/signup/layout.tsx b/src/app/signup/layout.tsx index fc947a2..0530dce 100644 --- a/src/app/signup/layout.tsx +++ b/src/app/signup/layout.tsx @@ -1,14 +1,14 @@ -import Image from "next/image"; -import Link from "next/link"; +import Image from "next/image" +import Link from "next/link" -import { buttonVariants } from "@/components/ui/button"; -import logoWhite from "@/images/logo-white.svg"; -import { cn } from "@/lib/utils"; +import { buttonVariants } from "@/components/ui/button" +import logoWhite from "@/images/logo-white.svg" +import { cn } from "@/lib/utils" export default function SignUpLayout({ children, }: { - children: React.ReactNode; + children: React.ReactNode }) { return (
@@ -56,5 +56,5 @@ export default function SignUpLayout({
{children}
- ); + ) } diff --git a/src/components/devtool/placeholder.tsx b/src/components/devtool/placeholder.tsx index f4315a3..faa4f28 100644 --- a/src/components/devtool/placeholder.tsx +++ b/src/components/devtool/placeholder.tsx @@ -1,12 +1,12 @@ -import Image from "next/image"; +import Image from "next/image" -import placeholder from "@/images/placeholder.svg"; +import placeholder from "@/images/placeholder.svg" interface PlaceholderInterface { - w: number; - h: number; + w: number + h: number } export function Placeholder({ w, h }: PlaceholderInterface) { - return {"placeholder"}; + return {"placeholder"} } diff --git a/src/components/molecules/linkWithActive.tsx b/src/components/molecules/linkWithActive.tsx index 264eedf..24a3fc1 100644 --- a/src/components/molecules/linkWithActive.tsx +++ b/src/components/molecules/linkWithActive.tsx @@ -1,25 +1,25 @@ -"use client"; +"use client" -import Link, { type LinkProps } from "next/link"; -import { usePathname } from "next/navigation"; -import { type ReactNode } from "react"; +import Link, { type LinkProps } from "next/link" +import { usePathname } from "next/navigation" +import { type ReactNode } from "react" interface LinkWithActiveProps extends LinkProps { - children: ReactNode; + children: ReactNode } export function LinkWithActive(props: LinkWithActiveProps) { - const currentPath = usePathname(); + const currentPath = usePathname() if (currentPath === props.href) return ( {props.children} - ); + ) else return ( {props.children} - ); + ) } diff --git a/src/components/molecules/logoutButton.tsx b/src/components/molecules/logoutButton.tsx index 1c84a1e..f843156 100644 --- a/src/components/molecules/logoutButton.tsx +++ b/src/components/molecules/logoutButton.tsx @@ -1,6 +1,6 @@ -"use client"; +"use client" -import { signOut } from "next-auth/react"; +import { signOut } from "next-auth/react" // TODO: Add confirm modal before triggering logout export function LogoutButton() { @@ -8,5 +8,5 @@ export function LogoutButton() { signOut()} className={"cursor-pointer"}> Logout - ); + ) } diff --git a/src/components/molecules/modal.tsx b/src/components/molecules/modal.tsx index 81ec6be..f72ec4a 100644 --- a/src/components/molecules/modal.tsx +++ b/src/components/molecules/modal.tsx @@ -1,27 +1,27 @@ -"use client"; +"use client" -import { useRouter } from "next/navigation"; +import { useRouter } from "next/navigation" import { Dialog, DialogContent, DialogDescription, DialogHeader, -} from "@/components/ui/dialog"; -import { useState } from "react"; +} from "@/components/ui/dialog" +import { useState } from "react" interface ModalProps { - children: React.ReactNode; - navigateOnClose?: boolean; + children: React.ReactNode + navigateOnClose?: boolean } export function Modal({ children, navigateOnClose = true }: ModalProps) { - const router = useRouter(); - const [open, setOpen] = useState(true); + const router = useRouter() + const [open, setOpen] = useState(true) const onOpenChange = () => { - if (navigateOnClose) router.back(); - else setOpen(false); - }; + if (navigateOnClose) router.back() + else setOpen(false) + } return ( <> @@ -33,5 +33,5 @@ export function Modal({ children, navigateOnClose = true }: ModalProps) { - ); + ) } diff --git a/src/components/molecules/statefulButton.tsx b/src/components/molecules/statefulButton.tsx index 469298f..9d5f01f 100644 --- a/src/components/molecules/statefulButton.tsx +++ b/src/components/molecules/statefulButton.tsx @@ -1,11 +1,11 @@ -"use client"; -import { noop } from "lodash"; -import { useFormStatus } from "react-dom"; +"use client" +import { noop } from "lodash" +import { useFormStatus } from "react-dom" -import { Button, type ButtonProps } from "@/components/ui/button"; +import { Button, type ButtonProps } from "@/components/ui/button" interface StatefulButtonProps extends ButtonProps { - loading?: boolean; + loading?: boolean } export function StatefulButton({ @@ -13,14 +13,14 @@ export function StatefulButton({ children, ...props }: StatefulButtonProps) { - const formStatus = useFormStatus(); - const isLoading = formStatus.pending || loading; + const formStatus = useFormStatus() + const isLoading = formStatus.pending || loading if (isLoading) return ( - ); - else return ; + ) + else return } diff --git a/src/components/ui/alert.tsx b/src/components/ui/alert.tsx index 1fc8db1..57b4c94 100644 --- a/src/components/ui/alert.tsx +++ b/src/components/ui/alert.tsx @@ -1,7 +1,7 @@ -import { cva, type VariantProps } from "class-variance-authority"; -import * as React from "react"; +import { cva, type VariantProps } from "class-variance-authority" +import * as React from "react" -import { cn } from "@/lib/utils"; +import { cn } from "@/lib/utils" const alertVariants = cva( "relative w-full rounded-md border px-4 py-3 text-sm [&>svg+div]:translate-y-[-3px] [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg]:text-foreground [&>svg~*]:pl-7", @@ -19,7 +19,7 @@ const alertVariants = cva( }, }, }, -); +) const Alert = React.forwardRef< HTMLDivElement, @@ -31,8 +31,8 @@ const Alert = React.forwardRef< className={cn(alertVariants({ variant }), className)} {...props} /> -)); -Alert.displayName = "Alert"; +)) +Alert.displayName = "Alert" const AlertTitle = React.forwardRef< HTMLParagraphElement, @@ -43,15 +43,15 @@ const AlertTitle = React.forwardRef< className={cn("text-md mb-1 font-bold", className)} {...props} /> -)); -AlertTitle.displayName = "AlertTitle"; +)) +AlertTitle.displayName = "AlertTitle" const AlertDescription = React.forwardRef< HTMLParagraphElement, React.HTMLAttributes >(({ className, ...props }, ref) => (
-)); -AlertDescription.displayName = "AlertDescription"; +)) +AlertDescription.displayName = "AlertDescription" -export { Alert, AlertDescription, AlertTitle }; +export { Alert, AlertDescription, AlertTitle } diff --git a/src/components/ui/badge.tsx b/src/components/ui/badge.tsx index 0c4beab..351a1ab 100644 --- a/src/components/ui/badge.tsx +++ b/src/components/ui/badge.tsx @@ -1,7 +1,7 @@ -import { cva, type VariantProps } from "class-variance-authority"; -import * as React from "react"; +import { cva, type VariantProps } from "class-variance-authority" +import * as React from "react" -import { cn } from "@/lib/utils"; +import { cn } from "@/lib/utils" const badgeVariants = cva( "inline-flex items-center rounded-md border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2", @@ -21,7 +21,7 @@ const badgeVariants = cva( }, }, }, -); +) export interface BadgeProps extends React.HTMLAttributes, @@ -30,7 +30,7 @@ export interface BadgeProps function Badge({ className, variant, ...props }: BadgeProps) { return (
- ); + ) } -export { Badge, badgeVariants }; +export { Badge, badgeVariants } diff --git a/src/components/ui/card.tsx b/src/components/ui/card.tsx index 4388f19..4a8cce0 100644 --- a/src/components/ui/card.tsx +++ b/src/components/ui/card.tsx @@ -1,6 +1,6 @@ -import * as React from "react"; +import * as React from "react" -import { cn } from "@/lib/utils"; +import { cn } from "@/lib/utils" const Card = React.forwardRef< HTMLDivElement, @@ -11,8 +11,8 @@ const Card = React.forwardRef< className={cn("rounded-md border bg-card text-card-foreground", className)} {...props} /> -)); -Card.displayName = "Card"; +)) +Card.displayName = "Card" const CardHeader = React.forwardRef< HTMLDivElement, @@ -23,8 +23,8 @@ const CardHeader = React.forwardRef< className={cn("flex flex-col space-y-1.5 p-6", className)} {...props} /> -)); -CardHeader.displayName = "CardHeader"; +)) +CardHeader.displayName = "CardHeader" const CardTitle = React.forwardRef< HTMLParagraphElement, @@ -35,8 +35,8 @@ const CardTitle = React.forwardRef< className={cn("font-semibold leading-none tracking-tight", className)} {...props} /> -)); -CardTitle.displayName = "CardTitle"; +)) +CardTitle.displayName = "CardTitle" const CardDescription = React.forwardRef< HTMLParagraphElement, @@ -47,16 +47,16 @@ const CardDescription = React.forwardRef< className={cn("text-sm text-muted-foreground", className)} {...props} /> -)); -CardDescription.displayName = "CardDescription"; +)) +CardDescription.displayName = "CardDescription" const CardContent = React.forwardRef< HTMLDivElement, React.HTMLAttributes >(({ className, ...props }, ref) => (
-)); -CardContent.displayName = "CardContent"; +)) +CardContent.displayName = "CardContent" const CardFooter = React.forwardRef< HTMLDivElement, @@ -67,14 +67,7 @@ const CardFooter = React.forwardRef< className={cn("flex items-center p-6 pt-0", className)} {...props} /> -)); -CardFooter.displayName = "CardFooter"; +)) +CardFooter.displayName = "CardFooter" -export { - Card, - CardContent, - CardDescription, - CardFooter, - CardHeader, - CardTitle, -}; +export { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } diff --git a/src/components/ui/checkbox.tsx b/src/components/ui/checkbox.tsx index 8b96701..3876535 100644 --- a/src/components/ui/checkbox.tsx +++ b/src/components/ui/checkbox.tsx @@ -1,10 +1,10 @@ -"use client"; +"use client" -import * as CheckboxPrimitive from "@radix-ui/react-checkbox"; -import { CheckIcon } from "@radix-ui/react-icons"; -import * as React from "react"; +import * as CheckboxPrimitive from "@radix-ui/react-checkbox" +import { CheckIcon } from "@radix-ui/react-icons" +import * as React from "react" -import { cn } from "@/lib/utils"; +import { cn } from "@/lib/utils" const Checkbox = React.forwardRef< React.ElementRef, @@ -24,7 +24,7 @@ const Checkbox = React.forwardRef< -)); -Checkbox.displayName = CheckboxPrimitive.Root.displayName; +)) +Checkbox.displayName = CheckboxPrimitive.Root.displayName -export { Checkbox }; +export { Checkbox } diff --git a/src/components/ui/dialog.tsx b/src/components/ui/dialog.tsx index 3db2a7d..c6a6a12 100644 --- a/src/components/ui/dialog.tsx +++ b/src/components/ui/dialog.tsx @@ -1,18 +1,18 @@ -"use client"; +"use client" -import * as React from "react"; -import * as DialogPrimitive from "@radix-ui/react-dialog"; -import { Cross2Icon } from "@radix-ui/react-icons"; +import * as React from "react" +import * as DialogPrimitive from "@radix-ui/react-dialog" +import { Cross2Icon } from "@radix-ui/react-icons" -import { cn } from "@/lib/utils"; +import { cn } from "@/lib/utils" -const Dialog = DialogPrimitive.Root; +const Dialog = DialogPrimitive.Root -const DialogTrigger = DialogPrimitive.Trigger; +const DialogTrigger = DialogPrimitive.Trigger -const DialogPortal = DialogPrimitive.Portal; +const DialogPortal = DialogPrimitive.Portal -const DialogClose = DialogPrimitive.Close; +const DialogClose = DialogPrimitive.Close const DialogOverlay = React.forwardRef< React.ElementRef, @@ -26,8 +26,8 @@ const DialogOverlay = React.forwardRef< )} {...props} /> -)); -DialogOverlay.displayName = DialogPrimitive.Overlay.displayName; +)) +DialogOverlay.displayName = DialogPrimitive.Overlay.displayName const DialogContent = React.forwardRef< React.ElementRef, @@ -50,8 +50,8 @@ const DialogContent = React.forwardRef< -)); -DialogContent.displayName = DialogPrimitive.Content.displayName; +)) +DialogContent.displayName = DialogPrimitive.Content.displayName const DialogHeader = ({ className, @@ -64,8 +64,8 @@ const DialogHeader = ({ )} {...props} /> -); -DialogHeader.displayName = "DialogHeader"; +) +DialogHeader.displayName = "DialogHeader" const DialogFooter = ({ className, @@ -78,8 +78,8 @@ const DialogFooter = ({ )} {...props} /> -); -DialogFooter.displayName = "DialogFooter"; +) +DialogFooter.displayName = "DialogFooter" const DialogTitle = React.forwardRef< React.ElementRef, @@ -93,8 +93,8 @@ const DialogTitle = React.forwardRef< )} {...props} /> -)); -DialogTitle.displayName = DialogPrimitive.Title.displayName; +)) +DialogTitle.displayName = DialogPrimitive.Title.displayName const DialogDescription = React.forwardRef< React.ElementRef, @@ -105,8 +105,8 @@ const DialogDescription = React.forwardRef< className={cn("text-sm text-muted-foreground", className)} {...props} /> -)); -DialogDescription.displayName = DialogPrimitive.Description.displayName; +)) +DialogDescription.displayName = DialogPrimitive.Description.displayName export { Dialog, @@ -119,4 +119,4 @@ export { DialogFooter, DialogTitle, DialogDescription, -}; +} diff --git a/src/components/ui/dropdown-menu.tsx b/src/components/ui/dropdown-menu.tsx index c5cee1b..5a74dcd 100644 --- a/src/components/ui/dropdown-menu.tsx +++ b/src/components/ui/dropdown-menu.tsx @@ -1,31 +1,31 @@ -"use client"; +"use client" -import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu"; +import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu" import { CheckIcon, ChevronRightIcon, DotFilledIcon, -} from "@radix-ui/react-icons"; -import * as React from "react"; +} from "@radix-ui/react-icons" +import * as React from "react" -import { cn } from "@/lib/utils"; +import { cn } from "@/lib/utils" -const DropdownMenu = DropdownMenuPrimitive.Root; +const DropdownMenu = DropdownMenuPrimitive.Root -const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger; +const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger -const DropdownMenuGroup = DropdownMenuPrimitive.Group; +const DropdownMenuGroup = DropdownMenuPrimitive.Group -const DropdownMenuPortal = DropdownMenuPrimitive.Portal; +const DropdownMenuPortal = DropdownMenuPrimitive.Portal -const DropdownMenuSub = DropdownMenuPrimitive.Sub; +const DropdownMenuSub = DropdownMenuPrimitive.Sub -const DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup; +const DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup const DropdownMenuSubTrigger = React.forwardRef< React.ElementRef, React.ComponentPropsWithoutRef & { - inset?: boolean; + inset?: boolean } >(({ className, inset, children, ...props }, ref) => ( -)); +)) DropdownMenuSubTrigger.displayName = - DropdownMenuPrimitive.SubTrigger.displayName; + DropdownMenuPrimitive.SubTrigger.displayName const DropdownMenuSubContent = React.forwardRef< React.ElementRef, @@ -56,9 +56,9 @@ const DropdownMenuSubContent = React.forwardRef< )} {...props} /> -)); +)) DropdownMenuSubContent.displayName = - DropdownMenuPrimitive.SubContent.displayName; + DropdownMenuPrimitive.SubContent.displayName const DropdownMenuContent = React.forwardRef< React.ElementRef, @@ -76,13 +76,13 @@ const DropdownMenuContent = React.forwardRef< {...props} /> -)); -DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName; +)) +DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName const DropdownMenuItem = React.forwardRef< React.ElementRef, React.ComponentPropsWithoutRef & { - inset?: boolean; + inset?: boolean } >(({ className, inset, ...props }, ref) => ( -)); -DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName; +)) +DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName const DropdownMenuCheckboxItem = React.forwardRef< React.ElementRef, @@ -117,9 +117,9 @@ const DropdownMenuCheckboxItem = React.forwardRef< {children} -)); +)) DropdownMenuCheckboxItem.displayName = - DropdownMenuPrimitive.CheckboxItem.displayName; + DropdownMenuPrimitive.CheckboxItem.displayName const DropdownMenuRadioItem = React.forwardRef< React.ElementRef, @@ -140,13 +140,13 @@ const DropdownMenuRadioItem = React.forwardRef< {children} -)); -DropdownMenuRadioItem.displayName = DropdownMenuPrimitive.RadioItem.displayName; +)) +DropdownMenuRadioItem.displayName = DropdownMenuPrimitive.RadioItem.displayName const DropdownMenuLabel = React.forwardRef< React.ElementRef, React.ComponentPropsWithoutRef & { - inset?: boolean; + inset?: boolean } >(({ className, inset, ...props }, ref) => ( -)); -DropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName; +)) +DropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName const DropdownMenuSeparator = React.forwardRef< React.ElementRef, @@ -170,8 +170,8 @@ const DropdownMenuSeparator = React.forwardRef< className={cn("-mx-1 my-1 h-px bg-muted", className)} {...props} /> -)); -DropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName; +)) +DropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName const DropdownMenuShortcut = ({ className, @@ -182,9 +182,9 @@ const DropdownMenuShortcut = ({ className={cn("ml-auto text-xs tracking-widest opacity-60", className)} {...props} /> - ); -}; -DropdownMenuShortcut.displayName = "DropdownMenuShortcut"; + ) +} +DropdownMenuShortcut.displayName = "DropdownMenuShortcut" export { DropdownMenu, @@ -202,4 +202,4 @@ export { DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, -}; +} diff --git a/src/components/ui/form.tsx b/src/components/ui/form.tsx index d70a960..c5cf94d 100644 --- a/src/components/ui/form.tsx +++ b/src/components/ui/form.tsx @@ -1,6 +1,6 @@ -import type * as LabelPrimitive from "@radix-ui/react-label"; -import { Slot } from "@radix-ui/react-slot"; -import * as React from "react"; +import type * as LabelPrimitive from "@radix-ui/react-label" +import { Slot } from "@radix-ui/react-slot" +import * as React from "react" import { Controller, type ControllerProps, @@ -8,23 +8,23 @@ import { type FieldValues, FormProvider, useFormContext, -} from "react-hook-form"; +} from "react-hook-form" -import { Label } from "@/components/ui/label"; -import { cn } from "@/lib/utils"; +import { Label } from "@/components/ui/label" +import { cn } from "@/lib/utils" -const Form = FormProvider; +const Form = FormProvider type FormFieldContextValue< TFieldValues extends FieldValues = FieldValues, TName extends FieldPath = FieldPath, > = { - name: TName; -}; + name: TName +} const FormFieldContext = React.createContext( {} as FormFieldContextValue, -); +) const FormField = < TFieldValues extends FieldValues = FieldValues, @@ -36,21 +36,21 @@ const FormField = < - ); -}; + ) +} const useFormField = () => { - const fieldContext = React.useContext(FormFieldContext); - const itemContext = React.useContext(FormItemContext); - const { getFieldState, formState } = useFormContext(); + const fieldContext = React.useContext(FormFieldContext) + const itemContext = React.useContext(FormItemContext) + const { getFieldState, formState } = useFormContext() - const fieldState = getFieldState(fieldContext.name, formState); + const fieldState = getFieldState(fieldContext.name, formState) if (!fieldContext) { - throw new Error("useFormField should be used within "); + throw new Error("useFormField should be used within ") } - const { id } = itemContext; + const { id } = itemContext return { formDescriptionId: `${id}-form-item-description`, @@ -59,36 +59,36 @@ const useFormField = () => { id, name: fieldContext.name, ...fieldState, - }; -}; + } +} type FormItemContextValue = { - id: string; -}; + id: string +} const FormItemContext = React.createContext( {} as FormItemContextValue, -); +) const FormItem = React.forwardRef< HTMLDivElement, React.HTMLAttributes >(({ className, ...props }, ref) => { - const id = React.useId(); + const id = React.useId() return (
- ); -}); -FormItem.displayName = "FormItem"; + ) +}) +FormItem.displayName = "FormItem" const FormLabel = React.forwardRef< React.ElementRef, React.ComponentPropsWithoutRef >(({ className, ...props }, ref) => { - const { error, formItemId } = useFormField(); + const { error, formItemId } = useFormField() return (
-)); -Table.displayName = "Table"; +)) +Table.displayName = "Table" const TableHeader = React.forwardRef< HTMLTableSectionElement, React.HTMLAttributes >(({ className, ...props }, ref) => ( -)); -TableHeader.displayName = "TableHeader"; +)) +TableHeader.displayName = "TableHeader" const TableBody = React.forwardRef< HTMLTableSectionElement, @@ -33,8 +33,8 @@ const TableBody = React.forwardRef< className={cn("[&_tr:last-child]:border-0", className)} {...props} /> -)); -TableBody.displayName = "TableBody"; +)) +TableBody.displayName = "TableBody" const TableFooter = React.forwardRef< HTMLTableSectionElement, @@ -48,8 +48,8 @@ const TableFooter = React.forwardRef< )} {...props} /> -)); -TableFooter.displayName = "TableFooter"; +)) +TableFooter.displayName = "TableFooter" const TableRow = React.forwardRef< HTMLTableRowElement, @@ -63,8 +63,8 @@ const TableRow = React.forwardRef< )} {...props} /> -)); -TableRow.displayName = "TableRow"; +)) +TableRow.displayName = "TableRow" const TableHead = React.forwardRef< HTMLTableCellElement, @@ -78,8 +78,8 @@ const TableHead = React.forwardRef< )} {...props} /> -)); -TableHead.displayName = "TableHead"; +)) +TableHead.displayName = "TableHead" const TableCell = React.forwardRef< HTMLTableCellElement, @@ -93,8 +93,8 @@ const TableCell = React.forwardRef< )} {...props} /> -)); -TableCell.displayName = "TableCell"; +)) +TableCell.displayName = "TableCell" const TableCaption = React.forwardRef< HTMLTableCaptionElement, @@ -105,8 +105,8 @@ const TableCaption = React.forwardRef< className={cn("mt-4 text-sm text-muted-foreground", className)} {...props} /> -)); -TableCaption.displayName = "TableCaption"; +)) +TableCaption.displayName = "TableCaption" export { Table, @@ -117,4 +117,4 @@ export { TableRow, TableCell, TableCaption, -}; +} diff --git a/src/components/ui/textarea.tsx b/src/components/ui/textarea.tsx index a066282..567ac65 100644 --- a/src/components/ui/textarea.tsx +++ b/src/components/ui/textarea.tsx @@ -1,8 +1,8 @@ -import * as React from "react"; +import * as React from "react" -import { cn } from "@/lib/utils"; +import { cn } from "@/lib/utils" -export type TextareaProps = React.TextareaHTMLAttributes; +export type TextareaProps = React.TextareaHTMLAttributes const Textarea = React.forwardRef( ({ className, ...props }, ref) => { @@ -15,9 +15,9 @@ const Textarea = React.forwardRef( ref={ref} {...props} /> - ); + ) }, -); -Textarea.displayName = "Textarea"; +) +Textarea.displayName = "Textarea" -export { Textarea }; +export { Textarea } diff --git a/src/components/ui/toast.tsx b/src/components/ui/toast.tsx index 871eaf6..02b0494 100644 --- a/src/components/ui/toast.tsx +++ b/src/components/ui/toast.tsx @@ -1,13 +1,13 @@ -"use client"; +"use client" -import * as React from "react"; -import { Cross2Icon } from "@radix-ui/react-icons"; -import * as ToastPrimitives from "@radix-ui/react-toast"; -import { cva, type VariantProps } from "class-variance-authority"; +import * as React from "react" +import { Cross2Icon } from "@radix-ui/react-icons" +import * as ToastPrimitives from "@radix-ui/react-toast" +import { cva, type VariantProps } from "class-variance-authority" -import { cn } from "@/lib/utils"; +import { cn } from "@/lib/utils" -const ToastProvider = ToastPrimitives.Provider; +const ToastProvider = ToastPrimitives.Provider const ToastViewport = React.forwardRef< React.ElementRef, @@ -21,8 +21,8 @@ const ToastViewport = React.forwardRef< )} {...props} /> -)); -ToastViewport.displayName = ToastPrimitives.Viewport.displayName; +)) +ToastViewport.displayName = ToastPrimitives.Viewport.displayName const toastVariants = cva( "group pointer-events-auto relative flex w-full items-center justify-between space-x-2 overflow-hidden rounded-md border p-4 pr-6 shadow-lg transition-all data-[swipe=cancel]:translate-x-0 data-[swipe=end]:translate-x-[var(--radix-toast-swipe-end-x)] data-[swipe=move]:translate-x-[var(--radix-toast-swipe-move-x)] data-[swipe=move]:transition-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[swipe=end]:animate-out data-[state=closed]:fade-out-80 data-[state=closed]:slide-out-to-right-full data-[state=open]:slide-in-from-top-full data-[state=open]:sm:slide-in-from-bottom-full", @@ -40,7 +40,7 @@ const toastVariants = cva( variant: "default", }, }, -); +) const Toast = React.forwardRef< React.ElementRef, @@ -53,9 +53,9 @@ const Toast = React.forwardRef< className={cn(toastVariants({ variant }), className)} {...props} /> - ); -}); -Toast.displayName = ToastPrimitives.Root.displayName; + ) +}) +Toast.displayName = ToastPrimitives.Root.displayName const ToastAction = React.forwardRef< React.ElementRef, @@ -69,8 +69,8 @@ const ToastAction = React.forwardRef< )} {...props} /> -)); -ToastAction.displayName = ToastPrimitives.Action.displayName; +)) +ToastAction.displayName = ToastPrimitives.Action.displayName const ToastClose = React.forwardRef< React.ElementRef, @@ -87,8 +87,8 @@ const ToastClose = React.forwardRef< > -)); -ToastClose.displayName = ToastPrimitives.Close.displayName; +)) +ToastClose.displayName = ToastPrimitives.Close.displayName const ToastTitle = React.forwardRef< React.ElementRef, @@ -99,8 +99,8 @@ const ToastTitle = React.forwardRef< className={cn("text-sm font-semibold [&+div]:text-xs", className)} {...props} /> -)); -ToastTitle.displayName = ToastPrimitives.Title.displayName; +)) +ToastTitle.displayName = ToastPrimitives.Title.displayName const ToastDescription = React.forwardRef< React.ElementRef, @@ -111,12 +111,12 @@ const ToastDescription = React.forwardRef< className={cn("text-sm opacity-90", className)} {...props} /> -)); -ToastDescription.displayName = ToastPrimitives.Description.displayName; +)) +ToastDescription.displayName = ToastPrimitives.Description.displayName -type ToastProps = React.ComponentPropsWithoutRef; +type ToastProps = React.ComponentPropsWithoutRef -type ToastActionElement = React.ReactElement; +type ToastActionElement = React.ReactElement export { type ToastProps, @@ -128,4 +128,4 @@ export { ToastDescription, ToastClose, ToastAction, -}; +} diff --git a/src/components/ui/toaster.tsx b/src/components/ui/toaster.tsx index 7d82ed5..e223385 100644 --- a/src/components/ui/toaster.tsx +++ b/src/components/ui/toaster.tsx @@ -1,4 +1,4 @@ -"use client"; +"use client" import { Toast, @@ -7,11 +7,11 @@ import { ToastProvider, ToastTitle, ToastViewport, -} from "@/components/ui/toast"; -import { useToast } from "@/components/ui/use-toast"; +} from "@/components/ui/toast" +import { useToast } from "@/components/ui/use-toast" export function Toaster() { - const { toasts } = useToast(); + const { toasts } = useToast() return ( @@ -27,9 +27,9 @@ export function Toaster() { {action} - ); + ) })} - ); + ) } diff --git a/src/components/ui/typography.tsx b/src/components/ui/typography.tsx index 8113530..094262e 100644 --- a/src/components/ui/typography.tsx +++ b/src/components/ui/typography.tsx @@ -1,16 +1,16 @@ interface GenericChildrenInterface { - children: React.ReactNode; - props?: React.PropsWithChildren; + children: React.ReactNode + props?: React.PropsWithChildren } export function Paragraph({ children }: GenericChildrenInterface) { - return

{children}

; + return

{children}

} interface SectionTitleInterface { - title: string; - description: string; - size?: SizeEnum; + title: string + description: string + size?: SizeEnum } enum SizeEnum { @@ -33,7 +33,7 @@ export function SectionTitle({ )} {description}
- ); + ) } export function LinkLabel({ children }: GenericChildrenInterface) { @@ -43,5 +43,5 @@ export function LinkLabel({ children }: GenericChildrenInterface) { > {children} - ); + ) } diff --git a/src/components/ui/use-toast.ts b/src/components/ui/use-toast.ts index 6555e79..d5068e3 100644 --- a/src/components/ui/use-toast.ts +++ b/src/components/ui/use-toast.ts @@ -1,75 +1,75 @@ -"use client"; +"use client" // Inspired by react-hot-toast library -import * as React from "react"; +import * as React from "react" -import type { ToastActionElement, ToastProps } from "@/components/ui/toast"; +import type { ToastActionElement, ToastProps } from "@/components/ui/toast" -const TOAST_LIMIT = 1; -const TOAST_REMOVE_DELAY = 1000000; +const TOAST_LIMIT = 1 +const TOAST_REMOVE_DELAY = 1000000 type ToasterToast = ToastProps & { - id: string; - title?: React.ReactNode; - description?: React.ReactNode; - action?: ToastActionElement; -}; + id: string + title?: React.ReactNode + description?: React.ReactNode + action?: ToastActionElement +} const actionTypes = { ADD_TOAST: "ADD_TOAST", UPDATE_TOAST: "UPDATE_TOAST", DISMISS_TOAST: "DISMISS_TOAST", REMOVE_TOAST: "REMOVE_TOAST", -} as const; +} as const -let count = 0; +let count = 0 function genId() { - count = (count + 1) % Number.MAX_SAFE_INTEGER; - return count.toString(); + count = (count + 1) % Number.MAX_SAFE_INTEGER + return count.toString() } -type ActionType = typeof actionTypes; +type ActionType = typeof actionTypes type Action = | { - type: ActionType["ADD_TOAST"]; - toast: ToasterToast; + type: ActionType["ADD_TOAST"] + toast: ToasterToast } | { - type: ActionType["UPDATE_TOAST"]; - toast: Partial; + type: ActionType["UPDATE_TOAST"] + toast: Partial } | { - type: ActionType["DISMISS_TOAST"]; - toastId?: ToasterToast["id"]; + type: ActionType["DISMISS_TOAST"] + toastId?: ToasterToast["id"] } | { - type: ActionType["REMOVE_TOAST"]; - toastId?: ToasterToast["id"]; - }; + type: ActionType["REMOVE_TOAST"] + toastId?: ToasterToast["id"] + } interface State { - toasts: ToasterToast[]; + toasts: ToasterToast[] } -const toastTimeouts = new Map>(); +const toastTimeouts = new Map>() const addToRemoveQueue = (toastId: string) => { if (toastTimeouts.has(toastId)) { - return; + return } const timeout = setTimeout(() => { - toastTimeouts.delete(toastId); + toastTimeouts.delete(toastId) dispatch({ type: "REMOVE_TOAST", toastId: toastId, - }); - }, TOAST_REMOVE_DELAY); + }) + }, TOAST_REMOVE_DELAY) - toastTimeouts.set(toastId, timeout); -}; + toastTimeouts.set(toastId, timeout) +} export const reducer = (state: State, action: Action): State => { switch (action.type) { @@ -77,7 +77,7 @@ export const reducer = (state: State, action: Action): State => { return { ...state, toasts: [action.toast, ...state.toasts].slice(0, TOAST_LIMIT), - }; + } case "UPDATE_TOAST": return { @@ -85,19 +85,19 @@ export const reducer = (state: State, action: Action): State => { toasts: state.toasts.map((t) => t.id === action.toast.id ? { ...t, ...action.toast } : t, ), - }; + } case "DISMISS_TOAST": { - const { toastId } = action; + const { toastId } = action // ! Side effects ! - This could be extracted into a dismissToast() action, // but I'll keep it here for simplicity if (toastId) { - addToRemoveQueue(toastId); + addToRemoveQueue(toastId) } else { state.toasts.forEach((toast) => { - addToRemoveQueue(toast.id); - }); + addToRemoveQueue(toast.id) + }) } return { @@ -110,44 +110,44 @@ export const reducer = (state: State, action: Action): State => { } : t, ), - }; + } } case "REMOVE_TOAST": if (action.toastId === undefined) { return { ...state, toasts: [], - }; + } } return { ...state, toasts: state.toasts.filter((t) => t.id !== action.toastId), - }; + } } -}; +} -const listeners: Array<(state: State) => void> = []; +const listeners: Array<(state: State) => void> = [] -let memoryState: State = { toasts: [] }; +let memoryState: State = { toasts: [] } function dispatch(action: Action) { - memoryState = reducer(memoryState, action); + memoryState = reducer(memoryState, action) listeners.forEach((listener) => { - listener(memoryState); - }); + listener(memoryState) + }) } -type Toast = Omit; +type Toast = Omit function toast({ ...props }: Toast) { - const id = genId(); + const id = genId() const update = (props: ToasterToast) => dispatch({ type: "UPDATE_TOAST", toast: { ...props, id }, - }); - const dismiss = () => dispatch({ type: "DISMISS_TOAST", toastId: id }); + }) + const dismiss = () => dispatch({ type: "DISMISS_TOAST", toastId: id }) dispatch({ type: "ADD_TOAST", @@ -156,36 +156,36 @@ function toast({ ...props }: Toast) { id, open: true, onOpenChange: (open) => { - if (!open) dismiss(); + if (!open) dismiss() }, }, - }); + }) return { id: id, dismiss, update, - }; + } } function useToast() { - const [state, setState] = React.useState(memoryState); + const [state, setState] = React.useState(memoryState) React.useEffect(() => { - listeners.push(setState); + listeners.push(setState) return () => { - const index = listeners.indexOf(setState); + const index = listeners.indexOf(setState) if (index > -1) { - listeners.splice(index, 1); + listeners.splice(index, 1) } - }; - }, [state]); + } + }, [state]) return { ...state, toast, dismiss: (toastId?: string) => dispatch({ type: "DISMISS_TOAST", toastId }), - }; + } } -export { useToast, toast }; +export { useToast, toast } diff --git a/src/context/NextAuthProvider.tsx b/src/context/NextAuthProvider.tsx index b8176c8..43e58ef 100644 --- a/src/context/NextAuthProvider.tsx +++ b/src/context/NextAuthProvider.tsx @@ -1,12 +1,12 @@ -"use client"; +"use client" -import { SessionProvider } from "next-auth/react"; -import { type ReactNode } from "react"; +import { SessionProvider } from "next-auth/react" +import { type ReactNode } from "react" export default function NextAuthProvider({ children, }: { - children: ReactNode; + children: ReactNode }) { - return {children}; + return {children} } diff --git a/src/emails/index.tsx b/src/emails/index.tsx index 3630fce..cb4de17 100644 --- a/src/emails/index.tsx +++ b/src/emails/index.tsx @@ -10,13 +10,13 @@ import { Preview, Section, Text, -} from "@react-email/components"; -import * as React from "react"; +} from "@react-email/components" +import * as React from "react" const baseUrl = process.env.VERCEL_URL ? `https://${process.env.VERCEL_URL}` - : ""; -console.log(process.env); + : "" +console.log(process.env) export default function Email() { return ( <> @@ -60,14 +60,14 @@ export default function Email() { - ); + ) } const main = { backgroundColor: "#ffffff", fontFamily: '-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif', -}; +} const container = { backgroundImage: 'url("/assets/raycast-bg.png")', @@ -75,34 +75,34 @@ const container = { backgroundRepeat: "no-repeat, no-repeat", margin: "0 auto", padding: "20px 25px 48px", -}; +} const heading = { fontSize: "28px", fontWeight: "bold", marginTop: "48px", -}; +} const body = { margin: "24px 0", -}; +} const paragraph = { fontSize: "16px", lineHeight: "26px", -}; +} const link = { color: "#FF6363", -}; +} const hr = { borderColor: "#dddddd", marginTop: "48px", -}; +} const footer = { color: "#8898aa", fontSize: "12px", marginLeft: "4px", -}; +} diff --git a/src/env.js b/src/env.js index 8e2afad..d33f651 100644 --- a/src/env.js +++ b/src/env.js @@ -1,5 +1,5 @@ -import { createEnv } from "@t3-oss/env-nextjs"; -import { z } from "zod"; +import { createEnv } from "@t3-oss/env-nextjs" +import { z } from "zod" export const env = createEnv({ /** @@ -8,7 +8,7 @@ export const env = createEnv({ * `NEXT_PUBLIC_`. */ client: { - NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY: z.string(), + NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY: z.string().optional(), }, /** @@ -52,17 +52,17 @@ export const env = createEnv({ (str) => !str.includes("YOUR_MYSQL_URL_HERE"), "You forgot to change the default URL", ), - DISCORD_CLIENT_ID: z.string(), - DISCORD_CLIENT_SECRET: z.string(), - EMAIL_FROM: z.string().email(), - EMAIL_SERVER_HOST: z.string(), - EMAIL_SERVER_PASSWORD: z.string(), + DISCORD_CLIENT_ID: z.string().optional(), + DISCORD_CLIENT_SECRET: z.string().optional(), - EMAIL_SERVER_PORT: z.number(), - EMAIL_SERVER_USER: z.string(), + EMAIL_FROM: z.string().email().optional(), + EMAIL_SERVER_HOST: z.string().optional(), + EMAIL_SERVER_PASSWORD: z.string().optional(), + EMAIL_SERVER_PORT: z.number().optional(), + EMAIL_SERVER_USER: z.string().optional(), - MARKETING_NAME: z.string(), - MARKETING_WEBSITE_URL: z.string(), + MARKETING_NAME: z.string().optional(), + MARKETING_WEBSITE_URL: z.string().optional(), NEXTAUTH_SECRET: process.env.NODE_ENV === "production" @@ -78,7 +78,7 @@ export const env = createEnv({ NODE_ENV: z .enum(["development", "test", "production"]) .default("development"), - STRIPE_PRIVATE_KEY: z.string(), + STRIPE_PRIVATE_KEY: z.string().optional(), }, /** @@ -86,4 +86,4 @@ export const env = createEnv({ * useful for Docker builds. */ skipValidation: !!process.env.SKIP_ENV_VALIDATION, -}); +}) diff --git a/src/lib/envs.ts b/src/lib/envs.ts index 25e7a13..48d535c 100644 --- a/src/lib/envs.ts +++ b/src/lib/envs.ts @@ -1,2 +1,2 @@ export const inDevEnvironment = - !!process && process.env.NODE_ENV === "development"; + !!process && process.env.NODE_ENV === "development" diff --git a/src/lib/permissions.ts b/src/lib/permissions.ts index b2a6d69..291fb2f 100644 --- a/src/lib/permissions.ts +++ b/src/lib/permissions.ts @@ -1,8 +1,8 @@ // Receives a required role and a session and return a boolean indicating if the provided session matches the required role -import { type UserRole } from "@prisma/client"; -import { isNil } from "lodash"; +import { type UserRole } from "@prisma/client" +import { isNil } from "lodash" export function hasRequiredRole(role: UserRole, session: unknown) { - if (isNil(session)) return false; - return (session as any)?.user?.role === role; + if (isNil(session)) return false + return (session as any)?.user?.role === role } diff --git a/src/lib/utils.ts b/src/lib/utils.ts index a0ff7a1..fac2c4b 100644 --- a/src/lib/utils.ts +++ b/src/lib/utils.ts @@ -1,8 +1,8 @@ -import { type ClassValue, clsx } from "clsx"; -import { twMerge } from "tailwind-merge"; +import { type ClassValue, clsx } from "clsx" +import { twMerge } from "tailwind-merge" export function cn(...inputs: ClassValue[]) { - return twMerge(clsx(inputs)); + return twMerge(clsx(inputs)) } export function usernameToInitials(username: string) { @@ -12,5 +12,5 @@ export function usernameToInitials(username: string) { .slice(0, 2) .map((word: string) => word[0]) .join("") - .toUpperCase(); + .toUpperCase() } diff --git a/src/mdx-components.tsx b/src/mdx-components.tsx index 9ff7229..ee1c3de 100644 --- a/src/mdx-components.tsx +++ b/src/mdx-components.tsx @@ -1,7 +1,7 @@ -import type { MDXComponents } from "mdx/types"; +import type { MDXComponents } from "mdx/types" export function useMDXComponents(components: MDXComponents): MDXComponents { return { ...components, - }; + } } diff --git a/src/server/auth.ts b/src/server/auth.ts index 007dc9e..55cddf6 100644 --- a/src/server/auth.ts +++ b/src/server/auth.ts @@ -1,16 +1,18 @@ -import { PrismaAdapter } from "@auth/prisma-adapter"; +import { PrismaAdapter } from "@auth/prisma-adapter" import { type DefaultSession, getServerSession, type NextAuthOptions, -} from "next-auth"; -import { type Adapter } from "next-auth/adapters"; -import DiscordProvider from "next-auth/providers/discord"; -import EmailProvider from "next-auth/providers/email"; - -import { env } from "@/env"; -import { inDevEnvironment } from "@/lib/envs"; -import { db } from "@/services/db"; +} from "next-auth" +import { type Adapter } from "next-auth/adapters" +import DiscordProvider from "next-auth/providers/discord" +import EmailProvider, { + type SendVerificationRequestParams, +} from "next-auth/providers/email" +import { env } from "@/env" +import { inDevEnvironment } from "@/lib/envs" +import { db } from "@/services/db" +import { type Provider } from "next-auth/providers/index" /** * Module augmentation for `next-auth` types. Allows us to add custom properties to the `session` @@ -21,10 +23,10 @@ import { db } from "@/services/db"; declare module "next-auth" { interface Session extends DefaultSession { user: { - id: string; + id: string // ...other properties // role: UserRole; - } & DefaultSession["user"]; + } & DefaultSession["user"] } // interface User { @@ -48,7 +50,29 @@ const emailProvider = EmailProvider({ host: env.EMAIL_SERVER_HOST, port: env.EMAIL_SERVER_PORT, }, -}); +}) + +const providers: Provider[] = [ + { + ...emailProvider, + async sendVerificationRequest(params: SendVerificationRequestParams) { + if (inDevEnvironment) { + console.log("\nRequested a magic link, signin with url:", params.url) + } else { + return emailProvider.sendVerificationRequest(params) + } + }, + }, +] + +if (env.DISCORD_CLIENT_ID && env.DISCORD_CLIENT_SECRET) { + providers.push( + DiscordProvider({ + clientId: env.DISCORD_CLIENT_ID, + clientSecret: env.DISCORD_CLIENT_SECRET, + }), + ) +} export const authOptions: NextAuthOptions = { adapter: PrismaAdapter(db) as Adapter, @@ -62,36 +86,12 @@ export const authOptions: NextAuthOptions = { }, }), }, - providers: [ - DiscordProvider({ - clientId: env.DISCORD_CLIENT_ID, - clientSecret: env.DISCORD_CLIENT_SECRET, - }), - { - ...emailProvider, - async sendVerificationRequest(params) { - if (inDevEnvironment) { - console.log("\nRequested a magic link, signin with url:", params.url); - } else { - return emailProvider.sendVerificationRequest(params); - } - }, - }, - /** - * ...add more providers here. - * - * Most other providers require a bit more work than the Discord provider. For example, the - * GitHub provider requires you to add the `refresh_token_expires_in` field to the Account - * model. Refer to the NextAuth.js docs for the provider you want to use. Example: - * - * @see https://next-auth.js.org/providers/github - */ - ], -}; + providers: providers, +} /** * Wrapper for `getServerSession` so that you don't need to import the `authOptions` in every file. * * @see https://next-auth.js.org/configuration/nextjs */ -export const getServerAuthSession = () => getServerSession(authOptions); +export const getServerAuthSession = () => getServerSession(authOptions) diff --git a/src/services/db.ts b/src/services/db.ts index 9255447..b9ad717 100644 --- a/src/services/db.ts +++ b/src/services/db.ts @@ -1,17 +1,17 @@ -import { PrismaClient } from "@prisma/client"; +import { PrismaClient } from "@prisma/client" -import { env } from "@/env"; +import { env } from "@/env" const createPrismaClient = () => new PrismaClient({ log: env.NODE_ENV === "development" ? ["query", "error", "warn"] : ["error"], - }); + }) const globalForPrisma = globalThis as unknown as { - prisma: ReturnType | undefined; -}; + prisma: ReturnType | undefined +} -export const db = globalForPrisma.prisma ?? createPrismaClient(); +export const db = globalForPrisma.prisma ?? createPrismaClient() -if (env.NODE_ENV !== "production") globalForPrisma.prisma = db; +if (env.NODE_ENV !== "production") globalForPrisma.prisma = db diff --git a/src/services/nodemailer.ts b/src/services/nodemailer.ts index 09e6701..114f68b 100644 --- a/src/services/nodemailer.ts +++ b/src/services/nodemailer.ts @@ -1,6 +1,6 @@ -import nodemailer from "nodemailer"; +import nodemailer from "nodemailer" -import { env } from "@/env"; +import { env } from "@/env" const transporter = nodemailer.createTransport({ auth: { @@ -10,6 +10,6 @@ const transporter = nodemailer.createTransport({ host: env.EMAIL_SERVER_HOST, port: env.EMAIL_SERVER_PORT, secure: true, -}); +}) -export { transporter }; +export { transporter } diff --git a/src/services/stripe.ts b/src/services/stripe.ts index 569f087..8fd7408 100644 --- a/src/services/stripe.ts +++ b/src/services/stripe.ts @@ -1,9 +1,19 @@ -import Stripe from "stripe"; +import Stripe from "stripe" +import { env } from "@/env" -import { env } from "@/env"; +let _stripe: Stripe -const stripe = new Stripe(env.STRIPE_PRIVATE_KEY, { - apiVersion: "2023-10-16", -}); +export const canUseStripe = (): boolean => !!env.STRIPE_PRIVATE_KEY -export { stripe }; +const stripe = () => { + if (!canUseStripe()) { + throw new Error("Stripe is not configured") + } + + if (!_stripe) + _stripe = new Stripe(env.STRIPE_PRIVATE_KEY!, { apiVersion: "2023-10-16" }) + + return _stripe +} + +export { stripe } diff --git a/src/store/signup.ts b/src/store/signup.ts index fc7fde8..b727618 100644 --- a/src/store/signup.ts +++ b/src/store/signup.ts @@ -1,10 +1,10 @@ -import { create } from "zustand"; +import { create } from "zustand" interface SignUpState { - name: string; - surname: string; - email: string; - socialSecurityNumber: string; + name: string + surname: string + email: string + socialSecurityNumber: string } export const useSignUpStore = create((set) => ({ @@ -17,4 +17,4 @@ export const useSignUpStore = create((set) => ({ setSurname: (surname: string) => set(() => ({ surname: surname })), socialSecurityNumber: "", surname: "", -})); +})) diff --git a/src/types/next-auth.d.ts b/src/types/next-auth.d.ts index 0b9de50..8a3c9ee 100644 --- a/src/types/next-auth.d.ts +++ b/src/types/next-auth.d.ts @@ -1,15 +1,15 @@ -import { type UserRole } from "@prisma/client"; +import { type UserRole } from "@prisma/client" declare module "next-auth" { interface User { // Add your additional properties here: - role: UserRole; + role: UserRole } } declare module "@auth/core/adapters" { interface AdapterUser { // Add your additional properties here: - role: UserRole; + role: UserRole } }