Files
003-fleet-management/biljeske/SKELETON_LIST_VIEW.md
2026-05-26 06:29:06 +00:00

3.5 KiB

Skeleton za List View

// src/components/common/UniversalList.jsx
import { h } from 'preact';
import { useEffect, useState } from 'preact/hooks';
import { useStore } from '@nanostores/preact';
import { getBaseUrl } from '../lib/nav';
import LoadingSpinner from './LoadingSpinner.jsx';

export default function UniversalList({ store, setter, fetchMethod, limit, baseName, children }) {
  const [loading, setLoading] = useState(true);
  const list = useStore(store);
  
  // Ako je baseName poslan, dohvati URL, inače ostavi undefined
  const baseUrl = baseName ? getBaseUrl(baseName) : undefined;

  useEffect(() => {
    async function fetchData() {
      if (list.length > 0) {
        setLoading(false);
        return;
      }

      try {
        setLoading(true);
        const data = await fetchMethod();
        setter(data || []);
      } catch (error) {
        console.error("Greška pri dohvatu:", error);
        setter([]);
      } finally {
        setTimeout(() => setLoading(false), 1000);
      }
    }
    fetchData();
  }, []);

  if (loading) return <LoadingSpinner text="Učitavanje..." />;

  const displayList = limit ? list.slice(0, limit) : list;

  return (
    <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
      {/* children funkcija sada prima item i opcionalni baseUrl */}
      {displayList.map(item => children(item, baseUrl))}
    </div>
  );
}

Loading komponenta

// src/components/common/LoadingSpinner.jsx
import { h } from 'preact';

export default function LoadingSpinner({ text = "Učitavanje podataka..." }) {
  return (
    <div class="flex items-center justify-center p-12 text-gray-500">
      <div class="animate-spin mr-3 h-5 w-5 border-2 border-gray-400 border-t-transparent rounded-full"></div>
      {text}
    </div>
  );
}

Komponenta FleetStrojeviLista.jsx koristi Skeleton

/// src/components/fleet/FleetStrojeviLista.jsx
import { h } from 'preact';
import UniversalList from '../common/UniversalList.jsx';
import { strojevi, setStrojevi } from '../stores/fleetStore';
import { getStrojevi } from '../lib/api';

export default function FleetStrojeviLista({ limit = 10 }) {
  return (
    <UniversalList 
      store={strojevi} 
      setter={setStrojevi} 
      fetchMethod={getStrojevi}
      baseName="Registrirani strojevi"
      limit={limit}
    >
      {(s, baseUrl) => (
        <div key={s.id} class="p-6 border border-gray-200 rounded-2xl bg-white shadow-sm hover:shadow-md transition-shadow">
          <div class="flex justify-between items-start mb-4">
            <h3 class="text-xl font-black text-gray-900">{s.naziv}</h3>
            <span class="px-2 py-1 bg-blue-100 text-blue-800 text-xs font-bold rounded-full uppercase">
              {s.tip_human_readable}
            </span>
          </div>

          <ul class="text-sm text-gray-600 space-y-1 mb-4">
            <li><strong>Marka/Model:</strong> {s.marka} {s.model_stroja}</li>
            <li><strong>Serijski br:</strong> {s.serijski_broj}</li>
            <li><strong>Vlasnik:</strong> {s.vlasnik_naziv}</li>
            <li><strong>Radni sati:</strong> {s.radni_sati} h</li>
            {s.registracija && <li><strong>Reg:</strong> {s.registracija}</li>}
          </ul>

          <a 
            href={`${baseUrl}/${s.id}`} 
            class="block text-center w-full py-2 bg-gray-900 text-white rounded-lg hover:bg-gray-700 transition"
          >
            Pregled detalja
          </a>
        </div>
      )}
    </UniversalList>
  );
}