feat: Add search and pagination to Prompts page

This commit is contained in:
gpt-engineer-app[bot]
2025-10-29 14:01:08 +00:00
parent 0b96ab51fb
commit a7defc1944
+138 -4
View File
@@ -1,11 +1,26 @@
import { useState } from "react";
import { useState, useMemo } from "react";
import { PromptCard } from "@/components/prompts/PromptCard";
import { CreatePromptDialog } from "@/components/prompts/CreatePromptDialog";
import { Button } from "@/components/ui/button";
import { Plus } from "lucide-react";
import { Input } from "@/components/ui/input";
import {
Pagination,
PaginationContent,
PaginationEllipsis,
PaginationItem,
PaginationLink,
PaginationNext,
PaginationPrevious,
} from "@/components/ui/pagination";
import { Plus, Search } from "lucide-react";
const ITEMS_PER_PAGE = 6;
export default function Prompts() {
const [isCreateDialogOpen, setIsCreateDialogOpen] = useState(false);
const [searchQuery, setSearchQuery] = useState("");
const [currentPage, setCurrentPage] = useState(1);
const [prompts] = useState([
{
id: 1,
@@ -35,11 +50,54 @@ export default function Prompts() {
lastModified: "3 dias atrás",
status: "published" as const,
},
{
id: 5,
title: "Prompt de Suporte Técnico",
creator: "Carlos Mendes",
lastModified: "4 dias atrás",
status: "published" as const,
},
{
id: 6,
title: "Prompt de Onboarding",
creator: "Fernanda Silva",
lastModified: "6 dias atrás",
status: "draft" as const,
},
{
id: 7,
title: "Prompt de Follow-up",
creator: "Rafael Santos",
lastModified: "1 dia atrás",
status: "published" as const,
},
]);
// Filtra prompts baseado na pesquisa
const filteredPrompts = useMemo(() => {
if (!searchQuery.trim()) return prompts;
const query = searchQuery.toLowerCase();
return prompts.filter(prompt =>
prompt.title.toLowerCase().includes(query) ||
prompt.creator.toLowerCase().includes(query)
);
}, [prompts, searchQuery]);
// Calcula paginação
const totalPages = Math.ceil(filteredPrompts.length / ITEMS_PER_PAGE);
const startIndex = (currentPage - 1) * ITEMS_PER_PAGE;
const paginatedPrompts = filteredPrompts.slice(startIndex, startIndex + ITEMS_PER_PAGE);
// Reset para primeira página quando busca muda
const handleSearchChange = (value: string) => {
setSearchQuery(value);
setCurrentPage(1);
};
return (
<div className="animate-fade-in">
<div className="flex items-center justify-between mb-8">
<div className="flex items-center justify-between mb-6">
<div>
<h1 className="text-3xl font-bold text-foreground mb-2">Gestão de Prompts</h1>
<p className="text-muted-foreground">
@@ -52,8 +110,29 @@ export default function Prompts() {
</Button>
</div>
<div className="mb-6">
<div className="relative max-w-md">
<Search className="absolute left-3 top-1/2 transform -translate-y-1/2 text-muted-foreground h-4 w-4" />
<Input
placeholder="Pesquisar prompts por título ou criador..."
value={searchQuery}
onChange={(e) => handleSearchChange(e.target.value)}
className="pl-10"
/>
</div>
<p className="text-sm text-muted-foreground mt-2">
{filteredPrompts.length} {filteredPrompts.length === 1 ? 'prompt encontrado' : 'prompts encontrados'}
</p>
</div>
{paginatedPrompts.length === 0 ? (
<div className="text-center py-12">
<p className="text-muted-foreground">Nenhum prompt encontrado com os critérios de busca.</p>
</div>
) : (
<>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
{prompts.map((prompt) => (
{paginatedPrompts.map((prompt) => (
<PromptCard
key={prompt.id}
title={prompt.title}
@@ -68,6 +147,61 @@ export default function Prompts() {
))}
</div>
{totalPages > 1 && (
<div className="mt-8">
<Pagination>
<PaginationContent>
<PaginationItem>
<PaginationPrevious
onClick={() => setCurrentPage(prev => Math.max(1, prev - 1))}
className={currentPage === 1 ? "pointer-events-none opacity-50" : "cursor-pointer"}
/>
</PaginationItem>
{Array.from({ length: totalPages }, (_, i) => i + 1).map((page) => {
// Mostrar primeira página, última página e páginas próximas à atual
if (
page === 1 ||
page === totalPages ||
(page >= currentPage - 1 && page <= currentPage + 1)
) {
return (
<PaginationItem key={page}>
<PaginationLink
onClick={() => setCurrentPage(page)}
isActive={currentPage === page}
className="cursor-pointer"
>
{page}
</PaginationLink>
</PaginationItem>
);
} else if (
page === currentPage - 2 ||
page === currentPage + 2
) {
return (
<PaginationItem key={page}>
<PaginationEllipsis />
</PaginationItem>
);
}
return null;
})}
<PaginationItem>
<PaginationNext
onClick={() => setCurrentPage(prev => Math.min(totalPages, prev + 1))}
className={currentPage === totalPages ? "pointer-events-none opacity-50" : "cursor-pointer"}
/>
</PaginationItem>
</PaginationContent>
</Pagination>
</div>
)}
</>
)}
<CreatePromptDialog
open={isCreateDialogOpen}
onOpenChange={setIsCreateDialogOpen}