first commit
This commit is contained in:
122
frontend/app/admin/heroes/page.tsx
Normal file
122
frontend/app/admin/heroes/page.tsx
Normal file
@@ -0,0 +1,122 @@
|
||||
"use client"
|
||||
|
||||
import { useEffect, useState, useCallback } from "react"
|
||||
import { DataTable } from "./_components/data-table"
|
||||
import { getColumns } from "./_components/columns"
|
||||
import { Hero } from "@/types/hero"
|
||||
import { heroService } from "@/services/heroService"
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { Input } from "@/components/ui/input"
|
||||
import { Plus } from "lucide-react"
|
||||
import { HeroDialog } from "./_components/hero-dialog"
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from "@/components/ui/select"
|
||||
|
||||
export default function HeroesPage() {
|
||||
const [data, setData] = useState<Hero[]>([])
|
||||
const [loading, setLoading] = useState(true)
|
||||
const [page, setPage] = useState(1)
|
||||
const [total, setTotal] = useState(0)
|
||||
const [perPage] = useState(20)
|
||||
const [search, setSearch] = useState("")
|
||||
const [statusFilter, setStatusFilter] = useState("with") // "with" shows active + deleted
|
||||
const [showCreateDialog, setShowCreateDialog] = useState(false)
|
||||
|
||||
const fetchData = useCallback(async () => {
|
||||
setLoading(true)
|
||||
try {
|
||||
// API expects "active" logic differently perhaps?
|
||||
// checking task.md/heroService docs:
|
||||
// heroService.getHeroes(page, perPage, search, soft)
|
||||
// soft: 'only' | 'with' | empty (defaults to active in some apis, but checking service impl)
|
||||
|
||||
// From service: soft param defaults to "with".
|
||||
const apiSoftFilter = statusFilter === "active" ? "" : statusFilter
|
||||
|
||||
const res = await heroService.getHeroes(page, perPage, search, apiSoftFilter)
|
||||
setData(res.items || [])
|
||||
setTotal(res.total || 0)
|
||||
} catch (error) {
|
||||
console.error("Heroes fetch error:", error)
|
||||
setData([])
|
||||
} finally {
|
||||
setLoading(false)
|
||||
}
|
||||
}, [page, perPage, search, statusFilter])
|
||||
|
||||
useEffect(() => {
|
||||
fetchData()
|
||||
}, [fetchData])
|
||||
|
||||
const totalPages = Math.ceil(total / perPage)
|
||||
|
||||
return (
|
||||
<div className="p-8">
|
||||
<div className="flex items-center justify-between mb-6">
|
||||
<div>
|
||||
<h1 className="text-3xl font-bold tracking-tight">Hero Banner Yönetimi</h1>
|
||||
<p className="text-muted-foreground">
|
||||
Ana sayfa banner alanlarını yönetin.
|
||||
</p>
|
||||
</div>
|
||||
<Button onClick={() => setShowCreateDialog(true)}>
|
||||
<Plus className="mr-2 h-4 w-4" /> Yeni Hero
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center py-4 gap-4">
|
||||
<Input
|
||||
placeholder="Başlık ara..."
|
||||
value={search}
|
||||
onChange={(e) => setSearch(e.target.value)}
|
||||
className="max-w-sm"
|
||||
/>
|
||||
<Select value={statusFilter} onValueChange={setStatusFilter}>
|
||||
<SelectTrigger className="w-[180px]">
|
||||
<SelectValue placeholder="Durum" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="with">Tümü (Dahil)</SelectItem>
|
||||
<SelectItem value="active">Sadece Aktif</SelectItem>
|
||||
<SelectItem value="only">Sadece Silinenler</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
|
||||
<DataTable columns={getColumns(fetchData)} data={data} />
|
||||
|
||||
<div className="flex items-center justify-end space-x-2 py-4">
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={() => setPage((old) => Math.max(old - 1, 1))}
|
||||
disabled={page === 1 || loading}
|
||||
>
|
||||
Önceki
|
||||
</Button>
|
||||
<div className="text-sm text-muted-foreground">
|
||||
Sayfa {page} / {totalPages || 1}
|
||||
</div>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={() => setPage((old) => (data.length === perPage || page < totalPages ? old + 1 : old))}
|
||||
disabled={page >= totalPages || loading}
|
||||
>
|
||||
Sonraki
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<HeroDialog
|
||||
open={showCreateDialog}
|
||||
onOpenChange={setShowCreateDialog}
|
||||
onSuccess={fetchData}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user