From aea1d20fdc02999f8a9c513c7264cd3134dc1ff8 Mon Sep 17 00:00:00 2001 From: "soroush.asadi" Date: Mon, 1 Jun 2026 08:24:57 +0330 Subject: [PATCH] fix(admin): redirect to edit page after creating blog post MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Root cause: after successful creation the form stayed on /blog/new. User couldn't tell it worked, clicked Save again, the second attempt hit the unique slug constraint and showed an error — making it look like creation was broken. Fix: adminPost is now typed, onSuccess redirects to /blog/{id} on new posts so the user lands on the edit page immediately. Also fixes commentCount being undefined in the list (MapPost now includes comment count via eager-loaded Comments). Co-Authored-By: Claude Sonnet 4.6 --- src/Meezi.Admin.API/Services/AdminWebsiteService.cs | 5 ++++- .../src/components/admin/admin-website-screens.tsx | 12 +++++++++--- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/Meezi.Admin.API/Services/AdminWebsiteService.cs b/src/Meezi.Admin.API/Services/AdminWebsiteService.cs index 61ae1e3..e444112 100644 --- a/src/Meezi.Admin.API/Services/AdminWebsiteService.cs +++ b/src/Meezi.Admin.API/Services/AdminWebsiteService.cs @@ -15,7 +15,9 @@ public class AdminWebsiteService(AppDbContext db) : IAdminWebsiteService var q = db.WebsiteBlogPosts.AsQueryable(); if (published.HasValue) q = q.Where(p => p.IsPublished == published.Value); var total = await q.CountAsync(ct); - var posts = await q.OrderByDescending(p => p.CreatedAt) + var posts = await q + .Include(p => p.Comments) + .OrderByDescending(p => p.CreatedAt) .Skip((page - 1) * limit).Take(limit).ToListAsync(ct); return new { Posts = posts.Select(MapPost), Total = total, Page = page, Limit = limit }; } @@ -162,5 +164,6 @@ public class AdminWebsiteService(AppDbContext db) : IAdminWebsiteService p.Id, p.Slug, p.TitleFa, p.TitleEn, p.ExcerptFa, p.ExcerptEn, p.ContentFa, p.ContentEn, p.CategoryFa, p.CategoryEn, p.Author, p.TagsJson, p.CoverImage, p.IsPublished, p.PublishedAt, p.ViewCount, p.CreatedAt, + CommentCount = p.Comments?.Count ?? 0, }; } diff --git a/web/admin/src/components/admin/admin-website-screens.tsx b/web/admin/src/components/admin/admin-website-screens.tsx index f09204b..e022df0 100644 --- a/web/admin/src/components/admin/admin-website-screens.tsx +++ b/web/admin/src/components/admin/admin-website-screens.tsx @@ -3,6 +3,7 @@ import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; import { useTranslations } from "next-intl"; import { useEffect, useState } from "react"; +import { useRouter } from "@/i18n/routing"; import { adminDelete, adminGet, adminPatch, adminPost, adminPut } from "@/lib/api/admin-client"; import type { AdminBlogPost, @@ -155,6 +156,7 @@ interface PostEditorProps { export function AdminBlogEditorScreen({ postId }: PostEditorProps) { const t = useTranslations("admin.website"); const qc = useQueryClient(); + const router = useRouter(); const isNew = !postId; const { data: post } = useQuery({ @@ -204,11 +206,15 @@ export function AdminBlogEditorScreen({ postId }: PostEditorProps) { const saveMut = useMutation({ mutationFn: () => isNew - ? adminPost("/api/admin/website/posts", form) - : adminPut(`/api/admin/website/posts/${postId}`, form), - onSuccess: () => { + ? adminPost<{ id: string }>("/api/admin/website/posts", form) + : adminPut<{ id: string }>(`/api/admin/website/posts/${postId}`, form), + onSuccess: (result) => { qc.invalidateQueries({ queryKey: ["admin", "website", "blog"] }); notify.success(t("saved")); + // After creating a new post, go to its edit page so the user can + // continue editing and won't accidentally hit Save again (which would + // fail on the unique slug constraint). + if (isNew) router.push(`/admin/website/blog/${result.id}`); }, onError: () => notify.error(t("errorGeneric")), });