@btst/stack 1.1.4 → 1.1.6
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.
- package/dist/node_modules/.pnpm/@radix-ui_react-alert-dialog@1.1.15_@types_react-dom@19.2.2_@types_react@19.2.2__@types_ec789942cd38340bd7362c09e7d34384/node_modules/@radix-ui/react-alert-dialog/dist/index.cjs +182 -0
- package/dist/node_modules/.pnpm/@radix-ui_react-alert-dialog@1.1.15_@types_react-dom@19.2.2_@types_react@19.2.2__@types_ec789942cd38340bd7362c09e7d34384/node_modules/@radix-ui/react-alert-dialog/dist/index.mjs +149 -0
- package/dist/packages/better-stack/src/plugins/blog/api/plugin.cjs +14 -7
- package/dist/packages/better-stack/src/plugins/blog/api/plugin.mjs +14 -7
- package/dist/packages/better-stack/src/plugins/blog/client/components/forms/post-forms.cjs +64 -14
- package/dist/packages/better-stack/src/plugins/blog/client/components/forms/post-forms.mjs +66 -16
- package/dist/packages/better-stack/src/plugins/blog/client/components/pages/edit-post-page.internal.cjs +5 -1
- package/dist/packages/better-stack/src/plugins/blog/client/components/pages/edit-post-page.internal.mjs +5 -1
- package/dist/packages/better-stack/src/plugins/blog/client/hooks/blog-hooks.cjs +31 -0
- package/dist/packages/better-stack/src/plugins/blog/client/hooks/blog-hooks.mjs +31 -1
- package/dist/packages/better-stack/src/plugins/blog/client/localization/blog-forms.cjs +8 -0
- package/dist/packages/better-stack/src/plugins/blog/client/localization/blog-forms.mjs +8 -0
- package/dist/packages/ui/src/components/alert-dialog.cjs +149 -0
- package/dist/packages/ui/src/components/alert-dialog.mjs +137 -0
- package/dist/plugins/blog/client/hooks/index.cjs +1 -0
- package/dist/plugins/blog/client/hooks/index.d.cts +7 -1
- package/dist/plugins/blog/client/hooks/index.d.mts +7 -1
- package/dist/plugins/blog/client/hooks/index.d.ts +7 -1
- package/dist/plugins/blog/client/hooks/index.mjs +1 -1
- package/dist/plugins/blog/client/index.d.cts +171 -177
- package/dist/plugins/blog/client/index.d.mts +171 -177
- package/dist/plugins/blog/client/index.d.ts +171 -177
- package/dist/plugins/blog/query-keys.d.cts +1 -0
- package/dist/plugins/blog/query-keys.d.mts +1 -0
- package/dist/plugins/blog/query-keys.d.ts +1 -0
- package/dist/plugins/client/index.d.cts +3 -2
- package/dist/plugins/client/index.d.mts +3 -2
- package/dist/plugins/client/index.d.ts +3 -2
- package/package.json +5 -3
- package/src/plugins/blog/api/plugin.ts +14 -6
- package/src/plugins/blog/client/components/forms/post-forms.tsx +92 -14
- package/src/plugins/blog/client/components/pages/edit-post-page.internal.tsx +6 -0
- package/src/plugins/blog/client/hooks/blog-hooks.tsx +38 -0
- package/src/plugins/blog/client/localization/blog-forms.ts +10 -0
- package/src/plugins/client/index.ts +7 -3
|
@@ -23,8 +23,20 @@ import {
|
|
|
23
23
|
useCreatePost,
|
|
24
24
|
useSuspensePost,
|
|
25
25
|
useUpdatePost,
|
|
26
|
+
useDeletePost,
|
|
26
27
|
} from "../../hooks/blog-hooks";
|
|
27
28
|
import { slugify } from "../../../utils";
|
|
29
|
+
import {
|
|
30
|
+
AlertDialog,
|
|
31
|
+
AlertDialogAction,
|
|
32
|
+
AlertDialogCancel,
|
|
33
|
+
AlertDialogContent,
|
|
34
|
+
AlertDialogDescription,
|
|
35
|
+
AlertDialogFooter,
|
|
36
|
+
AlertDialogHeader,
|
|
37
|
+
AlertDialogTitle,
|
|
38
|
+
AlertDialogTrigger,
|
|
39
|
+
} from "@workspace/ui/components/alert-dialog";
|
|
28
40
|
|
|
29
41
|
import { zodResolver } from "@hookform/resolvers/zod";
|
|
30
42
|
import { Loader2 } from "lucide-react";
|
|
@@ -404,6 +416,7 @@ type EditPostFormProps = {
|
|
|
404
416
|
postSlug: string;
|
|
405
417
|
onClose: () => void;
|
|
406
418
|
onSuccess: (post: { slug: string; published: boolean }) => void;
|
|
419
|
+
onDelete?: () => void;
|
|
407
420
|
};
|
|
408
421
|
|
|
409
422
|
const editPostFormPropsAreEqual = (
|
|
@@ -413,6 +426,7 @@ const editPostFormPropsAreEqual = (
|
|
|
413
426
|
if (prevProps.postSlug !== nextProps.postSlug) return false;
|
|
414
427
|
if (prevProps.onClose !== nextProps.onClose) return false;
|
|
415
428
|
if (prevProps.onSuccess !== nextProps.onSuccess) return false;
|
|
429
|
+
if (prevProps.onDelete !== nextProps.onDelete) return false;
|
|
416
430
|
return true;
|
|
417
431
|
};
|
|
418
432
|
|
|
@@ -420,8 +434,10 @@ const EditPostFormComponent = ({
|
|
|
420
434
|
postSlug,
|
|
421
435
|
onClose,
|
|
422
436
|
onSuccess,
|
|
437
|
+
onDelete,
|
|
423
438
|
}: EditPostFormProps) => {
|
|
424
439
|
const [featuredImageUploading, setFeaturedImageUploading] = useState(false);
|
|
440
|
+
const [deleteDialogOpen, setDeleteDialogOpen] = useState(false);
|
|
425
441
|
const { localization } = usePluginOverrides<
|
|
426
442
|
BlogPluginOverrides,
|
|
427
443
|
Partial<BlogPluginOverrides>
|
|
@@ -457,6 +473,9 @@ const EditPostFormComponent = ({
|
|
|
457
473
|
error: updatePostError,
|
|
458
474
|
} = useUpdatePost();
|
|
459
475
|
|
|
476
|
+
const { mutateAsync: deletePost, isPending: isDeletingPost } =
|
|
477
|
+
useDeletePost();
|
|
478
|
+
|
|
460
479
|
type EditPostFormValues = z.input<typeof schema>;
|
|
461
480
|
const onSubmit = async (data: EditPostFormValues) => {
|
|
462
481
|
// Wait for mutation to complete, including refresh
|
|
@@ -489,6 +508,21 @@ const EditPostFormComponent = ({
|
|
|
489
508
|
});
|
|
490
509
|
};
|
|
491
510
|
|
|
511
|
+
const handleDelete = async () => {
|
|
512
|
+
if (!post?.id) return;
|
|
513
|
+
|
|
514
|
+
await deletePost({ id: post.id });
|
|
515
|
+
toast.success(localization.BLOG_FORMS_TOAST_DELETE_SUCCESS);
|
|
516
|
+
setDeleteDialogOpen(false);
|
|
517
|
+
|
|
518
|
+
// Call onDelete callback if provided, otherwise use onClose
|
|
519
|
+
if (onDelete) {
|
|
520
|
+
onDelete();
|
|
521
|
+
} else {
|
|
522
|
+
onClose();
|
|
523
|
+
}
|
|
524
|
+
};
|
|
525
|
+
|
|
492
526
|
const form = useForm<z.input<typeof schema>>({
|
|
493
527
|
resolver: zodResolver(schema),
|
|
494
528
|
defaultValues: {
|
|
@@ -508,20 +542,64 @@ const EditPostFormComponent = ({
|
|
|
508
542
|
}
|
|
509
543
|
|
|
510
544
|
return (
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
545
|
+
<>
|
|
546
|
+
<PostFormBody
|
|
547
|
+
form={form}
|
|
548
|
+
onSubmit={onSubmit}
|
|
549
|
+
submitLabel={
|
|
550
|
+
isUpdatingPost
|
|
551
|
+
? localization.BLOG_FORMS_SUBMIT_UPDATE_PENDING
|
|
552
|
+
: localization.BLOG_FORMS_SUBMIT_UPDATE_IDLE
|
|
553
|
+
}
|
|
554
|
+
onCancel={onClose}
|
|
555
|
+
disabled={isUpdatingPost || featuredImageUploading}
|
|
556
|
+
errorMessage={updatePostError?.message}
|
|
557
|
+
setFeaturedImageUploading={setFeaturedImageUploading}
|
|
558
|
+
initialSlugTouched={!!post?.slug}
|
|
559
|
+
/>
|
|
560
|
+
<div className="w-full">
|
|
561
|
+
<AlertDialog open={deleteDialogOpen} onOpenChange={setDeleteDialogOpen}>
|
|
562
|
+
<AlertDialogTrigger asChild>
|
|
563
|
+
<Button
|
|
564
|
+
variant="destructive"
|
|
565
|
+
type="button"
|
|
566
|
+
disabled={
|
|
567
|
+
isUpdatingPost || featuredImageUploading || isDeletingPost
|
|
568
|
+
}
|
|
569
|
+
className="mt-4"
|
|
570
|
+
>
|
|
571
|
+
{localization.BLOG_FORMS_DELETE_BUTTON}
|
|
572
|
+
</Button>
|
|
573
|
+
</AlertDialogTrigger>
|
|
574
|
+
<AlertDialogContent>
|
|
575
|
+
<AlertDialogHeader>
|
|
576
|
+
<AlertDialogTitle>
|
|
577
|
+
{localization.BLOG_FORMS_DELETE_DIALOG_TITLE}
|
|
578
|
+
</AlertDialogTitle>
|
|
579
|
+
<AlertDialogDescription>
|
|
580
|
+
{localization.BLOG_FORMS_DELETE_DIALOG_DESCRIPTION}
|
|
581
|
+
</AlertDialogDescription>
|
|
582
|
+
</AlertDialogHeader>
|
|
583
|
+
<AlertDialogFooter>
|
|
584
|
+
<AlertDialogCancel disabled={isDeletingPost}>
|
|
585
|
+
{localization.BLOG_FORMS_DELETE_DIALOG_CANCEL}
|
|
586
|
+
</AlertDialogCancel>
|
|
587
|
+
<AlertDialogAction
|
|
588
|
+
onClick={(e) => {
|
|
589
|
+
e.preventDefault();
|
|
590
|
+
void handleDelete();
|
|
591
|
+
}}
|
|
592
|
+
disabled={isDeletingPost}
|
|
593
|
+
>
|
|
594
|
+
{isDeletingPost
|
|
595
|
+
? localization.BLOG_FORMS_DELETE_PENDING
|
|
596
|
+
: localization.BLOG_FORMS_DELETE_DIALOG_CONFIRM}
|
|
597
|
+
</AlertDialogAction>
|
|
598
|
+
</AlertDialogFooter>
|
|
599
|
+
</AlertDialogContent>
|
|
600
|
+
</AlertDialog>
|
|
601
|
+
</div>
|
|
602
|
+
</>
|
|
525
603
|
);
|
|
526
604
|
};
|
|
527
605
|
|
|
@@ -44,6 +44,11 @@ export function EditPostPage({ slug }: { slug: string }) {
|
|
|
44
44
|
navigate(`${basePath}/blog/${post.slug}`);
|
|
45
45
|
};
|
|
46
46
|
|
|
47
|
+
const handleDelete = () => {
|
|
48
|
+
// Navigate to blog list after deletion
|
|
49
|
+
navigate(`${basePath}/blog`);
|
|
50
|
+
};
|
|
51
|
+
|
|
47
52
|
return (
|
|
48
53
|
<PageWrapper className="gap-6" testId="edit-post-page">
|
|
49
54
|
<PageHeader
|
|
@@ -54,6 +59,7 @@ export function EditPostPage({ slug }: { slug: string }) {
|
|
|
54
59
|
postSlug={slug}
|
|
55
60
|
onClose={handleClose}
|
|
56
61
|
onSuccess={handleSuccess}
|
|
62
|
+
onDelete={handleDelete}
|
|
57
63
|
/>
|
|
58
64
|
</PageWrapper>
|
|
59
65
|
);
|
|
@@ -438,6 +438,44 @@ export function useUpdatePost() {
|
|
|
438
438
|
});
|
|
439
439
|
}
|
|
440
440
|
|
|
441
|
+
/** Delete a post by id */
|
|
442
|
+
export function useDeletePost() {
|
|
443
|
+
const { refresh, apiBaseURL, apiBasePath } =
|
|
444
|
+
usePluginOverrides<BlogPluginOverrides>("blog");
|
|
445
|
+
|
|
446
|
+
const client = createApiClient<BlogApiRouter>({
|
|
447
|
+
baseURL: apiBaseURL,
|
|
448
|
+
basePath: apiBasePath,
|
|
449
|
+
});
|
|
450
|
+
|
|
451
|
+
const queryClient = useQueryClient();
|
|
452
|
+
const queries = createBlogQueryKeys(client);
|
|
453
|
+
|
|
454
|
+
return useMutation<{ success: boolean }, Error, { id: string }>({
|
|
455
|
+
mutationKey: [...queries.posts._def, "delete"],
|
|
456
|
+
mutationFn: async ({ id }: { id: string }) => {
|
|
457
|
+
const response = await client(`@delete/posts/:id`, {
|
|
458
|
+
method: "DELETE",
|
|
459
|
+
params: { id },
|
|
460
|
+
});
|
|
461
|
+
return response.data as { success: boolean };
|
|
462
|
+
},
|
|
463
|
+
onSuccess: async () => {
|
|
464
|
+
// Invalidate all post lists and detail caches - wait for completion
|
|
465
|
+
await queryClient.invalidateQueries({
|
|
466
|
+
queryKey: queries.posts._def,
|
|
467
|
+
});
|
|
468
|
+
await queryClient.invalidateQueries({
|
|
469
|
+
queryKey: queries.drafts.list._def,
|
|
470
|
+
});
|
|
471
|
+
// Refresh server-side cache (Next.js router cache)
|
|
472
|
+
if (refresh) {
|
|
473
|
+
await refresh();
|
|
474
|
+
}
|
|
475
|
+
},
|
|
476
|
+
});
|
|
477
|
+
}
|
|
478
|
+
|
|
441
479
|
/**
|
|
442
480
|
* Hook for searching posts by a free-text query. Uses `usePosts` under the hood.
|
|
443
481
|
* Debounces the query and preserves last successful results to avoid flicker.
|
|
@@ -25,8 +25,18 @@ export const BLOG_FORMS = {
|
|
|
25
25
|
|
|
26
26
|
BLOG_FORMS_TOAST_CREATE_SUCCESS: "Post created successfully",
|
|
27
27
|
BLOG_FORMS_TOAST_UPDATE_SUCCESS: "Post updated successfully",
|
|
28
|
+
BLOG_FORMS_TOAST_DELETE_SUCCESS: "Post deleted successfully",
|
|
28
29
|
BLOG_FORMS_LOADING_POST: "Loading post...",
|
|
29
30
|
|
|
31
|
+
// Delete post
|
|
32
|
+
BLOG_FORMS_DELETE_BUTTON: "Delete Post",
|
|
33
|
+
BLOG_FORMS_DELETE_DIALOG_TITLE: "Delete Post",
|
|
34
|
+
BLOG_FORMS_DELETE_DIALOG_DESCRIPTION:
|
|
35
|
+
"Are you sure you want to delete this post? This action cannot be undone.",
|
|
36
|
+
BLOG_FORMS_DELETE_DIALOG_CANCEL: "Cancel",
|
|
37
|
+
BLOG_FORMS_DELETE_DIALOG_CONFIRM: "Delete",
|
|
38
|
+
BLOG_FORMS_DELETE_PENDING: "Deleting...",
|
|
39
|
+
|
|
30
40
|
// Markdown editor
|
|
31
41
|
BLOG_FORMS_EDITOR_PLACEHOLDER: "Write something...",
|
|
32
42
|
|
|
@@ -42,10 +42,14 @@ export { createClient } from "better-call/client";
|
|
|
42
42
|
* });
|
|
43
43
|
* ```
|
|
44
44
|
*
|
|
45
|
-
* @template
|
|
45
|
+
* @template TOverrides - The shape of overridable components/functions this plugin requires
|
|
46
|
+
* @template TRoutes - The exact shape of routes this plugin provides (preserves keys and route types)
|
|
46
47
|
*/
|
|
47
48
|
export function defineClientPlugin<
|
|
48
|
-
|
|
49
|
-
>
|
|
49
|
+
TOverrides = Record<string, never>,
|
|
50
|
+
TRoutes extends Record<string, Route> = Record<string, Route>,
|
|
51
|
+
>(
|
|
52
|
+
plugin: ClientPlugin<TOverrides, TRoutes>,
|
|
53
|
+
): ClientPlugin<TOverrides, TRoutes> {
|
|
50
54
|
return plugin;
|
|
51
55
|
}
|