Изображения в услугах, поиске, возможность открыть карточку услуги

This commit is contained in:
Халимов Рустам
2026-03-06 23:14:56 +03:00
parent d9d661a313
commit dc51097f47
167 changed files with 13977 additions and 176 deletions
+38 -10
View File
@@ -1,13 +1,13 @@
"use client";
import { useEffect, useState } from "react";
import { getMyOffers, Offer } from "@/shared/api/catalog";
import { getMyOffers, Offer, toggleOffer, deleteOffer } from "@/shared/api/catalog";
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "@/components/ui/card";
import { Button } from "@/components/ui/button";
import { toast } from "sonner";
import Link from "next/link";
import { useRouter } from "next/navigation";
import { PlusCircle, Loader2, Pencil, Trash2, PauseCircle, PlayCircle } from "lucide-react";
import { PlusCircle, Loader2, Pencil, Trash2, PauseCircle, PlayCircle, Image as ImageIcon } from "lucide-react";
import { useSessionStore } from "@/entities/session/store";
export default function MyOffersPage() {
@@ -42,6 +42,27 @@ export default function MyOffersPage() {
fetchOffers();
}, [isAuth, user, router]);
const handleToggle = async (id: string) => {
try {
const newStatus = await toggleOffer(id);
setOffers(offers.map(o => o.id === id ? { ...o, isActive: newStatus } : o));
toast.success(newStatus ? "Услуга активирована" : "Услуга приостановлена");
} catch {
toast.error("Не удалось изменить статус услуги");
}
};
const handleDelete = async (id: string) => {
if (!confirm("Вы уверены, что хотите удалить эту услугу?")) return;
try {
await deleteOffer(id);
setOffers(offers.filter(o => o.id !== id));
toast.success("Услуга удалена");
} catch {
toast.error("Не удалось удалить услугу");
}
};
if (loading) {
return (
<div className="flex justify-center items-center h-48">
@@ -104,6 +125,11 @@ export default function MyOffersPage() {
</CardDescription>
</CardHeader>
<CardContent className={`flex-1 ${!offer.isActive && "opacity-70 grayscale"}`}>
{offer.images && offer.images.length > 0 && (
<div className="w-full h-32 mb-4 rounded-md bg-muted overflow-hidden relative">
<img src={offer.images[0]} className="w-full h-full object-cover" alt="Primary image" />
</div>
)}
<p className="text-sm text-foreground/80 line-clamp-3 mb-4 leading-relaxed">
{offer.description}
</p>
@@ -115,19 +141,21 @@ export default function MyOffersPage() {
</div>
</CardContent>
<CardFooter className="flex gap-2 justify-end bg-muted/20 pt-4 mt-auto border-t">
<Button variant="outline" size="sm" className="group flex items-center gap-0 overflow-hidden px-2 hover:px-3 hover:bg-primary/10 border-transparent hover:border-primary/20 text-muted-foreground hover:text-primary transition-all duration-300 ease-out">
<Pencil className="h-4 w-4 shrink-0" />
<span className="max-w-0 overflow-hidden whitespace-nowrap opacity-0 group-hover:max-w-[120px] group-hover:opacity-100 group-hover:ml-2 transition-all duration-300 ease-out">
Редактировать
</span>
</Button>
<Button variant="outline" size="sm" className="group flex items-center gap-0 overflow-hidden px-2 hover:px-3 hover:bg-orange-500/10 border-transparent hover:border-orange-500/20 text-muted-foreground hover:text-orange-500 transition-all duration-300 ease-out" onClick={() => toast.info("Функция паузы в разработке")}>
<Link href={`/dashboard/offers/${offer.id}/edit`}>
<Button variant="outline" size="sm" className="group flex items-center gap-0 overflow-hidden px-2 hover:px-3 hover:bg-primary/10 border-transparent hover:border-primary/20 text-muted-foreground hover:text-primary transition-all duration-300 ease-out">
<Pencil className="h-4 w-4 shrink-0" />
<span className="max-w-0 overflow-hidden whitespace-nowrap opacity-0 group-hover:max-w-[120px] group-hover:opacity-100 group-hover:ml-2 transition-all duration-300 ease-out">
Редактировать
</span>
</Button>
</Link>
<Button variant="outline" size="sm" className="group flex items-center gap-0 overflow-hidden px-2 hover:px-3 hover:bg-orange-500/10 border-transparent hover:border-orange-500/20 text-muted-foreground hover:text-orange-500 transition-all duration-300 ease-out" onClick={() => handleToggle(offer.id)}>
{offer.isActive ? <PauseCircle className="h-4 w-4 shrink-0" /> : <PlayCircle className="h-4 w-4 shrink-0" />}
<span className="max-w-0 overflow-hidden whitespace-nowrap opacity-0 group-hover:max-w-[120px] group-hover:opacity-100 group-hover:ml-2 transition-all duration-300 ease-out">
{offer.isActive ? "Приостановить" : "Активировать"}
</span>
</Button>
<Button variant="outline" size="sm" className="group flex items-center gap-0 overflow-hidden px-2 hover:px-3 hover:bg-destructive/10 border-transparent hover:border-destructive/20 text-muted-foreground hover:text-destructive transition-all duration-300 ease-out" onClick={() => toast.info("Функция удаления в разработке")}>
<Button variant="outline" size="sm" className="group flex items-center gap-0 overflow-hidden px-2 hover:px-3 hover:bg-destructive/10 border-transparent hover:border-destructive/20 text-muted-foreground hover:text-destructive transition-all duration-300 ease-out" onClick={() => handleDelete(offer.id)}>
<Trash2 className="h-4 w-4 shrink-0" />
<span className="max-w-0 overflow-hidden whitespace-nowrap opacity-0 group-hover:max-w-[100px] group-hover:opacity-100 group-hover:ml-2 transition-all duration-300 ease-out">
Удалить