did more stuff
This commit is contained in:
		@@ -1,18 +1,73 @@
 | 
				
			|||||||
"use client"
 | 
					"use client"
 | 
				
			||||||
import * as React from "react"
 | 
					import * as React from "react"
 | 
				
			||||||
import { Calendar } from "~/components/ui/BillTrackerCalendar"
 | 
					import { Calendar } from "~/components/ui/BillTrackerCalendar"
 | 
				
			||||||
 | 
					import { Button } from "~/components/ui/button"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default function BillTrackerCalendar() {
 | 
					export default function BillTrackerCalendar() {
 | 
				
			||||||
  const [date, setDate] = React.useState<Date | undefined>(new Date())
 | 
					  const [selectedDate, setSelectedDate] = React.useState<Date | undefined>(undefined)
 | 
				
			||||||
 | 
					  const [isOpen, setIsOpen] = React.useState(false)
 | 
				
			||||||
 | 
					  const calendarRef = React.useRef<HTMLDivElement>(null)
 | 
				
			||||||
 | 
					  const popoverRef = React.useRef<HTMLDivElement>(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 (
 | 
					  return (
 | 
				
			||||||
    <div className="m-auto p-2">
 | 
					    <div className="m-auto p-2 relative" ref={calendarRef}>
 | 
				
			||||||
      <Calendar
 | 
					      <Calendar
 | 
				
			||||||
        mode="single"
 | 
					        mode="single"
 | 
				
			||||||
        selected={date}
 | 
					        selected={selectedDate}
 | 
				
			||||||
        onSelect={setDate}
 | 
					        onSelect={handleSelect}
 | 
				
			||||||
        className="rounded-md border m-auto"
 | 
					        className="rounded-md border m-auto"
 | 
				
			||||||
      />
 | 
					      />
 | 
				
			||||||
 | 
					      {isOpen && selectedDate && (
 | 
				
			||||||
 | 
					        <div 
 | 
				
			||||||
 | 
					          ref={popoverRef}
 | 
				
			||||||
 | 
					          className="absolute top-full left-1/2 transform -translate-x-1/2 border rounded-lg shadow-lg px-4 pb-4 w-80"
 | 
				
			||||||
 | 
					        >
 | 
				
			||||||
 | 
					          <div className="grid gap-4">
 | 
				
			||||||
 | 
					            <div className="space-y-2">
 | 
				
			||||||
 | 
					              <div className="flex flex-row w-full">
 | 
				
			||||||
 | 
					                <h3 className="font-medium leading-none text-center mx-auto mt-2 py-2 md:text-xl">
 | 
				
			||||||
 | 
					                  {selectedDate.toDateString()}
 | 
				
			||||||
 | 
					                </h3>
 | 
				
			||||||
 | 
					                <button className="justify-self-end ml-auto bg-none text-primary text-m md:text-xl"
 | 
				
			||||||
 | 
					                  onClick={() => setIsOpen(false)}
 | 
				
			||||||
 | 
					                >
 | 
				
			||||||
 | 
					                  x
 | 
				
			||||||
 | 
					                </button>
 | 
				
			||||||
 | 
					              </div>
 | 
				
			||||||
 | 
					              <p>Add your events or bills due here.</p>
 | 
				
			||||||
 | 
					            </div>
 | 
				
			||||||
 | 
					          </div>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					      )}
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
  )
 | 
					  )
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,7 +3,6 @@
 | 
				
			|||||||
import * as React from "react"
 | 
					import * as React from "react"
 | 
				
			||||||
import { ChevronLeft, ChevronRight } from "lucide-react"
 | 
					import { ChevronLeft, ChevronRight } from "lucide-react"
 | 
				
			||||||
import { DayPicker } from "react-day-picker"
 | 
					import { DayPicker } from "react-day-picker"
 | 
				
			||||||
 | 
					 | 
				
			||||||
import { cn } from "~/lib/utils"
 | 
					import { cn } from "~/lib/utils"
 | 
				
			||||||
import { buttonVariants } from "~/components/ui/button"
 | 
					import { buttonVariants } from "~/components/ui/button"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -16,15 +16,18 @@ const connectionString = process.env.DATABASE_URL ?? "";
 | 
				
			|||||||
const pool = postgres(connectionString, { max: 1 })
 | 
					const pool = postgres(connectionString, { max: 1 })
 | 
				
			||||||
export const db = drizzle(pool)
 | 
					export const db = drizzle(pool)
 | 
				
			||||||
 
 | 
					 
 | 
				
			||||||
export const frequencyEnum = pgEnum("frequency", ["Monthly", "Bi-weekly", "Weekly"])
 | 
					export const frequencyEnum = pgEnum("frequency", ["Monthly", "Bi-weekly", "Weekly"]);
 | 
				
			||||||
export const workOrderStatusEnum = pgEnum("workOrderStatus", ["Pending", "Open", "Closed"])
 | 
					export const workOrderStatusEnum = pgEnum("workOrderStatus", ["Pending", "Open", "Closed"]);
 | 
				
			||||||
export const paymentTypeEnum = pgEnum("paymentType", ["Security Deposit", "Rent", "Late Fee", "Other"])
 | 
					export const paymentTypeEnum = pgEnum("paymentType", ["Security Deposit", "Rent", "Late Fee", "Other"]);
 | 
				
			||||||
export const paymentStatusEnum = pgEnum("paymentStatus", ["Pending", "Complete", "Late", "Refunded"])
 | 
					export const paymentStatusEnum = pgEnum("paymentStatus", ["Pending", "Complete", "Late", "Refunded"]);
 | 
				
			||||||
export const preferredDaysofWeekEnum = pgEnum("preferredDaysofWeek", 
 | 
					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",
 | 
					export const propertyTypeEnum = pgEnum("propertyType", ["Apartment", "Condominium",
 | 
				
			||||||
  "Mobile Home", "Multi-Unit Home", "Single-Family Residence", "Townhouse"])
 | 
					  "Mobile Home", "Multi-Unit Home", "Single-Family Residence", "Townhouse"]
 | 
				
			||||||
export const workOrderPriorityEnum = pgEnum("workOrderPriority", ["Low", "High"])
 | 
					);
 | 
				
			||||||
 | 
					export const workOrderPriorityEnum = pgEnum("workOrderPriority", ["Low", "High"]
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
export const workOrderTypeEnum = pgEnum("workOrderType",
 | 
					export const workOrderTypeEnum = pgEnum("workOrderType",
 | 
				
			||||||
  ["Appliance Repair", "Carbon Monoxide Detector Installation", "Ceiling Fan Repair", 
 | 
					  ["Appliance Repair", "Carbon Monoxide Detector Installation", "Ceiling Fan Repair", 
 | 
				
			||||||
   "Carpentry Repair", "Door Installation/Repair", "Drywall Installation/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", 
 | 
					   "Tile Flooring", "Tree Trimming/Cutting", "Water Treatment", "Well/Water Testing", 
 | 
				
			||||||
   "Window Repair/Installation"]
 | 
					   "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(
 | 
					export const users = pgTable(
 | 
				
			||||||
  "user",
 | 
					  "user",
 | 
				
			||||||
@@ -210,3 +226,44 @@ export const emergencyContacts = pgTable(
 | 
				
			|||||||
    email: text("email"),
 | 
					    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),
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user