All checks were successful
Deploy to Coolify / deploy (push) Successful in 44s
- Next.js 14 + TypeScript + Tailwind CSS - Glassmorphism design with ambient orbs - Cards: Light x2, Temperature, AirPurifier, Tasks, Weather, Savings - Home Assistant integration (demo mode if no token) - Vikunja tasks API - Pulse savings API - wttr.in weather - Framer Motion animations - Dark/light theme toggle - Bottom navigation - Dockerfile for deployment
80 lines
1.8 KiB
TypeScript
80 lines
1.8 KiB
TypeScript
"use client";
|
|
|
|
import { useState, useEffect, useCallback } from "react";
|
|
import { HAStates } from "@/lib/ha";
|
|
|
|
export function useHA(refreshInterval = 10000) {
|
|
const [data, setData] = useState<HAStates | null>(null);
|
|
const [loading, setLoading] = useState(true);
|
|
|
|
const refresh = useCallback(async () => {
|
|
try {
|
|
const res = await fetch("/api/ha", { cache: "no-store" });
|
|
const json = await res.json();
|
|
setData(json);
|
|
} catch (e) {
|
|
console.error("HA fetch failed", e);
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
}, []);
|
|
|
|
useEffect(() => {
|
|
refresh();
|
|
const id = setInterval(refresh, refreshInterval);
|
|
return () => clearInterval(id);
|
|
}, [refresh, refreshInterval]);
|
|
|
|
return { data, loading, refresh };
|
|
}
|
|
|
|
export function useWeather() {
|
|
const [weather, setWeather] = useState<any>(null);
|
|
|
|
useEffect(() => {
|
|
fetch("/api/weather")
|
|
.then((r) => r.json())
|
|
.then(setWeather)
|
|
.catch(() => {});
|
|
}, []);
|
|
|
|
return weather;
|
|
}
|
|
|
|
export function useTasks() {
|
|
const [tasks, setTasks] = useState<any[]>([]);
|
|
const [demo, setDemo] = useState(false);
|
|
|
|
const refresh = useCallback(async () => {
|
|
try {
|
|
const res = await fetch("/api/tasks", { cache: "no-store" });
|
|
const json = await res.json();
|
|
setTasks(json.tasks || []);
|
|
setDemo(!!json.demo);
|
|
} catch (e) {}
|
|
}, []);
|
|
|
|
useEffect(() => {
|
|
refresh();
|
|
}, [refresh]);
|
|
|
|
return { tasks, setTasks, demo, refresh };
|
|
}
|
|
|
|
export function useSavings() {
|
|
const [savings, setSavings] = useState<any[]>([]);
|
|
const [demo, setDemo] = useState(false);
|
|
|
|
useEffect(() => {
|
|
fetch("/api/savings")
|
|
.then((r) => r.json())
|
|
.then((d) => {
|
|
setSavings(d.savings || []);
|
|
setDemo(!!d.demo);
|
|
})
|
|
.catch(() => {});
|
|
}, []);
|
|
|
|
return { savings, demo };
|
|
}
|