The ManageUsers sub-component referenced user?.role for conditional role dropdown options but didn't call useAuth() to get the user object. This caused 'user is not defined' JS errors and blank admin pages. Browser E2E: 20/20 tests pass.
108 lines
3.2 KiB
Plaintext
108 lines
3.2 KiB
Plaintext
generator client {
|
|
provider = "prisma-client-js"
|
|
}
|
|
|
|
datasource db {
|
|
provider = "postgresql"
|
|
url = env("DATABASE_URL")
|
|
}
|
|
|
|
enum Role {
|
|
employee
|
|
office
|
|
admin
|
|
super_admin
|
|
}
|
|
|
|
enum TimesheetStatus {
|
|
draft
|
|
submitted
|
|
approved
|
|
rejected
|
|
}
|
|
|
|
model User {
|
|
id String @id @default(uuid())
|
|
email String @unique
|
|
name String
|
|
role Role @default(employee)
|
|
passwordHash String @map("password_hash")
|
|
isActive Boolean @default(true) @map("is_active")
|
|
refreshToken String? @map("refresh_token")
|
|
createdAt DateTime @default(now()) @map("created_at")
|
|
updatedAt DateTime @updatedAt @map("updated_at")
|
|
|
|
timeEntries TimeEntry[]
|
|
timesheets Timesheet[] @relation("UserTimesheets")
|
|
approvals Timesheet[] @relation("ApprovedTimesheets")
|
|
|
|
@@map("users")
|
|
}
|
|
|
|
model Homeowner {
|
|
id String @id @default(uuid())
|
|
name String @unique
|
|
address String?
|
|
isActive Boolean @default(true) @map("is_active")
|
|
createdAt DateTime @default(now()) @map("created_at")
|
|
updatedAt DateTime @updatedAt @map("updated_at")
|
|
|
|
timeEntries TimeEntry[]
|
|
|
|
@@map("homeowners")
|
|
}
|
|
|
|
model TimeEntry {
|
|
id String @id @default(uuid())
|
|
userId String @map("user_id")
|
|
date DateTime @db.Date
|
|
homeownerId String @map("homeowner_id")
|
|
hoursWorked Decimal @map("hours_worked") @db.Decimal(4, 2)
|
|
workDescription String @map("work_description")
|
|
createdAt DateTime @default(now()) @map("created_at")
|
|
updatedAt DateTime @updatedAt @map("updated_at")
|
|
|
|
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
homeowner Homeowner @relation(fields: [homeownerId], references: [id])
|
|
timesheetLinks TimesheetEntry[]
|
|
|
|
@@index([userId, date])
|
|
@@index([homeownerId])
|
|
@@map("time_entries")
|
|
}
|
|
|
|
model Timesheet {
|
|
id String @id @default(uuid())
|
|
userId String @map("user_id")
|
|
weekStart DateTime @map("week_start") @db.Date
|
|
weekEnd DateTime @map("week_end") @db.Date
|
|
status TimesheetStatus @default(draft)
|
|
submittedAt DateTime? @map("submitted_at")
|
|
approvedBy String? @map("approved_by")
|
|
approvedAt DateTime? @map("approved_at")
|
|
notes String?
|
|
createdAt DateTime @default(now()) @map("created_at")
|
|
updatedAt DateTime @updatedAt @map("updated_at")
|
|
|
|
user User @relation("UserTimesheets", fields: [userId], references: [id], onDelete: Cascade)
|
|
approver User? @relation("ApprovedTimesheets", fields: [approvedBy], references: [id])
|
|
entries TimesheetEntry[]
|
|
|
|
@@unique([userId, weekStart])
|
|
@@index([status])
|
|
@@index([userId, weekStart])
|
|
@@map("timesheets")
|
|
}
|
|
|
|
model TimesheetEntry {
|
|
id String @id @default(uuid())
|
|
timesheetId String @map("timesheet_id")
|
|
timeEntryId String @map("time_entry_id")
|
|
|
|
timesheet Timesheet @relation(fields: [timesheetId], references: [id], onDelete: Cascade)
|
|
timeEntry TimeEntry @relation(fields: [timeEntryId], references: [id], onDelete: Cascade)
|
|
|
|
@@unique([timesheetId, timeEntryId])
|
|
@@map("timesheet_entries")
|
|
}
|