feat: add db models, setup prisma + utils
This commit is contained in:
parent
d799f3270a
commit
a10816e43c
|
|
@ -1,13 +1,13 @@
|
|||
import { PrismaClient } from '@prisma/client'
|
||||
import invariant from 'tiny-invariant'
|
||||
import { PrismaClient } from '@prisma/client';
|
||||
import invariant from 'tiny-invariant';
|
||||
|
||||
invariant(process.env.DATABASE_URL, 'DATABASE_URL must be set')
|
||||
const DATABASE_URL = process.env.DATABASE_URL
|
||||
invariant(process.env.DATABASE_URL, 'DATABASE_URL must be set');
|
||||
const DATABASE_URL = process.env.DATABASE_URL;
|
||||
|
||||
let prisma: PrismaClient
|
||||
let prisma: PrismaClient;
|
||||
|
||||
declare global {
|
||||
var __db__: PrismaClient
|
||||
var __db__: PrismaClient;
|
||||
}
|
||||
|
||||
// this is needed because in development we don't want to restart
|
||||
|
|
@ -15,20 +15,20 @@ declare global {
|
|||
// create a new connection to the DB with every change either.
|
||||
// in production we'll have a single connection to the DB.
|
||||
if (process.env.NODE_ENV === 'production') {
|
||||
prisma = getClient()
|
||||
prisma = getClient();
|
||||
} else {
|
||||
if (!global.__db__) {
|
||||
global.__db__ = getClient()
|
||||
global.__db__ = getClient();
|
||||
}
|
||||
prisma = global.__db__
|
||||
prisma = global.__db__;
|
||||
}
|
||||
|
||||
function getClient() {
|
||||
invariant(typeof DATABASE_URL === 'string', 'DATABASE_URL env var not set')
|
||||
invariant(typeof DATABASE_URL === 'string', 'DATABASE_URL env var not set');
|
||||
|
||||
const databaseUrl = new URL(DATABASE_URL)
|
||||
const databaseUrl = new URL(DATABASE_URL);
|
||||
|
||||
console.log(`🔌 setting up prisma client to ${databaseUrl.host}`)
|
||||
console.log(`🔌 setting up prisma client to ${databaseUrl.host}`);
|
||||
// NOTE: during development if you change anything in this function, remember
|
||||
// that this only runs once per server restart and won't automatically be
|
||||
// re-run per request like everything else is. So if you need to change
|
||||
|
|
@ -39,11 +39,11 @@ function getClient() {
|
|||
url: databaseUrl.toString()
|
||||
}
|
||||
}
|
||||
})
|
||||
});
|
||||
// connect eagerly
|
||||
client.$connect()
|
||||
client.$connect();
|
||||
|
||||
return client
|
||||
return client;
|
||||
}
|
||||
|
||||
export { prisma }
|
||||
export { prisma };
|
||||
|
|
|
|||
|
|
@ -1,37 +1,55 @@
|
|||
import type { User, Project } from '@prisma/client'
|
||||
import type { User, Project } from '@prisma/client';
|
||||
|
||||
import { prisma } from '~/db.server'
|
||||
import { prisma } from '~/db.server';
|
||||
|
||||
export type { Project } from '@prisma/client'
|
||||
export type { Project } from '@prisma/client';
|
||||
|
||||
export function getProject({
|
||||
id,
|
||||
userId
|
||||
}: Pick<Project, 'id'> & {
|
||||
userId: User['id']
|
||||
userId: User['id'];
|
||||
}) {
|
||||
return prisma.project.findFirst({
|
||||
where: { id, userId }
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
export function getProjects({
|
||||
export async function getProjects({
|
||||
userId,
|
||||
page,
|
||||
offset,
|
||||
orderBy
|
||||
size,
|
||||
orderBy,
|
||||
order
|
||||
}: {
|
||||
userId: User['id']
|
||||
page?: number
|
||||
offset?: number
|
||||
orderBy?: { [key in keyof Project]?: 'asc' | 'desc' }
|
||||
userId: User['id'];
|
||||
page?: number;
|
||||
size?: number;
|
||||
orderBy?: string;
|
||||
order?: 'asc' | 'desc';
|
||||
}) {
|
||||
return prisma.project.findMany({
|
||||
const totalProjects = await prisma.project.count({
|
||||
where: { userId }
|
||||
});
|
||||
const paginatedProjects = await prisma.project.findMany({
|
||||
where: { userId },
|
||||
orderBy: orderBy || { updatedAt: 'desc' },
|
||||
skip: page && offset ? page * offset : 0,
|
||||
take: offset
|
||||
})
|
||||
orderBy: {
|
||||
[orderBy || 'createdAt']: order || 'desc'
|
||||
},
|
||||
skip: page && size ? (page - 1) * size : 0,
|
||||
take: size
|
||||
});
|
||||
|
||||
const nextPage =
|
||||
page && size && totalProjects > page * size ? page + 1 : null;
|
||||
const previousPage = page && page > 2 ? page - 1 : null;
|
||||
|
||||
return {
|
||||
total: totalProjects,
|
||||
projects: paginatedProjects,
|
||||
nextPage,
|
||||
previousPage
|
||||
};
|
||||
}
|
||||
|
||||
export function createProject({
|
||||
|
|
@ -40,7 +58,7 @@ export function createProject({
|
|||
color,
|
||||
userId
|
||||
}: Pick<Project, 'name' | 'description' | 'color'> & {
|
||||
userId: User['id']
|
||||
userId: User['id'];
|
||||
}) {
|
||||
return prisma.project.create({
|
||||
data: {
|
||||
|
|
@ -49,7 +67,7 @@ export function createProject({
|
|||
color,
|
||||
userId
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
export function updateProject({
|
||||
|
|
@ -58,7 +76,7 @@ export function updateProject({
|
|||
description,
|
||||
color
|
||||
}: Partial<Pick<Project, 'name' | 'description' | 'color'>> & {
|
||||
projectId: Project['id']
|
||||
projectId: Project['id'];
|
||||
}) {
|
||||
return prisma.project.update({
|
||||
data: {
|
||||
|
|
@ -69,11 +87,14 @@ export function updateProject({
|
|||
where: {
|
||||
id: projectId
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
export function deleteProject({ id, userId }: Pick<Project, 'id'> & { userId: User['id'] }) {
|
||||
export function deleteProject({
|
||||
id,
|
||||
userId
|
||||
}: Pick<Project, 'id'> & { userId: User['id'] }) {
|
||||
return prisma.project.deleteMany({
|
||||
where: { id, userId }
|
||||
})
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,39 +1,104 @@
|
|||
import type { User, TimeEntry, Project } from '@prisma/client'
|
||||
import type { User, TimeEntry, Project } from '@prisma/client';
|
||||
|
||||
import { prisma } from '~/db.server'
|
||||
import { prisma } from '~/db.server';
|
||||
|
||||
export type { TimeEntry } from '@prisma/client'
|
||||
export type { TimeEntry } from '@prisma/client';
|
||||
|
||||
export function getTimeEntry({
|
||||
id,
|
||||
userId
|
||||
}: Pick<TimeEntry, 'id'> & {
|
||||
userId: User['id']
|
||||
userId: User['id'];
|
||||
}) {
|
||||
return prisma.timeEntry.findFirst({
|
||||
where: { id, userId }
|
||||
})
|
||||
where: { id, userId },
|
||||
include: {
|
||||
project: true
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export function getTimeEntries({
|
||||
export async function getTimeEntries({
|
||||
userId,
|
||||
projectId,
|
||||
page,
|
||||
offset,
|
||||
orderBy
|
||||
size,
|
||||
orderBy,
|
||||
order
|
||||
}: {
|
||||
userId: User['id']
|
||||
projectId?: Project['id']
|
||||
page?: number
|
||||
offset?: number
|
||||
orderBy?: { [key in keyof TimeEntry]?: 'asc' | 'desc' }
|
||||
userId: User['id'];
|
||||
projectId?: Project['id'];
|
||||
page?: number;
|
||||
size?: number;
|
||||
orderBy?: string;
|
||||
order?: 'asc' | 'desc';
|
||||
}) {
|
||||
return prisma.timeEntry.findMany({
|
||||
const totalTimeEntries = await prisma.timeEntry.count({
|
||||
where: { userId, projectId }
|
||||
});
|
||||
const paginatedEntries = await prisma.timeEntry.findMany({
|
||||
where: { userId, projectId },
|
||||
orderBy: orderBy || { updatedAt: 'desc' },
|
||||
skip: page && offset ? page * offset : 0,
|
||||
take: offset
|
||||
})
|
||||
include: {
|
||||
project: true
|
||||
},
|
||||
orderBy: {
|
||||
[orderBy || 'startTime']: order || 'desc'
|
||||
},
|
||||
skip: page && size ? (page - 1) * size : 0,
|
||||
take: size
|
||||
});
|
||||
|
||||
const monthAgo = new Date(new Date().getFullYear(), new Date().getMonth(), 1);
|
||||
const weekAgo = new Date(
|
||||
new Date().getFullYear(),
|
||||
new Date().getMonth(),
|
||||
new Date().getDate() - 7
|
||||
);
|
||||
const monthEntries = await prisma.timeEntry.findMany({
|
||||
where: {
|
||||
userId,
|
||||
projectId,
|
||||
startTime: { gte: monthAgo },
|
||||
endTime: { lte: new Date() }
|
||||
}
|
||||
});
|
||||
const monthTotalHours =
|
||||
monthEntries.reduce(
|
||||
(acc, entry) =>
|
||||
acc +
|
||||
((entry.endTime || new Date(Date.now())).getTime() -
|
||||
entry.startTime.getTime()),
|
||||
0
|
||||
) /
|
||||
1000 /
|
||||
60 /
|
||||
60;
|
||||
const weekTotalHours =
|
||||
monthEntries
|
||||
.filter((e) => e.startTime >= weekAgo)
|
||||
.reduce(
|
||||
(acc, entry) =>
|
||||
acc +
|
||||
((entry.endTime || new Date(Date.now())).getTime() -
|
||||
entry.startTime.getTime()),
|
||||
0
|
||||
) /
|
||||
1000 /
|
||||
60 /
|
||||
60;
|
||||
|
||||
const nextPage =
|
||||
page && size && totalTimeEntries > page * size ? page + 1 : null;
|
||||
const previousPage = page && page > 2 ? page - 1 : null;
|
||||
|
||||
return {
|
||||
total: totalTimeEntries,
|
||||
monthTotalHours,
|
||||
weekTotalHours,
|
||||
timeEntries: paginatedEntries,
|
||||
nextPage,
|
||||
previousPage
|
||||
};
|
||||
}
|
||||
|
||||
export function createTimeEntry({
|
||||
|
|
@ -43,8 +108,8 @@ export function createTimeEntry({
|
|||
userId,
|
||||
projectId
|
||||
}: Pick<TimeEntry, 'description' | 'startTime' | 'endTime'> & {
|
||||
userId: User['id']
|
||||
projectId: Project['id']
|
||||
userId: User['id'];
|
||||
projectId: Project['id'];
|
||||
}) {
|
||||
return prisma.timeEntry.create({
|
||||
data: {
|
||||
|
|
@ -54,7 +119,14 @@ export function createTimeEntry({
|
|||
projectId,
|
||||
userId
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
export function stopAllTimeEntries(userId: User['id']) {
|
||||
return prisma.timeEntry.updateMany({
|
||||
where: { userId, endTime: null },
|
||||
data: { endTime: new Date() }
|
||||
});
|
||||
}
|
||||
|
||||
export function updateTimeEntry({
|
||||
|
|
@ -63,8 +135,10 @@ export function updateTimeEntry({
|
|||
startTime,
|
||||
endTime,
|
||||
projectId
|
||||
}: Partial<Pick<TimeEntry, 'description' | 'startTime' | 'endTime' | 'projectId'>> & {
|
||||
timeEntryId: TimeEntry['id']
|
||||
}: Partial<
|
||||
Pick<TimeEntry, 'description' | 'startTime' | 'endTime' | 'projectId'>
|
||||
> & {
|
||||
timeEntryId: TimeEntry['id'];
|
||||
}) {
|
||||
return prisma.timeEntry.update({
|
||||
data: {
|
||||
|
|
@ -76,11 +150,14 @@ export function updateTimeEntry({
|
|||
where: {
|
||||
id: timeEntryId
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
export function deleteNote({ id, userId }: Pick<TimeEntry, 'id'> & { userId: User['id'] }) {
|
||||
export function deleteTimeEntry({
|
||||
id,
|
||||
userId
|
||||
}: Pick<TimeEntry, 'id'> & { userId: User['id'] }) {
|
||||
return prisma.timeEntry.deleteMany({
|
||||
where: { id, userId }
|
||||
})
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,19 +1,19 @@
|
|||
import type { Password, User } from "@prisma/client";
|
||||
import bcrypt from "bcryptjs";
|
||||
import type { Password, User } from '@prisma/client';
|
||||
import bcrypt from 'bcryptjs';
|
||||
|
||||
import { prisma } from "~/db.server";
|
||||
import { prisma } from '~/db.server';
|
||||
|
||||
export type { User } from "@prisma/client";
|
||||
export type { User } from '@prisma/client';
|
||||
|
||||
export async function getUserById(id: User["id"]) {
|
||||
export async function getUserById(id: User['id']) {
|
||||
return prisma.user.findUnique({ where: { id } });
|
||||
}
|
||||
|
||||
export async function getUserByEmail(email: User["email"]) {
|
||||
export async function getUserByEmail(email: User['email']) {
|
||||
return prisma.user.findUnique({ where: { email } });
|
||||
}
|
||||
|
||||
export async function createUser(email: User["email"], password: string) {
|
||||
export async function createUser(email: User['email'], password: string) {
|
||||
const hashedPassword = await bcrypt.hash(password, 10);
|
||||
|
||||
return prisma.user.create({
|
||||
|
|
@ -21,27 +21,28 @@ export async function createUser(email: User["email"], password: string) {
|
|||
email,
|
||||
password: {
|
||||
create: {
|
||||
hash: hashedPassword,
|
||||
},
|
||||
},
|
||||
},
|
||||
hash: hashedPassword
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export async function deleteUserByEmail(email: User["email"]) {
|
||||
export async function deleteUserByEmail(email: User['email']) {
|
||||
return prisma.user.delete({ where: { email } });
|
||||
}
|
||||
|
||||
export async function verifyLogin(
|
||||
email: User["email"],
|
||||
password: Password["hash"]
|
||||
email: User['email'],
|
||||
password: Password['hash']
|
||||
) {
|
||||
const userWithPassword = await prisma.user.findUnique({
|
||||
where: { email },
|
||||
include: {
|
||||
password: true,
|
||||
},
|
||||
password: true
|
||||
}
|
||||
});
|
||||
console.log(userWithPassword);
|
||||
|
||||
if (!userWithPassword || !userWithPassword.password) {
|
||||
return null;
|
||||
|
|
@ -51,6 +52,7 @@ export async function verifyLogin(
|
|||
password,
|
||||
userWithPassword.password.hash
|
||||
);
|
||||
console.log(isValid, password, userWithPassword.password.hash);
|
||||
|
||||
if (!isValid) {
|
||||
return null;
|
||||
|
|
|
|||
|
|
@ -1,62 +1,67 @@
|
|||
import { createCookieSessionStorage, redirect } from '@remix-run/node'
|
||||
import invariant from 'tiny-invariant'
|
||||
import { createCookieSessionStorage, redirect } from '@remix-run/node';
|
||||
import invariant from 'tiny-invariant';
|
||||
|
||||
import type { User } from '~/models/user.server'
|
||||
import { getUserById } from '~/models/user.server'
|
||||
import type { User } from '~/models/user.server';
|
||||
import { getUserById } from '~/models/user.server';
|
||||
|
||||
invariant(process.env.SESSION_SECRET, 'SESSION_SECRET must be set')
|
||||
const SESSION_SECRET = process.env.SESSION_SECRET
|
||||
invariant(process.env.SESSION_SECRET, 'SESSION_SECRET must be set');
|
||||
const SESSION_SECRET = process.env.SESSION_SECRET;
|
||||
|
||||
export const sessionStorage = createCookieSessionStorage({
|
||||
cookie: {
|
||||
name: '__session',
|
||||
name: 'wta__session',
|
||||
httpOnly: true,
|
||||
path: '/',
|
||||
sameSite: 'lax',
|
||||
secrets: [SESSION_SECRET],
|
||||
secure: process.env.NODE_ENV === 'production'
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
const USER_SESSION_KEY = 'userId'
|
||||
const USER_SESSION_KEY = 'userId';
|
||||
|
||||
export async function getSession(request: Request) {
|
||||
const cookie = request.headers.get('Cookie')
|
||||
return sessionStorage.getSession(cookie)
|
||||
const cookie = request.headers.get('Cookie');
|
||||
return sessionStorage.getSession(cookie);
|
||||
}
|
||||
|
||||
export async function getUserId(request: Request): Promise<User['id'] | undefined> {
|
||||
const session = await getSession(request)
|
||||
const userId = session.get(USER_SESSION_KEY)
|
||||
return userId
|
||||
export async function getUserId(
|
||||
request: Request
|
||||
): Promise<User['id'] | undefined> {
|
||||
const session = await getSession(request);
|
||||
const userId = session.get(USER_SESSION_KEY);
|
||||
return userId;
|
||||
}
|
||||
|
||||
export async function getUser(request: Request) {
|
||||
const userId = await getUserId(request)
|
||||
if (userId === undefined) return null
|
||||
const userId = await getUserId(request);
|
||||
if (userId === undefined) return null;
|
||||
|
||||
const user = await getUserById(userId)
|
||||
if (user) return user
|
||||
const user = await getUserById(userId);
|
||||
if (user) return user;
|
||||
|
||||
throw await logout(request)
|
||||
throw await logout(request);
|
||||
}
|
||||
|
||||
export async function requireUserId(request: Request, redirectTo: string = new URL(request.url).pathname) {
|
||||
const userId = await getUserId(request)
|
||||
export async function requireUserId(
|
||||
request: Request,
|
||||
redirectTo: string = new URL(request.url).pathname
|
||||
) {
|
||||
const userId = await getUserId(request);
|
||||
if (!userId) {
|
||||
const searchParams = new URLSearchParams([['redirectTo', redirectTo]])
|
||||
throw redirect(`/login?${searchParams}`)
|
||||
const searchParams = new URLSearchParams([['redirectTo', redirectTo]]);
|
||||
throw redirect(`/login?${searchParams}`);
|
||||
}
|
||||
return userId
|
||||
return userId;
|
||||
}
|
||||
|
||||
export async function requireUser(request: Request) {
|
||||
const userId = await requireUserId(request)
|
||||
const userId = await requireUserId(request);
|
||||
|
||||
const user = await getUserById(userId)
|
||||
if (user) return user
|
||||
const user = await getUserById(userId);
|
||||
if (user) return user;
|
||||
|
||||
throw await logout(request)
|
||||
throw await logout(request);
|
||||
}
|
||||
|
||||
export async function createUserSession({
|
||||
|
|
@ -65,13 +70,13 @@ export async function createUserSession({
|
|||
remember,
|
||||
redirectTo
|
||||
}: {
|
||||
request: Request
|
||||
userId: string
|
||||
remember: boolean
|
||||
redirectTo: string
|
||||
request: Request;
|
||||
userId: string;
|
||||
remember: boolean;
|
||||
redirectTo: string;
|
||||
}) {
|
||||
const session = await getSession(request)
|
||||
session.set(USER_SESSION_KEY, userId)
|
||||
const session = await getSession(request);
|
||||
session.set(USER_SESSION_KEY, userId);
|
||||
return redirect(redirectTo, {
|
||||
headers: {
|
||||
'Set-Cookie': await sessionStorage.commitSession(session, {
|
||||
|
|
@ -80,14 +85,14 @@ export async function createUserSession({
|
|||
: undefined
|
||||
})
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
export async function logout(request: Request) {
|
||||
const session = await getSession(request)
|
||||
const session = await getSession(request);
|
||||
return redirect('/', {
|
||||
headers: {
|
||||
'Set-Cookie': await sessionStorage.destroySession(session)
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
|
|
|
|||
20
app/utils.ts
20
app/utils.ts
|
|
@ -1,9 +1,9 @@
|
|||
import { useMatches } from "@remix-run/react";
|
||||
import { useMemo } from "react";
|
||||
import { useMatches } from '@remix-run/react';
|
||||
import { useMemo } from 'react';
|
||||
|
||||
import type { User } from "~/models/user.server";
|
||||
import type { User } from '~/models/user.server';
|
||||
|
||||
const DEFAULT_REDIRECT = "/";
|
||||
const DEFAULT_REDIRECT = '/';
|
||||
|
||||
/**
|
||||
* This should be used any time the redirect path is user-provided
|
||||
|
|
@ -16,11 +16,11 @@ export function safeRedirect(
|
|||
to: FormDataEntryValue | string | null | undefined,
|
||||
defaultRedirect: string = DEFAULT_REDIRECT
|
||||
) {
|
||||
if (!to || typeof to !== "string") {
|
||||
if (!to || typeof to !== 'string') {
|
||||
return defaultRedirect;
|
||||
}
|
||||
|
||||
if (!to.startsWith("/") || to.startsWith("//")) {
|
||||
if (!to.startsWith('/') || to.startsWith('//')) {
|
||||
return defaultRedirect;
|
||||
}
|
||||
|
||||
|
|
@ -45,11 +45,11 @@ export function useMatchesData(
|
|||
}
|
||||
|
||||
function isUser(user: any): user is User {
|
||||
return user && typeof user === "object" && typeof user.email === "string";
|
||||
return user && typeof user === 'object' && typeof user.email === 'string';
|
||||
}
|
||||
|
||||
export function useOptionalUser(): User | undefined {
|
||||
const data = useMatchesData("root");
|
||||
const data = useMatchesData('root');
|
||||
if (!data || !isUser(data.user)) {
|
||||
return undefined;
|
||||
}
|
||||
|
|
@ -60,12 +60,12 @@ export function useUser(): User {
|
|||
const maybeUser = useOptionalUser();
|
||||
if (!maybeUser) {
|
||||
throw new Error(
|
||||
"No user found in root loader, but user is required by useUser. If user is optional, try useOptionalUser instead."
|
||||
'No user found in root loader, but user is required by useUser. If user is optional, try useOptionalUser instead.'
|
||||
);
|
||||
}
|
||||
return maybeUser;
|
||||
}
|
||||
|
||||
export function validateEmail(email: unknown): email is string {
|
||||
return typeof email === "string" && email.length > 3 && email.includes("@");
|
||||
return typeof email === 'string' && email.length > 3 && email.includes('@');
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,17 +1,17 @@
|
|||
import { PrismaClient } from '@prisma/client'
|
||||
import bcrypt from 'bcryptjs'
|
||||
import { PrismaClient } from '@prisma/client';
|
||||
import bcrypt from 'bcryptjs';
|
||||
|
||||
const prisma = new PrismaClient()
|
||||
const prisma = new PrismaClient();
|
||||
|
||||
async function seed() {
|
||||
const email = 'admin@rawmaterial.it'
|
||||
const email = 'admin@rawmaterial.it';
|
||||
|
||||
// cleanup the existing database
|
||||
await prisma.user.delete({ where: { email } }).catch(() => {
|
||||
// no worries if it doesn't exist yet
|
||||
})
|
||||
});
|
||||
|
||||
const hashedPassword = await bcrypt.hash('admin', 10)
|
||||
const hashedPassword = await bcrypt.hash('rawmaterial', 10);
|
||||
|
||||
const user = await prisma.user.create({
|
||||
data: {
|
||||
|
|
@ -22,16 +22,36 @@ async function seed() {
|
|||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
const project = await prisma.project.create({
|
||||
data: {
|
||||
name: 'RawMaterial',
|
||||
description: 'Raw Material is a web app for managing your projects and tasks.',
|
||||
color: '#333',
|
||||
description:
|
||||
'Raw Material is a web app for managing your projects and tasks.',
|
||||
color: 'green',
|
||||
userId: user.id
|
||||
}
|
||||
})
|
||||
});
|
||||
const otherProject = await prisma.project.create({
|
||||
data: {
|
||||
name: 'Memori',
|
||||
description: 'Memori is a web app for managing your memories.',
|
||||
color: 'violet',
|
||||
userId: user.id
|
||||
}
|
||||
});
|
||||
|
||||
new Array(10).fill(0).forEach(async (_, index) => {
|
||||
await prisma.project.create({
|
||||
data: {
|
||||
name: `Project ${index}`,
|
||||
description: `Project ${index} description`,
|
||||
color: 'red',
|
||||
userId: user.id
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
await prisma.timeEntry.create({
|
||||
data: {
|
||||
|
|
@ -41,25 +61,42 @@ async function seed() {
|
|||
projectId: project.id,
|
||||
userId: user.id
|
||||
}
|
||||
})
|
||||
});
|
||||
await prisma.timeEntry.create({
|
||||
data: {
|
||||
description: 'Database setup',
|
||||
description: 'Database setup same day',
|
||||
startTime: new Date('2021-01-01T13:00:00.000Z'),
|
||||
endTime: new Date('2021-01-01T19:00:00.000Z'),
|
||||
projectId: otherProject.id,
|
||||
userId: user.id
|
||||
}
|
||||
});
|
||||
await prisma.timeEntry.create({
|
||||
data: {
|
||||
description: 'Database setup next day',
|
||||
startTime: new Date('2021-01-02T13:00:00.000Z'),
|
||||
endTime: new Date('2021-01-02T19:00:00.000Z'),
|
||||
projectId: otherProject.id,
|
||||
userId: user.id
|
||||
}
|
||||
});
|
||||
await prisma.timeEntry.create({
|
||||
data: {
|
||||
description: 'Ongoing activity',
|
||||
startTime: new Date('2021-01-02T13:00:00.000Z'),
|
||||
projectId: project.id,
|
||||
userId: user.id
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
console.log(`Database has been seeded. 🌱`)
|
||||
console.log(`Database has been seeded. 🌱`);
|
||||
}
|
||||
|
||||
seed()
|
||||
.catch((e) => {
|
||||
console.error(e)
|
||||
process.exit(1)
|
||||
console.error(e);
|
||||
process.exit(1);
|
||||
})
|
||||
.finally(async () => {
|
||||
await prisma.$disconnect()
|
||||
})
|
||||
await prisma.$disconnect();
|
||||
});
|
||||
|
|
|
|||
4
remix.env.d.ts
vendored
4
remix.env.d.ts
vendored
|
|
@ -1,2 +1,6 @@
|
|||
/// <reference types="@remix-run/dev" />
|
||||
/// <reference types="@remix-run/node" />
|
||||
|
||||
declare type Prettify<T> = {
|
||||
[K in keyof T]: T[K]
|
||||
} & {}
|
||||
|
|
|
|||
Loading…
Reference in a new issue