♻️ Use safe action (#1832)

This commit is contained in:
Luke Vella 2025-07-16 15:00:01 +01:00 committed by GitHub
parent c9b5527432
commit 08ce80fb8d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 61 additions and 61 deletions

View file

@ -0,0 +1,23 @@
"use server";
import { prisma } from "@rallly/database";
import { revalidateTag } from "next/cache";
import { instanceSettingsTag } from "@/features/instance-settings/constants";
import { instanceSettingsSchema } from "@/features/instance-settings/schema";
import { adminActionClient } from "@/features/safe-action/server";
export const updateInstanceSettingsAction = adminActionClient
.metadata({
actionName: "update_instance_settings",
})
.inputSchema(instanceSettingsSchema)
.action(async ({ parsedInput }) => {
await prisma.instanceSettings.update({
where: {
id: 1,
},
data: parsedInput,
});
revalidateTag(instanceSettingsTag);
});

View file

@ -26,10 +26,11 @@ import {
SettingsGroupTitle,
} from "@/components/settings-group";
import { Trans } from "@/components/trans";
import { updateInstanceSettings } from "@/features/instance-settings/mutations";
import type { InstanceSettings } from "@/features/instance-settings/schema";
import { instanceSettingsSchema } from "@/features/instance-settings/schema";
import { useSafeAction } from "@/features/safe-action/client";
import { useTranslation } from "@/i18n/client";
import { updateInstanceSettingsAction } from "./actions";
export function InstanceSettingsForm({
defaultValue,
@ -41,6 +42,8 @@ export function InstanceSettingsForm({
resolver: zodResolver(instanceSettingsSchema),
});
const updateInstanceSettings = useSafeAction(updateInstanceSettingsAction);
const { t } = useTranslation();
return (
@ -49,7 +52,7 @@ export function InstanceSettingsForm({
name="instance-settings-form"
onSubmit={form.handleSubmit(async (data) => {
try {
await updateInstanceSettings(data);
await updateInstanceSettings.executeAsync(data);
form.reset(data);
} catch (error) {
console.error(error);

View file

@ -1,35 +1,37 @@
"use server";
import { requireUser } from "@/auth/queries";
import type { Feedback } from "@/features/feedback/schema";
import { feedbackSchema } from "@/features/feedback/schema";
import { authActionClient } from "@/features/safe-action/server";
import { getEmailClient } from "@/utils/emails";
import { rateLimit } from "../rate-limit";
export const submitFeedback = async (formData: Feedback) => {
const { success } = await rateLimit("submitFeedback", 3, "1h");
export const submitFeedbackAction = authActionClient
.metadata({
actionName: "submitFeedback",
})
.inputSchema(feedbackSchema)
.action(async ({ ctx, parsedInput }) => {
const { success } = await rateLimit("submitFeedback", 3, "1h");
if (!success) {
return {
error: "Rate limit exceeded" as const,
};
}
if (!success) {
return {
error: "Rate limit exceeded" as const,
};
}
const user = await requireUser();
try {
const { content } = feedbackSchema.parse(formData);
getEmailClient().sendEmail({
to: "feedback@rallly.co",
subject: "Feedback",
text: `User: ${user.name} (${user.email})\n\n${content}`,
});
return {
success: true,
};
} catch {
return {
error: "Invalid Form Data" as const,
};
}
};
try {
const { content } = parsedInput;
getEmailClient().sendEmail({
to: "feedback@rallly.co",
subject: "Feedback",
text: `User: ${ctx.user.name} (${ctx.user.email})\n\n${content}`,
});
return {
success: true,
};
} catch {
return {
error: "Invalid Form Data" as const,
};
}
});

View file

@ -24,12 +24,14 @@ import { useForm } from "react-hook-form";
import { Trans } from "@/components/trans";
import { useSafeAction } from "@/features/safe-action/client";
import { isSelfHosted } from "@/utils/constants";
import { submitFeedback } from "../actions";
import { submitFeedbackAction } from "../actions";
import type { Feedback } from "../schema";
import { feedbackSchema } from "../schema";
export function FeedbackToggle() {
const submitFeedback = useSafeAction(submitFeedbackAction);
const form = useForm<Feedback>({
resolver: zodResolver(feedbackSchema),
});
@ -72,17 +74,7 @@ export function FeedbackToggle() {
</DialogHeader>
<Form {...form}>
<form
onSubmit={form.handleSubmit(async (data) => {
const res = await submitFeedback(data);
if (res.error) {
form.setError("content", {
message: res.error,
});
}
})}
>
<form onSubmit={form.handleSubmit(submitFeedback.executeAsync)}>
<FormField
control={form.control}
name="content"

View file

@ -1,20 +0,0 @@
"use server";
import type { InstanceSettings } from "@rallly/database";
import { prisma } from "@rallly/database";
import { revalidateTag } from "next/cache";
import { requireAdmin } from "@/auth/queries";
import { instanceSettingsTag } from "./constants";
export async function updateInstanceSettings(data: Partial<InstanceSettings>) {
await requireAdmin();
await prisma.instanceSettings.update({
where: {
id: 1,
},
data,
});
revalidateTag(instanceSettingsTag);
}