@arch-cadre/blog-module 1.0.13 → 1.0.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. package/dist/actions/index.cjs +158 -0
  2. package/dist/actions/index.d.ts +4 -37
  3. package/dist/actions/index.mjs +121 -0
  4. package/dist/components/BlogStatsWidget.cjs +45 -0
  5. package/dist/components/BlogStatsWidget.d.ts +2 -1
  6. package/dist/components/BlogStatsWidget.mjs +13 -0
  7. package/dist/components/RecentCommentsWidget.cjs +47 -0
  8. package/dist/components/RecentCommentsWidget.d.ts +2 -1
  9. package/dist/components/RecentCommentsWidget.mjs +28 -0
  10. package/dist/components/RecentPostsWidget.cjs +47 -0
  11. package/dist/components/RecentPostsWidget.d.ts +2 -1
  12. package/dist/components/RecentPostsWidget.mjs +28 -0
  13. package/dist/components/ui/button.cjs +54 -0
  14. package/dist/components/ui/button.mjs +47 -0
  15. package/dist/components/ui/card.cjs +47 -0
  16. package/dist/components/ui/card.mjs +36 -0
  17. package/dist/components/ui/input.cjs +24 -0
  18. package/dist/components/ui/input.mjs +17 -0
  19. package/dist/components/ui/table.cjs +68 -0
  20. package/dist/components/ui/table.mjs +65 -0
  21. package/dist/components/ui/textarea.cjs +22 -0
  22. package/dist/components/ui/textarea.mjs +16 -0
  23. package/dist/index.cjs +100 -0
  24. package/dist/index.mjs +95 -0
  25. package/dist/intl.d.ts +7 -0
  26. package/dist/lib/utils.cjs +11 -0
  27. package/dist/lib/{utils.js → utils.mjs} +1 -1
  28. package/dist/lib/validation.cjs +16 -0
  29. package/dist/lib/validation.d.ts +2 -2
  30. package/dist/lib/validation.mjs +10 -0
  31. package/dist/navigation.cjs +23 -0
  32. package/dist/navigation.mjs +21 -0
  33. package/dist/routes.cjs +74 -0
  34. package/dist/routes.mjs +68 -0
  35. package/dist/schema.cjs +62 -0
  36. package/dist/schema.mjs +53 -0
  37. package/dist/styles/globals.css +1 -0
  38. package/dist/ui/views.cjs +448 -0
  39. package/dist/ui/views.d.ts +6 -5
  40. package/dist/ui/views.mjs +232 -0
  41. package/package.json +14 -10
  42. package/dist/actions/index.js +0 -149
  43. package/dist/components/BlogStatsWidget.js +0 -17
  44. package/dist/components/RecentCommentsWidget.js +0 -24
  45. package/dist/components/RecentPostsWidget.js +0 -24
  46. package/dist/components/ui/button.js +0 -33
  47. package/dist/components/ui/card.js +0 -12
  48. package/dist/components/ui/input.js +0 -8
  49. package/dist/components/ui/table.js +0 -16
  50. package/dist/components/ui/textarea.js +0 -8
  51. package/dist/index.js +0 -98
  52. package/dist/lib/validation.js +0 -11
  53. package/dist/navigation.js +0 -21
  54. package/dist/routes.js +0 -55
  55. package/dist/schema.js +0 -60
  56. package/dist/ui/views.js +0 -119
package/dist/index.js DELETED
@@ -1,98 +0,0 @@
1
- import { assignPermissionToRole, createPermission, db, getRoles, permissionsTable, } from "@arch-cadre/core/server";
2
- import { inArray, sql } from "drizzle-orm";
3
- import manifest from "../manifest.json" with { type: "json" };
4
- import BlogStatsWidget from "./components/BlogStatsWidget";
5
- import RecentCommentsWidget from "./components/RecentCommentsWidget";
6
- import RecentPostsWidget from "./components/RecentPostsWidget";
7
- import { navigation } from "./navigation";
8
- import { privateRoutes, publicRoutes } from "./routes";
9
- const BLOG_PERMISSIONS = [
10
- { name: "post:create", description: "Allow creating blog posts" },
11
- { name: "post:update", description: "Allow updating blog posts" },
12
- { name: "post:delete", description: "Allow deleting blog posts" },
13
- { name: "comment:create", description: "Allow creating comments" },
14
- { name: "comment:update", description: "Allow updating comments" },
15
- { name: "comment:delete", description: "Allow deleting comments" },
16
- ];
17
- // --- Module Definition ---
18
- const blogModule = {
19
- manifest: manifest,
20
- init: async () => {
21
- console.log("[BlogModule] ready.");
22
- },
23
- widgets: [
24
- {
25
- id: "blog-stats",
26
- name: "Blog Stats",
27
- area: "dashboard-stats",
28
- component: BlogStatsWidget,
29
- priority: 20,
30
- },
31
- {
32
- id: "recent-posts",
33
- name: "Recent Posts",
34
- area: "dashboard-main",
35
- component: RecentPostsWidget,
36
- priority: 20,
37
- },
38
- {
39
- id: "recent-comments",
40
- name: "Recent Comments",
41
- area: "dashboard-main",
42
- component: RecentCommentsWidget,
43
- priority: 30,
44
- },
45
- ],
46
- onEnable: async () => {
47
- console.log("[BlogModule] enabling and registering permissions...");
48
- try {
49
- // 1. Create permissions
50
- for (const perm of BLOG_PERMISSIONS) {
51
- await createPermission(perm.name, perm.description);
52
- }
53
- // 2. Assign to admin role
54
- const roles = await getRoles();
55
- const adminRole = roles.find((r) => r.name === "admin");
56
- if (adminRole) {
57
- const blogPermNames = BLOG_PERMISSIONS.map((p) => p.name);
58
- const blogPerms = await db
59
- .select()
60
- .from(permissionsTable)
61
- .where(inArray(permissionsTable.name, blogPermNames));
62
- for (const p of blogPerms) {
63
- await assignPermissionToRole(adminRole.id, p.id);
64
- }
65
- console.log("[BlogModule] Permissions assigned to admin role.");
66
- }
67
- }
68
- catch (error) {
69
- console.error("[BlogModule] Error during permission registration:", error);
70
- }
71
- console.log("[BlogModule] enabled.");
72
- },
73
- onDisable: async () => {
74
- console.log("[Blog] onDisable: Cleaning up tables and permissions...");
75
- try {
76
- // 1. Remove permissions (cascades to role-permission mappings)
77
- const blogPermNames = BLOG_PERMISSIONS.map((p) => p.name);
78
- await db
79
- .delete(permissionsTable)
80
- .where(inArray(permissionsTable.name, blogPermNames));
81
- console.log("[BlogModule] Permissions and mappings removed.");
82
- // 2. Drop tables
83
- const tables = ["blog_posts", "blog_comments"];
84
- for (const table of tables) {
85
- await db.execute(sql.raw(`DROP TABLE IF EXISTS ${table} CASCADE`));
86
- }
87
- }
88
- catch (e) {
89
- console.error("[Blog] onDisable Error:", e);
90
- }
91
- },
92
- routes: {
93
- public: publicRoutes,
94
- private: privateRoutes,
95
- },
96
- navigation: navigation,
97
- };
98
- export default blogModule;
@@ -1,11 +0,0 @@
1
- import { z } from "zod";
2
- // --- Validation Schemas ---
3
- export const postSchema = z.object({
4
- title: z.string().min(3, "Title must be at least 3 characters"),
5
- content: z.string().min(10, "Content must be at least 10 characters"),
6
- slug: z.string().min(3, "Slug is required"),
7
- });
8
- export const commentSchema = z.object({
9
- content: z.string().min(2, "Comment is too short"),
10
- postId: z.string().uuid(),
11
- });
@@ -1,21 +0,0 @@
1
- import { i18n } from "@arch-cadre/intl";
2
- export const navigation = {
3
- public: [
4
- {
5
- title: i18n("Blog"),
6
- url: "/blog",
7
- icon: "solar:pen-2-broken",
8
- },
9
- ],
10
- admin: {
11
- [i18n("CMS")]: [
12
- {
13
- title: i18n("Blog Manager"),
14
- url: "/blog",
15
- icon: "solar:posts-carousel-vertical-broken",
16
- roles: ["admin"],
17
- permissions: ["post:create", "post:update", "post:delete"],
18
- },
19
- ],
20
- },
21
- };
package/dist/routes.js DELETED
@@ -1,55 +0,0 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
2
- import { getCurrentSession } from "@arch-cadre/core/server";
3
- import { getComments, getPostById, getPostBySlug, getPosts } from "./actions/index";
4
- import { BlogAdminPage, BlogListPage, CreatePostForm, EditPostForm, PostDetailPage, } from "./ui/views";
5
- export const publicRoutes = [
6
- {
7
- path: "/blog",
8
- component: async () => {
9
- const posts = await getPosts();
10
- return _jsx(BlogListPage, { posts: posts });
11
- },
12
- auth: false,
13
- },
14
- {
15
- path: "/blog/:slug",
16
- component: async ({ params }) => {
17
- const { slug } = await params;
18
- const post = await getPostBySlug(slug);
19
- const comments = post ? await getComments(post.id) : [];
20
- const session = await getCurrentSession();
21
- return (_jsx(PostDetailPage, { post: post, comments: comments, currentUser: session?.user }));
22
- },
23
- auth: false,
24
- },
25
- ];
26
- export const privateRoutes = [
27
- {
28
- path: "/blog",
29
- component: async () => {
30
- const posts = await getPosts();
31
- return _jsx(BlogAdminPage, { posts: posts });
32
- },
33
- auth: true,
34
- roles: ["admin"],
35
- permissions: ["post:create", "post:update", "post:delete"],
36
- },
37
- {
38
- path: "/blog/new",
39
- component: CreatePostForm,
40
- auth: true,
41
- roles: ["admin"],
42
- permissions: ["post:create"],
43
- },
44
- {
45
- path: "/blog/edit/:id",
46
- component: async ({ params }) => {
47
- const { id } = await params;
48
- const post = await getPostById(id);
49
- return _jsx(EditPostForm, { post: post });
50
- },
51
- auth: true,
52
- roles: ["admin"],
53
- permissions: ["post:update"],
54
- },
55
- ];
package/dist/schema.js DELETED
@@ -1,60 +0,0 @@
1
- import { userTable } from "@arch-cadre/core";
2
- import { defineRelations } from "drizzle-orm";
3
- import { pgTable, text, timestamp } from "drizzle-orm/pg-core";
4
- export const postsTable = pgTable("blog_posts", {
5
- id: text("id")
6
- .primaryKey()
7
- .$defaultFn(() => crypto.randomUUID()),
8
- title: text("title").notNull(),
9
- slug: text("slug").unique().notNull(),
10
- content: text("content").notNull(),
11
- authorId: text("author_id")
12
- .references(() => userTable.id, { onDelete: "cascade" })
13
- .notNull(),
14
- createdAt: timestamp("created_at").defaultNow().notNull(),
15
- });
16
- export const commentsTable = pgTable("blog_comments", {
17
- id: text("id")
18
- .primaryKey()
19
- .$defaultFn(() => crypto.randomUUID()),
20
- postId: text("post_id")
21
- .references(() => postsTable.id, { onDelete: "cascade" })
22
- .notNull(),
23
- authorId: text("author_id")
24
- .references(() => userTable.id, { onDelete: "cascade" })
25
- .notNull(),
26
- content: text("content").notNull(),
27
- createdAt: timestamp("created_at").defaultNow().notNull(),
28
- });
29
- export const blogSchema = {
30
- postsTable,
31
- commentsTable,
32
- };
33
- export const relations = defineRelations({
34
- user: userTable,
35
- post: postsTable,
36
- comment: commentsTable,
37
- }, (r) => ({
38
- user: {
39
- posts: r.many.post({
40
- from: r.user.id,
41
- to: r.post.authorId,
42
- }),
43
- comments: r.many.comment({
44
- from: r.user.id,
45
- to: r.comment.authorId,
46
- }),
47
- },
48
- post: {
49
- comments: r.many.comment({
50
- from: r.post.id,
51
- to: r.comment.postId,
52
- }),
53
- },
54
- comment: {
55
- post: r.one.post({
56
- from: r.comment.postId,
57
- to: r.post.id,
58
- }),
59
- },
60
- }));
package/dist/ui/views.js DELETED
@@ -1,119 +0,0 @@
1
- /** biome-ignore-all lint/a11y/noLabelWithoutControl: <explanation> */
2
- "use client";
3
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
4
- import { useTranslation } from "@arch-cadre/intl/client";
5
- import { zodResolver } from "@hookform/resolvers/zod";
6
- import { ArrowLeft, Eye, MessageSquare, Pencil, Plus, Trash2, User as UserIcon, } from "lucide-react";
7
- import Link from "next/link";
8
- import { useRouter } from "next/navigation";
9
- import { useForm } from "react-hook-form";
10
- import { toast } from "sonner";
11
- import { createComment, createPost, deletePost, updatePost } from "../actions/index";
12
- import { Button } from "../components/ui/button";
13
- import { Card, CardContent, CardHeader, CardTitle, } from "../components/ui/card";
14
- import { Input } from "../components/ui/input";
15
- import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from "../components/ui/table";
16
- import { Textarea } from "../components/ui/textarea";
17
- import { commentSchema, postSchema } from "../lib/validation";
18
- export function BlogListPage({ posts = [] }) {
19
- const { t } = useTranslation();
20
- return (_jsxs("div", { className: "max-w-4xl mx-auto p-6 space-y-8", children: [_jsxs("header", { className: "border-b pb-6", children: [_jsx("h1", { className: "text-4xl font-black tracking-tighter text-primary", children: t("Blog Posts") }), _jsx("p", { className: "text-muted-foreground mt-2", children: t("Reading your blog posts") })] }), _jsx("div", { className: "grid gap-6", children: posts.map((post) => (_jsx(Link, { href: `/blog/${post.slug}`, children: _jsxs(Card, { className: "group hover:shadow-lg transition-all cursor-pointer overflow-hidden border-primary/5", children: [_jsxs(CardHeader, { children: [_jsx(CardTitle, { className: "text-2xl group-hover:text-primary transition-colors", children: post.title }), _jsxs("div", { className: "flex items-center gap-2 text-xs text-muted-foreground mt-1", children: [_jsx(UserIcon, { className: "size-3" }), _jsx("span", { children: post.author?.name }), _jsx("span", { children: "\u2022" }), _jsx("span", { children: new Date(post.createdAt).toLocaleDateString() })] })] }), _jsx(CardContent, { children: _jsx("p", { className: "text-secondary-foreground line-clamp-2", children: post.content }) })] }) }, post.id))) })] }));
21
- }
22
- // --- Comment Form Component ---
23
- function CommentForm({ postId }) {
24
- const router = useRouter();
25
- const { t } = useTranslation();
26
- const { register, handleSubmit, reset, formState: { errors, isSubmitting }, } = useForm({
27
- resolver: zodResolver(commentSchema.omit({ postId: true })),
28
- });
29
- const onSubmit = async (data) => {
30
- const result = await createComment({ ...data, postId });
31
- if (result.success) {
32
- toast.success(t("Comment added"));
33
- reset();
34
- router.refresh();
35
- }
36
- else {
37
- toast.error(result.error);
38
- }
39
- };
40
- return (_jsxs("form", { onSubmit: handleSubmit(onSubmit), className: "space-y-4", children: [_jsxs("div", { className: "space-y-1", children: [_jsx(Textarea, { ...register("content"), placeholder: t("Add your comment here..."), className: errors.content ? "border-destructive" : "" }), errors.content && (_jsx("p", { className: "text-xs text-destructive", children: errors.content.message }))] }), _jsx(Button, { type: "submit", disabled: isSubmitting, size: "sm", children: isSubmitting ? t("Please wait...") : t("Create Comment") })] }));
41
- }
42
- // --- Detail View ---
43
- export function PostDetailPage({ post, comments = [], currentUser, }) {
44
- const { t } = useTranslation();
45
- if (!post)
46
- return _jsx("div", { className: "p-20 text-center", children: t("Post not found") });
47
- return (_jsxs("div", { className: "max-w-3xl mx-auto p-6 space-y-10 pb-20", children: [_jsx(Button, { asChild: true, variant: "ghost", size: "sm", className: "gap-2", children: _jsxs(Link, { href: "/blog", children: [_jsx(ArrowLeft, { className: "size-4" }), " ", t("Back to posts")] }) }), _jsxs("article", { className: "space-y-6", children: [_jsxs("div", { className: "space-y-2", children: [_jsx("h1", { className: "text-5xl font-black tracking-tighter leading-tight", children: post.title }), _jsxs("div", { className: "flex items-center gap-3 text-muted-foreground", children: [_jsx("div", { className: "size-8 rounded-full bg-primary/10 flex items-center justify-center", children: _jsx(UserIcon, { className: "size-4 text-primary" }) }), _jsxs("div", { className: "text-sm", children: [_jsx("p", { className: "font-bold text-foreground leading-none", children: post.author?.name }), _jsx("p", { className: "text-xs", children: new Date(post.createdAt).toLocaleDateString() })] })] })] }), _jsx("div", { className: "prose prose-lg dark:prose-invert max-w-none whitespace-pre-wrap pt-4 border-t", children: post.content })] }), _jsxs("section", { className: "pt-10 border-t space-y-8", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(MessageSquare, { className: "size-5" }), _jsxs("h3", { className: "text-2xl font-bold tracking-tight", children: [t("Comments"), " (", comments.length, ")"] })] }), currentUser ? (_jsxs("div", { className: "bg-muted/30 p-6 rounded-2xl border", children: [_jsx("p", { className: "text-sm font-bold mb-4", children: t("Leave a comment") }), _jsx(CommentForm, { postId: post.id })] })) : (_jsx("div", { className: "p-6 bg-amber-50 border border-amber-100 rounded-2xl text-center", children: _jsxs("p", { className: "text-sm font-medium text-amber-800", children: ["Please", " ", _jsx(Link, { href: "/signin", className: "underline font-bold", children: t("Sign in") }), " ", t("to join the conversation.")] }) })), _jsxs("div", { className: "space-y-6", children: [comments.map((comment) => (_jsxs("div", { className: "flex gap-4", children: [_jsx("div", { className: "size-10 rounded-full bg-muted flex items-center justify-center shrink-0", children: _jsx(UserIcon, { className: "size-5 opacity-40" }) }), _jsxs("div", { className: "space-y-1", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx("span", { className: "font-bold text-sm", children: comment.author?.name }), _jsx("span", { className: "text-[10px] opacity-50", children: new Date(comment.createdAt).toLocaleDateString() })] }), _jsx("p", { className: "text-sm text-secondary-foreground leading-relaxed", children: comment.content })] })] }, comment.id))), comments.length === 0 && (_jsx("p", { className: "text-center text-muted-foreground text-sm py-10 italic", children: t("No comments yet. Be the first to comment!") }))] })] })] }));
48
- }
49
- // --- Admin View Components ---
50
- export function BlogAdminPage({ posts = [] }) {
51
- const router = useRouter();
52
- const { t } = useTranslation();
53
- const handleDelete = async (id) => {
54
- if (!confirm(t("Confirm deletion of this post?")))
55
- return;
56
- const result = await deletePost(id);
57
- if (result.success) {
58
- toast.success(t("Post deleted"));
59
- router.refresh();
60
- }
61
- else {
62
- toast.error(t("UnexpectedError") + result.error);
63
- }
64
- };
65
- return (_jsxs("div", { className: "p-6 space-y-6", children: [_jsxs("div", { className: "flex justify-between items-center", children: [_jsx("h1", { className: "text-3xl font-black tracking-tight text-foreground", children: t("Blog posts") }), _jsx(Button, { asChild: true, size: "sm", className: "gap-2", children: _jsxs(Link, { href: "/kryo/blog/new", children: [_jsx(Plus, { className: "size-4" }), " ", t("New Post")] }) })] }), _jsx(Card, { className: "border-primary/10 shadow-sm overflow-hidden", children: _jsxs(Table, { children: [_jsx(TableHeader, { children: _jsxs(TableRow, { children: [_jsx(TableHead, { className: "w-[40%]", children: t("Title") }), _jsx(TableHead, { children: t("Author") }), _jsx(TableHead, { children: t("Date") }), _jsx(TableHead, { className: "text-right", children: t("Actions") })] }) }), _jsxs(TableBody, { children: [posts.length === 0 && (_jsx(TableRow, { children: _jsx(TableCell, { colSpan: 4, className: "h-24 text-center text-muted-foreground italic", children: t("No posts found. Create your first post!") }) })), posts.map((post) => (_jsxs(TableRow, { className: "transition-colors", children: [_jsx(TableCell, { className: "font-bold", children: post.title }), _jsx(TableCell, { className: "text-xs", children: post.author?.name }), _jsx(TableCell, { className: "text-muted-foreground text-xs", children: new Date(post.createdAt).toLocaleDateString() }), _jsx(TableCell, { className: "text-right", children: _jsxs("div", { className: "flex justify-end gap-2", children: [_jsx(Button, { asChild: true, variant: "ghost", size: "icon", className: "size-8", children: _jsx(Link, { href: `/blog/${post.slug}`, target: "_blank", children: _jsx(Eye, { className: "size-4" }) }) }), _jsx(Button, { asChild: true, variant: "ghost", size: "icon", className: "size-8", children: _jsx(Link, { href: `/kryo/blog/edit/${post.id}`, children: _jsx(Pencil, { className: "size-4" }) }) }), _jsx(Button, { variant: "ghost", size: "icon", className: "size-8 text-destructive hover:text-destructive hover:bg-destructive/10", onClick: () => handleDelete(post.id), children: _jsx(Trash2, { className: "size-4" }) })] }) })] }, post.id)))] })] }) })] }));
66
- }
67
- export function CreatePostForm() {
68
- const router = useRouter();
69
- const { t } = useTranslation();
70
- const { register, handleSubmit, formState: { errors, isSubmitting }, } = useForm({
71
- resolver: zodResolver(postSchema.omit({ slug: true })),
72
- });
73
- const onSubmit = async (data) => {
74
- const slug = data.title
75
- .toLowerCase()
76
- .replace(/ /g, "-")
77
- .replace(/[^\w-]+/g, "");
78
- const result = await createPost({ ...data, slug });
79
- if (result.success) {
80
- toast.success(t("Post created"));
81
- router.push("/kryo/blog");
82
- router.refresh();
83
- }
84
- else {
85
- toast.error(t("UnexpectedError") + result.error);
86
- }
87
- };
88
- return (_jsxs("div", { className: "max-w-2xl mx-auto p-6 space-y-6", children: [_jsxs("div", { className: "flex items-center gap-4", children: [_jsx(Button, { asChild: true, variant: "outline", size: "icon", className: "rounded-lg", children: _jsx(Link, { href: "/kryo/blog", children: _jsx(ArrowLeft, { className: "size-4" }) }) }), _jsx("h1", { className: "text-2xl font-black text-foreground", children: t("New Post") })] }), _jsx(Card, { className: "border-primary/10 shadow-lg", children: _jsx(CardContent, { className: "pt-6", children: _jsxs("form", { onSubmit: handleSubmit(onSubmit), className: "space-y-6", children: [_jsxs("div", { className: "space-y-2", children: [_jsx("label", { className: "text-xs font-black uppercase tracking-widest opacity-50 px-1", children: t("Title") }), _jsx(Input, { ...register("title"), className: errors.title ? "border-destructive font-bold" : "font-bold", placeholder: t("Title of your post") }), errors.title && (_jsx("p", { className: "text-xs text-destructive font-bold", children: errors.title.message }))] }), _jsxs("div", { className: "space-y-2", children: [_jsx("label", { className: "text-xs font-black uppercase tracking-widest opacity-50 px-1", children: t("Content") }), _jsx(Textarea, { ...register("content"), rows: 12, className: errors.content
89
- ? "border-destructive resize-none"
90
- : "resize-none", placeholder: t("Content of your post") }), errors.content && (_jsx("p", { className: "text-xs text-destructive font-bold", children: errors.content.message }))] }), _jsx(Button, { type: "submit", disabled: isSubmitting, className: "w-full text-sm uppercase tracking-widest transition-all", children: isSubmitting ? t("Please wait...") : t("Publish") })] }) }) })] }));
91
- }
92
- export function EditPostForm({ post }) {
93
- const router = useRouter();
94
- const { t } = useTranslation();
95
- const { register, handleSubmit, formState: { errors, isSubmitting }, } = useForm({
96
- resolver: zodResolver(postSchema),
97
- defaultValues: {
98
- title: post.title,
99
- content: post.content,
100
- slug: post.slug,
101
- },
102
- });
103
- const onSubmit = async (data) => {
104
- const result = await updatePost(post.id, data);
105
- if (result.success) {
106
- toast.success(t("Post updated"));
107
- router.push("/kryo/blog");
108
- router.refresh();
109
- }
110
- else {
111
- toast.error(t("UnexpectedError") + result.error);
112
- }
113
- };
114
- return (_jsxs("div", { className: "max-w-2xl mx-auto p-6 space-y-6", children: [_jsxs("div", { className: "flex items-center gap-4", children: [_jsx(Button, { asChild: true, variant: "outline", size: "icon", className: "rounded-lg", children: _jsx(Link, { href: "/kryo/blog", children: _jsx(ArrowLeft, { className: "size-4" }) }) }), _jsx("h1", { className: "text-2xl font-black text-foreground", children: t("Edit Post") })] }), _jsx(Card, { className: "border-primary/10 shadow-lg", children: _jsx(CardContent, { className: "pt-6", children: _jsxs("form", { onSubmit: handleSubmit(onSubmit), className: "space-y-6", children: [_jsxs("div", { className: "space-y-2", children: [_jsx("label", { className: "text-xs font-black uppercase tracking-widest opacity-50 px-1", children: t("Title") }), _jsx(Input, { ...register("title"), className: errors.title ? "border-destructive font-bold" : "font-bold", placeholder: t("Title of your post") }), errors.title && (_jsx("p", { className: "text-xs text-destructive font-bold", children: errors.title.message }))] }), _jsxs("div", { className: "space-y-2", children: [_jsx("label", { className: "text-xs font-black uppercase tracking-widest opacity-50 px-1", children: t("Slug") }), _jsx(Input, { ...register("slug"), className: errors.slug
115
- ? "border-destructive font-mono text-sm"
116
- : "font-mono text-sm", placeholder: t("Slug URL") }), errors.slug && (_jsx("p", { className: "text-xs text-destructive font-bold", children: errors.slug.message }))] }), _jsxs("div", { className: "space-y-2", children: [_jsx("label", { className: "text-xs font-black uppercase tracking-widest opacity-50 px-1", children: t("Content") }), _jsx(Textarea, { ...register("content"), rows: 12, className: errors.content
117
- ? "border-destructive resize-none"
118
- : "resize-none", placeholder: t("Content of your post") }), errors.content && (_jsx("p", { className: "text-xs text-destructive font-bold", children: errors.content.message }))] }), _jsx(Button, { type: "submit", disabled: isSubmitting, className: "w-full text-sm uppercase tracking-widest transition-all", children: isSubmitting ? t("Please wait...") : t("Update") })] }) }) })] }));
119
- }