monorepo/apps/web2/src/app/_components/post/hooks.ts

98 lines
3.4 KiB
TypeScript

'use client';
import { getRandomInt } from '@3rapp/utils';
import { zodResolver } from '@hookform/resolvers/zod';
import { Post } from '@prisma/client';
import { isNil } from 'lodash';
import { useRouter } from 'next/navigation';
import { useMemo } from 'react';
import { useForm } from 'react-hook-form';
import { DeepNonNullable } from 'utility-types';
import { createPostItem, updatePostItem } from '@/app/actions/post';
import { useToast } from '@/hooks/use-toast';
import { MarkdownEditorProps } from '../markdown/type';
import { useEditorModalContext } from '../modal/hooks';
import { generatePostFormValidator } from './form-validator';
import { PostActionFormProps, PostCreateData, PostFormData, PostUpdateData } from './types';
export function usePostActionForm(params: PostActionFormProps) {
const defaultValues = useMemo(() => {
if (params.type === 'create') {
return {
title: '',
body: '',
summary: '',
slug: '',
keywords: '',
description: '',
} as DeepNonNullable<PostCreateData>;
}
return {
title: params.post.title,
body: params.post.body,
summary: isNil(params.post.summary) ? '' : params.post.summary,
slug: isNil(params.post.slug) ? null : params.post.slug,
keywords: isNil(params.post.keywords) ? '' : params.post.keywords,
description: isNil(params.post.description) ? '' : params.post.description,
} as DeepNonNullable<PostUpdateData>;
}, [params.type]);
return useForm<DeepNonNullable<PostFormData>>({
defaultValues,
mode: 'all',
resolver: zodResolver(
generatePostFormValidator(params.type === 'update' ? params.post.id : undefined),
),
});
}
export function usePostFormSubmitHandler(params: PostActionFormProps) {
const router = useRouter();
const { toast } = useToast();
const submitHandle = async (data: PostFormData) => {
let post: Post | null;
for (const key of Object.keys(data) as Array<keyof PostFormData>) {
if (typeof data[key] === 'string' && data[key].trim() === '') {
delete data[key];
}
}
try {
if (params.type === 'update') {
post = await updatePostItem(params.post.id, data);
} else {
post = await createPostItem({
thumb: `/uploads/thumb/post-${getRandomInt(1, 8)}.png`,
...data,
} as PostCreateData);
}
// 创建或更新文章后跳转到文章详情页
// 注意,这里不要用push,防止在详情页后退后返回到创建或编辑页面的弹出框
if (!isNil(post)) router.replace(`/post/${post.id}`);
} catch (error) {
toast({
variant: 'destructive',
title: '遇到服务器错误,请联系管理员处理',
description: (error as Error).message,
});
}
};
return submitHandle;
}
export const usePostEditorScreenHandler = () => {
const { editorFullScreen } = useEditorModalContext();
return useMemo<MarkdownEditorProps['handlers']>(
() => ({
onBroswerScreen: editorFullScreen,
onPageScreen: editorFullScreen,
}),
[editorFullScreen],
);
};