feat(Nextjs): Custom Layout delete endpoint & ui implemented

This commit is contained in:
shiva raj badu 2025-08-04 18:08:00 +05:45
parent d9a46fdff3
commit 8495d2b8d1
No known key found for this signature in database
5 changed files with 63 additions and 7 deletions

View file

@ -73,6 +73,11 @@ class GetLayoutsResponse(BaseModel):
message: Optional[str] = None
class DeleteLayoutResponse(BaseModel):
success: bool
message: Optional[str] = None
class PresentationSummary(BaseModel):
presentation_id: str
layout_count: int
@ -917,4 +922,40 @@ async def get_presentations_summary(
raise HTTPException(
status_code=500,
detail=f"Internal server error while retrieving presentations summary: {str(e)}"
)
)
# ENDPOINT : Delete a layout
@LAYOUT_MANAGEMENT_ROUTER.delete(
"/delete-layouts/{presentation_id}",
response_model=DeleteLayoutResponse,
responses={
200: {"model": DeleteLayoutResponse, "description": "Layout deleted successfully"},
404: {"model": ErrorResponse, "description": "Presentation Layouts not found"},
500: {"model": ErrorResponse, "description": "Internal server error"}
}
)
async def delete_layouts(presentation_id: str, session: AsyncSession = Depends(get_async_session)):
try:
# Validate presentation_id format (basic UUID check)
if not presentation_id or len(presentation_id.strip()) == 0:
raise HTTPException(
status_code=400,
detail="Presentation ID cannot be empty"
)
# Delete Presentation with all layouts
await session.execute(delete(PresentationLayoutCodeModel).where(PresentationLayoutCodeModel.presentation_id == presentation_id))
await session.commit()
return DeleteLayoutResponse(
success=True,
message=f"Successfully deleted layout(s) for presentation {presentation_id}"
)
except HTTPException:
raise
except Exception as e:
print(f"Error deleting layouts for presentation {presentation_id}: {str(e)}")
raise HTTPException(
status_code=500,
detail=f"Internal server error while deleting layouts: {str(e)}"
)

View file

@ -275,7 +275,7 @@ const ImageEditor = ({
</TabsTrigger>
</TabsList>
{/* Generate Tab */}
<TabsContent value="generate" className="mt-4 space-y-4">
<TabsContent value="generate" className="mt-4 space-y-4 overflow-y-auto hide-scrollbar h-[85vh]">
<div className="space-y-4">
<div>
<h3 className="text-sm font-medium mb-1">Current Prompt</h3>
@ -333,7 +333,7 @@ const ImageEditor = ({
<h3 className="text-sm font-medium mb-2">
Previous Generated Images
</h3>
<div className="grid grid-cols-2 gap-4 h-[400px] overflow-y-auto hide-scrollbar">
<div className="grid grid-cols-2 gap-4 ">
{previousGeneratedImages.map((image) => (
<div
onClick={() => handleImageChange(image.path)}

View file

@ -85,7 +85,8 @@ const compileCustomLayout = (layoutCode: string, React: any, z: any) => {
.replace(/import\s+.*\s+from\s+['"]zod['"];?/g, "")
// remove every zod import (any style)
.replace(/import\s+.*\s+from\s+['"]zod['"];?/g, "")
.replace(/const\s+[^=]*=\s*require\(['"]zod['"]\);?/g, "");
.replace(/const\s+[^=]*=\s*require\(['"]zod['"]\);?/g, "")
.replace(/Looking at this HTML structure, I can see it's a slide layout with a header, title, description, and a 2x2 grid of images with captions, plus footer elements.?/g, "")
const compiled = Babel.transform(cleanCode, {
presets: [
["react", { runtime: "classic" }],

View file

@ -5,14 +5,14 @@ import { useParams, useRouter } from "next/navigation";
import LoadingStates from "../components/LoadingStates";
import { Card } from "@/components/ui/card";
import { Button } from "@/components/ui/button";
import { ArrowLeft, Home } from "lucide-react";
import { ArrowLeft, Home, Trash2 } from "lucide-react";
import { useLayout } from "@/app/(presentation-generator)/context/LayoutContext";
const GroupLayoutPreview = () => {
const params = useParams();
const router = useRouter();
const slug = params.slug as string;
const { getFullDataByGroup, loading } = useLayout();
const { getFullDataByGroup, loading,refetch } = useLayout();
const layoutGroup = getFullDataByGroup(slug);
useEffect(() => {
@ -36,7 +36,17 @@ const GroupLayoutPreview = () => {
if (!layoutGroup || layoutGroup.length === 0) {
return <LoadingStates type="empty" />;
}
const deleteLayouts = async () => {
const presentationId = slug.replace('custom-','');
refetch();
router.back();
const response = await fetch(`/api/v1/ppt/layout-management/delete-layouts/${presentationId}`, {
method: "DELETE",
});
if (response.ok) {
router.push("/layout-preview");
}
}
return (
<div className="min-h-screen bg-gray-50">
{/* Header */}
@ -62,6 +72,9 @@ const GroupLayoutPreview = () => {
<Home className="w-4 h-4" />
All Groups
</Button>
{slug.includes('custom-') && <button className=" border border-red-200 flex justify-center items-center gap-2 text-red-700 px-4 py-1 rounded-md" onClick={() => {
deleteLayouts();
}}><Trash2 className="w-4 h-4" />Delete</button>}
</div>
<div className="text-center">
@ -73,6 +86,7 @@ const GroupLayoutPreview = () => {
{layoutGroup[0].groupName}
</p>
</div>
</div>
</header>