Files
Condopay/pages/FamilyList.tsx
frakarr 79e249b638 feat: Setup project with Vite and React
Initializes the Condopay frontend project using Vite, React, and TypeScript. Includes basic project structure, dependencies, and configuration for Tailwind CSS and React Router.
2025-12-06 18:55:48 +01:00

102 lines
4.2 KiB
TypeScript

import React, { useEffect, useState } from 'react';
import { Link } from 'react-router-dom';
import { CondoService } from '../services/mockDb';
import { Family, AppSettings } from '../types';
import { Search, ChevronRight, UserCircle } from 'lucide-react';
export const FamilyList: React.FC = () => {
const [families, setFamilies] = useState<Family[]>([]);
const [loading, setLoading] = useState(true);
const [searchTerm, setSearchTerm] = useState('');
const [settings, setSettings] = useState<AppSettings | null>(null);
useEffect(() => {
const fetchData = async () => {
try {
CondoService.seedPayments();
const [fams, sets] = await Promise.all([
CondoService.getFamilies(),
CondoService.getSettings()
]);
setFamilies(fams);
setSettings(sets);
} catch (e) {
console.error("Error fetching data", e);
} finally {
setLoading(false);
}
};
fetchData();
}, []);
const filteredFamilies = families.filter(f =>
f.name.toLowerCase().includes(searchTerm.toLowerCase()) ||
f.unitNumber.toLowerCase().includes(searchTerm.toLowerCase())
);
if (loading) {
return <div className="flex justify-center items-center h-64 text-slate-400">Caricamento in corso...</div>;
}
return (
<div className="space-y-6">
{/* Responsive Header */}
<div className="flex flex-col md:flex-row md:items-end justify-between gap-4">
<div>
<h2 className="text-2xl font-bold text-slate-800">Elenco Condomini</h2>
<p className="text-slate-500 text-sm md:text-base">{settings?.condoName || 'Gestione Condominiale'}</p>
</div>
<div className="relative w-full md:w-80 lg:w-96">
<div className="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
<Search className="h-5 w-5 text-slate-400" />
</div>
<input
type="text"
className="block w-full pl-10 pr-3 py-2.5 border border-slate-300 rounded-xl leading-5 bg-white placeholder-slate-400 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500 transition duration-150 ease-in-out sm:text-sm shadow-sm"
placeholder="Cerca nome o interno..."
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
/>
</div>
</div>
{/* List */}
<div className="bg-white shadow-sm rounded-xl overflow-hidden border border-slate-200">
<ul className="divide-y divide-slate-100">
{filteredFamilies.length === 0 ? (
<li className="p-8 text-center text-slate-500 flex flex-col items-center gap-2">
<Search className="w-8 h-8 text-slate-300" />
<span>Nessuna famiglia trovata.</span>
</li>
) : (
filteredFamilies.map((family) => (
<li key={family.id} className="hover:bg-slate-50 transition-colors active:bg-slate-100">
<Link to={`/family/${family.id}`} className="block p-4 sm:p-5">
<div className="flex items-center justify-between gap-3">
<div className="flex items-center gap-3 sm:gap-4 overflow-hidden">
<div className="bg-blue-100 p-2 sm:p-2.5 rounded-full flex-shrink-0">
<UserCircle className="w-6 h-6 sm:w-8 sm:h-8 text-blue-600" />
</div>
<div className="min-w-0">
<p className="text-base sm:text-lg font-semibold text-blue-600 truncate">
{family.name}
</p>
<p className="flex items-center text-sm text-slate-500 truncate">
Interno: <span className="font-medium text-slate-700 ml-1">{family.unitNumber}</span>
</p>
</div>
</div>
<div className="flex-shrink-0">
<ChevronRight className="h-5 w-5 text-slate-400" />
</div>
</div>
</Link>
</li>
))
)}
</ul>
</div>
</div>
);
};