- Remove old Confluence variables - Add NEXT_PUBLIC_API_URL for API access 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
112 lines
3.7 KiB
TypeScript
112 lines
3.7 KiB
TypeScript
'use client'
|
|
|
|
import { useState, useEffect } from 'react';
|
|
import { FilamentTable } from '../src/components/FilamentTable';
|
|
import { Filament } from '../src/types/filament';
|
|
import axios from 'axios';
|
|
|
|
export default function Home() {
|
|
const [filaments, setFilaments] = useState<Filament[]>([]);
|
|
const [loading, setLoading] = useState(true);
|
|
const [error, setError] = useState<string | null>(null);
|
|
const [lastUpdate, setLastUpdate] = useState<Date | null>(null);
|
|
const [darkMode, setDarkMode] = useState(false);
|
|
const [mounted, setMounted] = useState(false);
|
|
|
|
// Initialize dark mode from localStorage after mounting
|
|
useEffect(() => {
|
|
setMounted(true);
|
|
const saved = localStorage.getItem('darkMode');
|
|
if (saved) {
|
|
setDarkMode(JSON.parse(saved));
|
|
}
|
|
}, []);
|
|
|
|
// Update dark mode
|
|
useEffect(() => {
|
|
if (!mounted) return;
|
|
|
|
localStorage.setItem('darkMode', JSON.stringify(darkMode));
|
|
if (darkMode) {
|
|
document.documentElement.classList.add('dark');
|
|
} else {
|
|
document.documentElement.classList.remove('dark');
|
|
}
|
|
}, [darkMode, mounted]);
|
|
|
|
const fetchFilaments = async () => {
|
|
try {
|
|
setLoading(true);
|
|
setError(null);
|
|
|
|
// Use API if available, fallback to static JSON
|
|
const apiUrl = process.env.NEXT_PUBLIC_API_URL;
|
|
const url = apiUrl ? `${apiUrl}/filaments` : '/data.json';
|
|
console.log('Fetching from:', url);
|
|
console.log('API URL configured:', apiUrl);
|
|
const response = await axios.get(url);
|
|
console.log('Response data:', response.data);
|
|
setFilaments(response.data);
|
|
setLastUpdate(new Date());
|
|
} catch (err) {
|
|
setError(err instanceof Error ? err.message : 'Greška pri učitavanju filamenata');
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
};
|
|
|
|
useEffect(() => {
|
|
fetchFilaments();
|
|
|
|
// Refresh every 5 minutes
|
|
const interval = setInterval(fetchFilaments, 5 * 60 * 1000);
|
|
|
|
return () => clearInterval(interval);
|
|
}, []);
|
|
|
|
return (
|
|
<div className="min-h-screen bg-gray-50 dark:bg-gray-900 transition-colors">
|
|
<header className="bg-white dark:bg-gray-800 shadow transition-colors">
|
|
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-6">
|
|
<div className="flex justify-between items-center">
|
|
<h1 className="text-3xl font-bold text-gray-900 dark:text-white">
|
|
Filamenteka
|
|
</h1>
|
|
<div className="flex items-center gap-4">
|
|
{lastUpdate && (
|
|
<span className="text-sm text-gray-500 dark:text-gray-400">
|
|
Poslednje ažuriranje: {lastUpdate.toLocaleTimeString('sr-RS')}
|
|
</span>
|
|
)}
|
|
<button
|
|
onClick={fetchFilaments}
|
|
disabled={loading}
|
|
className="px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600 disabled:opacity-50"
|
|
>
|
|
{loading ? 'Ažuriranje...' : 'Osveži'}
|
|
</button>
|
|
{mounted && (
|
|
<button
|
|
onClick={() => setDarkMode(!darkMode)}
|
|
className="px-4 py-2 bg-gray-200 dark:bg-gray-700 text-gray-800 dark:text-gray-200 rounded hover:bg-gray-300 dark:hover:bg-gray-600 transition-colors"
|
|
title={darkMode ? 'Svetla tema' : 'Tamna tema'}
|
|
>
|
|
{darkMode ? '☀️' : '🌙'}
|
|
</button>
|
|
)}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</header>
|
|
|
|
<main className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
|
|
<FilamentTable
|
|
filaments={filaments}
|
|
loading={loading}
|
|
error={error || undefined}
|
|
/>
|
|
</main>
|
|
|
|
</div>
|
|
);
|
|
} |