Refactor Project Tasks and Task Templates pages with new UI components

- Introduced PageContainer and PageHeader components for consistent layout.
- Added SearchBar and FilterBar components for improved task filtering and searching.
- Implemented LoadingState component for better loading indication.
- Updated ProjectTasksPage to utilize new components and enhance user experience.
- Refactored TaskTemplatesPage to use PageContainer and PageHeader for better structure.
- Created FilterBar component to manage filter options dynamically.
- Added SearchBar component for searching tasks with clear functionality.
- Introduced States component for loading and error states.
This commit is contained in:
Chop
2025-06-02 23:41:49 +02:00
parent fb00c1d2d6
commit a1261b2169
11 changed files with 1283 additions and 1176 deletions

View File

@@ -5,6 +5,11 @@ import Link from "next/link";
import { Card, CardHeader, CardContent } from "@/components/ui/Card";
import Button from "@/components/ui/Button";
import Badge from "@/components/ui/Badge";
import PageContainer from "@/components/ui/PageContainer";
import PageHeader from "@/components/ui/PageHeader";
import SearchBar from "@/components/ui/SearchBar";
import FilterBar from "@/components/ui/FilterBar";
import { LoadingState } from "@/components/ui/States";
export default function ContractsMainPage() {
const [contracts, setContracts] = useState([]);
@@ -162,37 +167,75 @@ export default function ContractsMainPage() {
};
if (loading) {
return (
<div className="p-6 max-w-7xl mx-auto">
<div className="text-center">
<div className="animate-spin rounded-full h-8 w-8 border-b-2 border-blue-600 mx-auto"></div>
<p className="mt-2 text-gray-600">Ładowanie umów...</p>
</div>
</div>
<PageContainer>
<PageHeader
title="Umowy"
description="Zarządzaj swoimi umowami i kontraktami"
>
<Link href="/contracts/new">
<Button variant="primary" size="lg">
<span className="mr-2"></span>
Nowa umowa
</Button>
</Link>
</PageHeader>
<LoadingState message="Ładowanie umów..." />
</PageContainer>
);
}
const stats = getContractStats();
const filterOptions = [
{
label: "Status",
value: statusFilter,
onChange: (e) => setStatusFilter(e.target.value),
options: [
{ value: "all", label: "Wszystkie" },
{ value: "active", label: "Aktywne" },
{ value: "completed", label: "Zakończone" },
{ value: "no_end_date", label: "Bez daty końca" },
],
},
{
label: "Sortuj według",
value: sortBy,
onChange: (e) => setSortBy(e.target.value),
options: [
{ value: "contract_number", label: "Numer umowy" },
{ value: "contract_name", label: "Nazwa umowy" },
{ value: "customer", label: "Klient" },
{ value: "start_date", label: "Data rozpoczęcia" },
{ value: "finish_date", label: "Data zakończenia" },
],
},
{
label: "Kolejność",
value: sortOrder,
onChange: (e) => setSortOrder(e.target.value),
options: [
{ value: "asc", label: "Rosnąco" },
{ value: "desc", label: "Malejąco" },
],
},
];
return (
<div className="p-6 max-w-7xl mx-auto space-y-6">
{/* Header */}
<div className="flex flex-col sm:flex-row justify-between items-start sm:items-center gap-4">
<div>
<h1 className="text-3xl font-bold text-gray-900">Umowy</h1>
<p className="text-gray-600 mt-1">
Zarządzaj swoimi umowami i kontraktami
</p>
</div>{" "}
<Link
href="/contracts/new"
className="inline-flex items-center justify-center px-4 py-2 bg-blue-600 hover:bg-blue-700 text-white rounded-lg font-medium transition-colors focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2"
>
<span className="mr-2"></span>
Nowa umowa
</Link>
</div>
<PageContainer>
<PageHeader
title="Umowy"
description="Zarządzaj swoimi umowami i kontraktami"
>
<Link href="/contracts/new">
<Button variant="primary" size="lg">
<span className="mr-2"></span>
Nowa umowa
</Button>
</Link>{" "}
</PageHeader>
{/* Statistics Cards */}
<div className="grid grid-cols-1 md:grid-cols-4 gap-4">
<div className="grid grid-cols-1 md:grid-cols-4 gap-6 mb-6">
<Card>
<CardContent className="p-4">
<div className="flex items-center">
@@ -302,93 +345,17 @@ export default function ContractsMainPage() {
</p>
</div>
</div>
</CardContent>
</CardContent>{" "}
</Card>
</div>
{/* Filters and Search */}
<Card>
<CardContent className="p-4">
<div className="flex flex-col lg:flex-row gap-4">
{/* Search */}
<div className="flex-1">
<label
htmlFor="search"
className="block text-sm font-medium text-gray-700 mb-1"
>
Wyszukaj
</label>
<input
id="search"
type="text"
placeholder="Szukaj po numerze, nazwie, kliencie lub inwestorze..."
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent"
/>
</div>
{/* Status Filter */}
<div className="w-full lg:w-48">
<label
htmlFor="status"
className="block text-sm font-medium text-gray-700 mb-1"
>
Status
</label>
<select
id="status"
value={statusFilter}
onChange={(e) => setStatusFilter(e.target.value)}
className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent"
>
<option value="all">Wszystkie</option>
<option value="active">Aktywne</option>
<option value="completed">Zakończone</option>
<option value="no_end_date">W trakcie</option>
</select>
</div>
{/* Sort */}
<div className="w-full lg:w-48">
<label
htmlFor="sort"
className="block text-sm font-medium text-gray-700 mb-1"
>
Sortuj według
</label>
<select
id="sort"
value={`${sortBy}-${sortOrder}`}
onChange={(e) => {
const [field, order] = e.target.value.split("-");
setSortBy(field);
setSortOrder(order);
}}
className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent"
>
<option value="contract_number-asc">Numer umowy (A-Z)</option>
<option value="contract_number-desc">Numer umowy (Z-A)</option>
<option value="contract_name-asc">Nazwa (A-Z)</option>
<option value="contract_name-desc">Nazwa (Z-A)</option>
<option value="customer-asc">Klient (A-Z)</option>
<option value="customer-desc">Klient (Z-A)</option>
<option value="date_signed-desc">
Data zawarcia (najnowsze)
</option>
<option value="date_signed-asc">
Data zawarcia (najstarsze)
</option>
<option value="finish_date-desc">
Data zakończenia (najnowsze)
</option>
<option value="finish_date-asc">
Data zakończenia (najstarsze)
</option>
</select>
</div>
</div>
</CardContent>
</Card>{" "}
<SearchBar
searchTerm={searchTerm}
onSearchChange={handleSearchChange}
placeholder="Szukaj umów po numerze, nazwie, kliencie lub inwestorze..."
resultsCount={filteredContracts.length}
resultsText="umów"
/>
<FilterBar filters={filterOptions} className="mb-6" />{" "}
{/* Contracts List */}
{filteredContracts.length === 0 ? (
<Card>
@@ -624,9 +591,9 @@ export default function ContractsMainPage() {
Wyczyść filtry
</button>
)}
</p>
</p>{" "}
</div>
)}
</div>
</PageContainer>
);
}