From cb00826b163ef43e1337becd1b455e004da35b8c Mon Sep 17 00:00:00 2001 From: gibbyb Date: Sun, 1 Sep 2024 19:48:10 -0500 Subject: [PATCH] did more stuff --- .../billtracker/BillTrackerCalendar.tsx | 63 ++++++++++++++-- src/components/ui/BillTrackerCalendar.tsx | 1 - src/server/db/schema.ts | 71 +++++++++++++++++-- 3 files changed, 123 insertions(+), 12 deletions(-) diff --git a/src/components/billtracker/BillTrackerCalendar.tsx b/src/components/billtracker/BillTrackerCalendar.tsx index 49ab7bc..a5b9eef 100644 --- a/src/components/billtracker/BillTrackerCalendar.tsx +++ b/src/components/billtracker/BillTrackerCalendar.tsx @@ -1,18 +1,73 @@ "use client" import * as React from "react" import { Calendar } from "~/components/ui/BillTrackerCalendar" +import { Button } from "~/components/ui/button" export default function BillTrackerCalendar() { - const [date, setDate] = React.useState(new Date()) + const [selectedDate, setSelectedDate] = React.useState(undefined) + const [isOpen, setIsOpen] = React.useState(false) + const calendarRef = React.useRef(null) + const popoverRef = React.useRef(null) + + const handleSelect = (date: Date | undefined) => { + if (date) { + if (selectedDate && date.getTime() === selectedDate.getTime()) + setIsOpen(!isOpen) + else { + setSelectedDate(date) + setIsOpen(true) + } + } else + setIsOpen(false) + } + + React.useEffect(() => { + const handleClickOutside = (event: MouseEvent) => { + if ( + calendarRef.current && + popoverRef.current && + !calendarRef.current.contains(event.target as Node) && + !popoverRef.current.contains(event.target as Node) + ) { + setIsOpen(false) + } + } + document.addEventListener('mousedown', handleClickOutside) + return () => { + document.removeEventListener('mousedown', handleClickOutside) + } + }, []) return ( -
+
+ {isOpen && selectedDate && ( +
+
+
+
+

+ {selectedDate.toDateString()} +

+ +
+

Add your events or bills due here.

+
+
+
+ )}
) } diff --git a/src/components/ui/BillTrackerCalendar.tsx b/src/components/ui/BillTrackerCalendar.tsx index ca14991..fd68cc1 100644 --- a/src/components/ui/BillTrackerCalendar.tsx +++ b/src/components/ui/BillTrackerCalendar.tsx @@ -3,7 +3,6 @@ import * as React from "react" import { ChevronLeft, ChevronRight } from "lucide-react" import { DayPicker } from "react-day-picker" - import { cn } from "~/lib/utils" import { buttonVariants } from "~/components/ui/button" diff --git a/src/server/db/schema.ts b/src/server/db/schema.ts index d29a41f..4ea3db2 100644 --- a/src/server/db/schema.ts +++ b/src/server/db/schema.ts @@ -16,15 +16,18 @@ const connectionString = process.env.DATABASE_URL ?? ""; const pool = postgres(connectionString, { max: 1 }) export const db = drizzle(pool) -export const frequencyEnum = pgEnum("frequency", ["Monthly", "Bi-weekly", "Weekly"]) -export const workOrderStatusEnum = pgEnum("workOrderStatus", ["Pending", "Open", "Closed"]) -export const paymentTypeEnum = pgEnum("paymentType", ["Security Deposit", "Rent", "Late Fee", "Other"]) -export const paymentStatusEnum = pgEnum("paymentStatus", ["Pending", "Complete", "Late", "Refunded"]) +export const frequencyEnum = pgEnum("frequency", ["Monthly", "Bi-weekly", "Weekly"]); +export const workOrderStatusEnum = pgEnum("workOrderStatus", ["Pending", "Open", "Closed"]); +export const paymentTypeEnum = pgEnum("paymentType", ["Security Deposit", "Rent", "Late Fee", "Other"]); +export const paymentStatusEnum = pgEnum("paymentStatus", ["Pending", "Complete", "Late", "Refunded"]); export const preferredDaysofWeekEnum = pgEnum("preferredDaysofWeek", - ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"]) + ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"] +); export const propertyTypeEnum = pgEnum("propertyType", ["Apartment", "Condominium", - "Mobile Home", "Multi-Unit Home", "Single-Family Residence", "Townhouse"]) -export const workOrderPriorityEnum = pgEnum("workOrderPriority", ["Low", "High"]) + "Mobile Home", "Multi-Unit Home", "Single-Family Residence", "Townhouse"] +); +export const workOrderPriorityEnum = pgEnum("workOrderPriority", ["Low", "High"] +); export const workOrderTypeEnum = pgEnum("workOrderType", ["Appliance Repair", "Carbon Monoxide Detector Installation", "Ceiling Fan Repair", "Carpentry Repair", "Door Installation/Repair", "Drywall Installation/Repair", @@ -35,6 +38,19 @@ export const workOrderTypeEnum = pgEnum("workOrderType", "Tile Flooring", "Tree Trimming/Cutting", "Water Treatment", "Well/Water Testing", "Window Repair/Installation"] ); +export const billStatusEnum = pgEnum("billStatus", + ["Awaiting Payment", "Paid", "Scheduled", "Late", "Refunded"] +); +export const billTypeEnum = pgEnum("billType", + ["Rent", "Power", "Internet", "Gas", "Water", "Phone Bill", "Cable", + "Security Deposit", "Other"] +); +export const billPaymentTypeEnum = pgEnum("billPaymentType", + ["Paid Online", "Zelle", "Cash", "Cash App", "Apple Pay"] +); +export const billRecurrenceEnum = pgEnum("billRecurrence", + ["Monthly", "Bi-weekly", "Weekly", "Annually"] +); export const users = pgTable( "user", @@ -210,3 +226,44 @@ export const emergencyContacts = pgTable( email: text("email"), } ) + +export const bills = pgTable( + "bill", + { + id: text("id").primaryKey(), + billType: billTypeEnum("billType").notNull(), + billDescription: text("billDescription"), + createdBy: text("createdBy").notNull().references(() => users.id, { onDelete: "cascade" }), + createdAt: timestamp("createdAt").notNull().defaultNow(), + dueDate: timestamp("dueDate").notNull(), + amount: numeric("amount").notNull(), + currency: text("currency").notNull().default("USD"), + recurrence: billRecurrenceEnum("recurrence"), + attachmentUrl: text("attachmentUrl"), + } +) + +export const billsSplitBetween = pgTable( + "billSplitBetween", + { + id: text("id").primaryKey(), + billID: text("billID").notNull().references(() => bills.id, { onDelete: "cascade" }), + userID: text("userID").notNull().references(() => users.id, { onDelete: "cascade" }), + amount: numeric("amount").notNull(), + status: billStatusEnum("status").notNull(), + paymentType: billPaymentTypeEnum("paymentType"), + paidAt: timestamp("paidAt"), + attachmentUrl: text("attachmentUrl"), + } +) + +export const billReminders = pgTable( + "billReminders", + { + id: text("id").primaryKey(), + billID: text("billID").notNull().references(() => bills.id, { onDelete: "cascade" }), + userID: text("userID").notNull().references(() => users.id, { onDelete: "cascade" }), + reminderDate: timestamp("reminderDate").notNull(), + reminderSent: boolean("reminderSent").notNull().default(false), + } +)