feat(dashboard): setting up layout

This commit is contained in:
2025-11-12 16:51:59 +02:00
parent b8b2a15ee9
commit a3f46b6b38
61 changed files with 2957 additions and 123 deletions
@@ -0,0 +1,30 @@
import { TZDate } from "@date-fns/tz";
import { eachDayOfInterval, endOfMonth, endOfWeek, startOfMonth, startOfWeek } from "date-fns";
export function useCalendarDates(currentDate: Date, weekStartsOnMonday: boolean) {
const monthStart = startOfMonth(currentDate);
const monthEnd = endOfMonth(currentDate);
const calendarStart = startOfWeek(monthStart, {
weekStartsOn: weekStartsOnMonday ? 1 : 0,
});
const calendarEnd = endOfWeek(monthEnd, {
weekStartsOn: weekStartsOnMonday ? 1 : 0,
});
const calendarDays = eachDayOfInterval({
end: calendarEnd,
start: calendarStart,
}).map((date) => new TZDate(date, "UTC"));
const firstWeek = eachDayOfInterval({
end: endOfWeek(calendarStart, { weekStartsOn: weekStartsOnMonday ? 1 : 0 }),
start: calendarStart,
}).map((date) => new TZDate(date, "UTC"));
return {
calendarDays,
calendarEnd,
calendarStart,
firstWeek,
monthEnd,
monthStart,
};
}
@@ -0,0 +1,69 @@
"use client";
import { useCallback, useEffect, useState } from "react";
// Original useLocalStorage hook (useState-like API)
export function useLocalStorage<T>(
key: string,
initialValue: T,
): [T, (value: T | ((val: T) => T)) => void] {
// Initialize state with a function to handle SSR
const [localState, setLocalState] = useState<T>(() => {
// Check if we're in a browser environment
if (typeof window === "undefined") {
return initialValue;
}
try {
// Get from local storage by key
const item = window.localStorage.getItem(key);
// Parse stored json or if none return initialValue
return item ? JSON.parse(item) : initialValue;
} catch (error) {
console.warn(`Error reading localStorage key "${key}":`, error);
return initialValue;
}
});
// Return a wrapped version of useState's setter function that persists the new value to localStorage
const handleSetState = useCallback(
(value: T | ((val: T) => T)) => {
try {
// Allow value to be a function so we have same API as useState
const valueToStore = value instanceof Function ? value(localState) : value;
// Save state
setLocalState(valueToStore);
// Save to local storage
if (typeof window !== "undefined") {
window.localStorage.setItem(key, JSON.stringify(valueToStore));
}
} catch (error) {
console.warn(`Error setting localStorage key "${key}":`, error);
}
},
[key, localState],
);
useEffect(() => {
// Handle storage changes in other tabs/windows
function handleStorageChange(event: StorageEvent) {
if (event.key === key && event.newValue) {
setLocalState(JSON.parse(event.newValue));
}
}
// Subscribe to storage changes
if (typeof window !== "undefined") {
window.addEventListener("storage", handleStorageChange);
}
// Cleanup the event listener on component unmount
return () => {
if (typeof window !== "undefined") {
window.removeEventListener("storage", handleStorageChange);
}
};
}, [key]);
return [localState, handleSetState];
}
+14
View File
@@ -0,0 +1,14 @@
/** biome-ignore-all lint/suspicious/noExplicitAny: This is a hook file */
import { zodResolver } from "@hookform/resolvers/zod";
import { type Resolver, type UseFormProps, useForm } from "react-hook-form";
import type { z } from "zod";
export const useZodForm = <T extends z.ZodType<any, any>>(
schema: T,
options?: Omit<UseFormProps<z.infer<T>>, "resolver">,
) => {
return useForm<z.infer<T>>({
resolver: zodResolver(schema) as unknown as Resolver<z.infer<T>, any, z.infer<T>>,
...options,
});
};