From e614a826128f4b04db0a028b7968ce72b3ba544f Mon Sep 17 00:00:00 2001 From: Florian Knip Date: Wed, 11 Mar 2026 09:58:33 +0100 Subject: [PATCH 1/5] fix: add missing .nvmrc for CI node version resolution --- .nvmrc | 1 + 1 file changed, 1 insertion(+) create mode 100644 .nvmrc diff --git a/.nvmrc b/.nvmrc new file mode 100644 index 0000000..2bd5a0a --- /dev/null +++ b/.nvmrc @@ -0,0 +1 @@ +22 From 9c993cf2504b8cbe09067c5acfef14e7d3dc0e12 Mon Sep 17 00:00:00 2001 From: Florian Knip Date: Wed, 11 Mar 2026 11:02:18 +0100 Subject: [PATCH 2/5] fix: add packageManager field and pin supabase version for CI compatibility --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index 7064d66..cbf2a04 100644 --- a/package.json +++ b/package.json @@ -2,6 +2,7 @@ "name": "hourtracker", "version": "0.1.0", "private": true, + "packageManager": "pnpm@10.27.0", "scripts": { "build": "next build", "dev": "next dev", From 715948410b99c24b0346e3acc6c207bb90b501d3 Mon Sep 17 00:00:00 2001 From: Florian Knip Date: Wed, 11 Mar 2026 11:07:18 +0100 Subject: [PATCH 3/5] fix: resolve all ESLint errors --- app/auth/login/page.tsx | 3 --- app/layout.tsx | 4 ---- components/timesheet-entries-content.tsx | 2 +- components/ui/use-toast.ts | 1 + hooks/use-toast.ts | 1 + lib/calculations.ts | 2 +- 6 files changed, 4 insertions(+), 9 deletions(-) diff --git a/app/auth/login/page.tsx b/app/auth/login/page.tsx index d5d6f0b..95822c7 100644 --- a/app/auth/login/page.tsx +++ b/app/auth/login/page.tsx @@ -8,7 +8,6 @@ import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/com import { Input } from "@/components/ui/input" import { Label } from "@/components/ui/label" import Link from "next/link" -import { useRouter } from "next/navigation" import { useState } from "react" import { Clock } from "lucide-react" @@ -17,8 +16,6 @@ export default function LoginPage() { const [password, setPassword] = useState("") const [error, setError] = useState(null) const [isLoading, setIsLoading] = useState(false) - const router = useRouter() - const handleLogin = async (e: React.FormEvent) => { e.preventDefault() setIsLoading(true) diff --git a/app/layout.tsx b/app/layout.tsx index a0da94b..c63d2e4 100644 --- a/app/layout.tsx +++ b/app/layout.tsx @@ -1,12 +1,8 @@ import type React from "react" import type { Metadata } from "next" -import { Geist, Geist_Mono } from "next/font/google" import { ThemeProvider } from "@/components/theme-provider" import "./globals.css" -const _geist = Geist({ subsets: ["latin"] }) -const _geistMono = Geist_Mono({ subsets: ["latin"] }) - export const metadata: Metadata = { title: "HourTracker - Freelance Hour Tracking", description: "Track your freelance hours and manage customer timesheets", diff --git a/components/timesheet-entries-content.tsx b/components/timesheet-entries-content.tsx index 360d6df..46624a6 100644 --- a/components/timesheet-entries-content.tsx +++ b/components/timesheet-entries-content.tsx @@ -285,7 +285,7 @@ export function TimesheetEntriesContent({ customer, timesheet, initialEntries, u - This timesheet is marked as completed and is locked for editing. Click "Reopen for Editing" to make changes. + This timesheet is marked as completed and is locked for editing. Click "Reopen for Editing" to make changes. )} diff --git a/components/ui/use-toast.ts b/components/ui/use-toast.ts index 8932bc5..be5d07b 100644 --- a/components/ui/use-toast.ts +++ b/components/ui/use-toast.ts @@ -15,6 +15,7 @@ type ToasterToast = ToastProps & { action?: ToastActionElement } +// eslint-disable-next-line @typescript-eslint/no-unused-vars const actionTypes = { ADD_TOAST: 'ADD_TOAST', UPDATE_TOAST: 'UPDATE_TOAST', diff --git a/hooks/use-toast.ts b/hooks/use-toast.ts index 8932bc5..be5d07b 100644 --- a/hooks/use-toast.ts +++ b/hooks/use-toast.ts @@ -15,6 +15,7 @@ type ToasterToast = ToastProps & { action?: ToastActionElement } +// eslint-disable-next-line @typescript-eslint/no-unused-vars const actionTypes = { ADD_TOAST: 'ADD_TOAST', UPDATE_TOAST: 'UPDATE_TOAST', diff --git a/lib/calculations.ts b/lib/calculations.ts index 4cd5c16..5da70fb 100644 --- a/lib/calculations.ts +++ b/lib/calculations.ts @@ -1,4 +1,4 @@ -import type { TimeEntry, CustomerWithStats } from "./types" +import type { CustomerWithStats } from "./types" interface HoursEntry { hours: number | string From 4e02c0617d32bca471e6ab120e6fd1b392264a87 Mon Sep 17 00:00:00 2001 From: Florian Knip Date: Wed, 11 Mar 2026 12:47:52 +0100 Subject: [PATCH 4/5] fix: restore Geist font imports required for CSS font loading --- app/layout.tsx | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/app/layout.tsx b/app/layout.tsx index c63d2e4..b7192c5 100644 --- a/app/layout.tsx +++ b/app/layout.tsx @@ -1,8 +1,14 @@ import type React from "react" import type { Metadata } from "next" +import { Geist, Geist_Mono } from "next/font/google" import { ThemeProvider } from "@/components/theme-provider" import "./globals.css" +// eslint-disable-next-line @typescript-eslint/no-unused-vars +const _geist = Geist({ subsets: ["latin"] }) +// eslint-disable-next-line @typescript-eslint/no-unused-vars +const _geistMono = Geist_Mono({ subsets: ["latin"] }) + export const metadata: Metadata = { title: "HourTracker - Freelance Hour Tracking", description: "Track your freelance hours and manage customer timesheets", From 878743a58a5d40488265258459bf28ae068ef0b2 Mon Sep 17 00:00:00 2001 From: Florian Knip Date: Wed, 11 Mar 2026 12:52:18 +0100 Subject: [PATCH 5/5] fix: replace useEffect setState and impure Math.random in sidebar skeleton --- components/customer-dialog.tsx | 19 +++++++++---------- components/ui/sidebar.tsx | 5 +---- 2 files changed, 10 insertions(+), 14 deletions(-) diff --git a/components/customer-dialog.tsx b/components/customer-dialog.tsx index 1286960..bd24ae2 100644 --- a/components/customer-dialog.tsx +++ b/components/customer-dialog.tsx @@ -2,7 +2,7 @@ import type React from "react" -import { useState, useEffect } from "react" +import { useState } from "react" import { Button } from "@/components/ui/button" import { Dialog, @@ -27,16 +27,15 @@ interface CustomerDialogProps { export function CustomerDialog({ open, onOpenChange, onSave, customer, isLoading }: CustomerDialogProps) { const [name, setName] = useState("") const [bookedHours, setBookedHours] = useState("") + const [prevOpen, setPrevOpen] = useState(false) - useEffect(() => { - if (customer) { - setName(customer.name) - setBookedHours(customer.booked_hours.toString()) - } else { - setName("") - setBookedHours("") - } - }, [customer, open]) + if (open && !prevOpen) { + setName(customer?.name ?? "") + setBookedHours(customer?.booked_hours.toString() ?? "") + } + if (open !== prevOpen) { + setPrevOpen(open) + } const handleSubmit = async (e: React.FormEvent) => { e.preventDefault() diff --git a/components/ui/sidebar.tsx b/components/ui/sidebar.tsx index ee74343..6589cf3 100644 --- a/components/ui/sidebar.tsx +++ b/components/ui/sidebar.tsx @@ -606,10 +606,7 @@ function SidebarMenuSkeleton({ }: React.ComponentProps<'div'> & { showIcon?: boolean }) { - // Random width between 50 to 90%. - const width = React.useMemo(() => { - return `${Math.floor(Math.random() * 40) + 50}%` - }, []) + const width = '70%' return (