Initial commit for wedding-planner MVP

This commit is contained in:
2025-06-23 10:20:37 -04:00
commit bbe5eb0ccd
37 changed files with 5650 additions and 0 deletions

69
lib/auth.ts Normal file
View File

@@ -0,0 +1,69 @@
// lib/auth.ts
import NextAuth from 'next-auth';
import { PrismaAdapter } from '@next-auth/prisma-adapter';
import CredentialsProvider from 'next-auth/providers/credentials';
import { prisma } from './prisma';
import type { NextAuthOptions, User } from 'next-auth';
import bcrypt from "bcrypt";
export const authOptions: NextAuthOptions = {
adapter: PrismaAdapter(prisma),
providers: [
CredentialsProvider({
name: 'Credentials',
credentials: {
email: { label: "Email", type: "email" },
password: { label: "Password", type: "password" },
},
async authorize(credentials) {
if (!credentials?.email || !credentials?.password) {
throw new Error("Missing email or password");
}
const user = await prisma.user.findUnique({
where: { email: credentials.email },
});
if (!user || !user.password) {
throw new Error("Invalid credentials");
}
const isValid = await bcrypt.compare(credentials.password, user.password);
if (!isValid) {
throw new Error("Invalid credentials");
}
return {
id: user.id,
email: user.email,
name: user.name,
role: user.role,
};
},
}),
],
session: {
strategy: 'jwt',
},
callbacks: {
async session({ session, token }: { session: any; token: any }) {
if (session.user) {
session.user.id = token.sub!;
session.user.role = token.role;
}
return session;
},
async jwt({ token, user }: { token: any; user?: any }) {
if (user) {
token.role = user.role;
}
return token;
},
},
secret: process.env.NEXTAUTH_SECRET,
};
export const {
handlers: { GET, POST },
auth,
} = NextAuth(authOptions);

34
lib/mutations.ts Normal file
View File

@@ -0,0 +1,34 @@
import { prisma } from './prisma';
export const mutations = {
async createEvent(data: {
name: string;
date?: string;
location?: string;
creatorId: string;
}) {
const event = await prisma.event.create({
data: {
name: data.name,
date: data.date ? new Date(data.date) : undefined,
location: data.location,
creatorId: data.creatorId,
},
});
return event;
},
async addGuest(data: {
eventId: string;
name: string;
email?: string;
}) {
return await prisma.guest.create({
data: {
eventId: data.eventId,
name: data.name,
email: data.email,
},
});
}
};

13
lib/prisma.ts Normal file
View File

@@ -0,0 +1,13 @@
import { PrismaClient } from '@prisma/client'
const globalForPrisma = globalThis as unknown as {
prisma: PrismaClient | undefined
}
export const prisma =
globalForPrisma.prisma ??
new PrismaClient({
log: ['query', 'error', 'warn'],
})
if (process.env.NODE_ENV !== 'production') globalForPrisma.prisma = prisma

5
lib/queries.ts Normal file
View File

@@ -0,0 +1,5 @@
import { prisma } from './prisma';
export const queries = {
// Test for adding invitees
}

14
lib/setup.ts Normal file
View File

@@ -0,0 +1,14 @@
import { prisma } from './prisma';
export async function isFirstSetup() {
const user = await prisma.user.findFirst({
where: {
OR: [
{ role: 'COUPLE' },
{ role: 'PLANNER'},
]
}
});
return !user;
}