mirror of
https://github.com/lukevella/rallly.git
synced 2025-07-27 13:17:51 +02:00
♻️ Use safe action (#1832)
This commit is contained in:
parent
c9b5527432
commit
08ce80fb8d
5 changed files with 61 additions and 61 deletions
23
apps/web/src/app/[locale]/control-panel/settings/actions.ts
Normal file
23
apps/web/src/app/[locale]/control-panel/settings/actions.ts
Normal 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);
|
||||||
|
});
|
|
@ -26,10 +26,11 @@ import {
|
||||||
SettingsGroupTitle,
|
SettingsGroupTitle,
|
||||||
} from "@/components/settings-group";
|
} from "@/components/settings-group";
|
||||||
import { Trans } from "@/components/trans";
|
import { Trans } from "@/components/trans";
|
||||||
import { updateInstanceSettings } from "@/features/instance-settings/mutations";
|
|
||||||
import type { InstanceSettings } from "@/features/instance-settings/schema";
|
import type { InstanceSettings } from "@/features/instance-settings/schema";
|
||||||
import { instanceSettingsSchema } 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 { useTranslation } from "@/i18n/client";
|
||||||
|
import { updateInstanceSettingsAction } from "./actions";
|
||||||
|
|
||||||
export function InstanceSettingsForm({
|
export function InstanceSettingsForm({
|
||||||
defaultValue,
|
defaultValue,
|
||||||
|
@ -41,6 +42,8 @@ export function InstanceSettingsForm({
|
||||||
resolver: zodResolver(instanceSettingsSchema),
|
resolver: zodResolver(instanceSettingsSchema),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const updateInstanceSettings = useSafeAction(updateInstanceSettingsAction);
|
||||||
|
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -49,7 +52,7 @@ export function InstanceSettingsForm({
|
||||||
name="instance-settings-form"
|
name="instance-settings-form"
|
||||||
onSubmit={form.handleSubmit(async (data) => {
|
onSubmit={form.handleSubmit(async (data) => {
|
||||||
try {
|
try {
|
||||||
await updateInstanceSettings(data);
|
await updateInstanceSettings.executeAsync(data);
|
||||||
form.reset(data);
|
form.reset(data);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
|
|
|
@ -1,13 +1,16 @@
|
||||||
"use server";
|
"use server";
|
||||||
|
|
||||||
import { requireUser } from "@/auth/queries";
|
|
||||||
import type { Feedback } from "@/features/feedback/schema";
|
|
||||||
import { feedbackSchema } from "@/features/feedback/schema";
|
import { feedbackSchema } from "@/features/feedback/schema";
|
||||||
|
import { authActionClient } from "@/features/safe-action/server";
|
||||||
import { getEmailClient } from "@/utils/emails";
|
import { getEmailClient } from "@/utils/emails";
|
||||||
|
|
||||||
import { rateLimit } from "../rate-limit";
|
import { rateLimit } from "../rate-limit";
|
||||||
|
|
||||||
export const submitFeedback = async (formData: Feedback) => {
|
export const submitFeedbackAction = authActionClient
|
||||||
|
.metadata({
|
||||||
|
actionName: "submitFeedback",
|
||||||
|
})
|
||||||
|
.inputSchema(feedbackSchema)
|
||||||
|
.action(async ({ ctx, parsedInput }) => {
|
||||||
const { success } = await rateLimit("submitFeedback", 3, "1h");
|
const { success } = await rateLimit("submitFeedback", 3, "1h");
|
||||||
|
|
||||||
if (!success) {
|
if (!success) {
|
||||||
|
@ -16,13 +19,12 @@ export const submitFeedback = async (formData: Feedback) => {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const user = await requireUser();
|
|
||||||
try {
|
try {
|
||||||
const { content } = feedbackSchema.parse(formData);
|
const { content } = parsedInput;
|
||||||
getEmailClient().sendEmail({
|
getEmailClient().sendEmail({
|
||||||
to: "feedback@rallly.co",
|
to: "feedback@rallly.co",
|
||||||
subject: "Feedback",
|
subject: "Feedback",
|
||||||
text: `User: ${user.name} (${user.email})\n\n${content}`,
|
text: `User: ${ctx.user.name} (${ctx.user.email})\n\n${content}`,
|
||||||
});
|
});
|
||||||
return {
|
return {
|
||||||
success: true,
|
success: true,
|
||||||
|
@ -32,4 +34,4 @@ export const submitFeedback = async (formData: Feedback) => {
|
||||||
error: "Invalid Form Data" as const,
|
error: "Invalid Form Data" as const,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
|
|
|
@ -24,12 +24,14 @@ import { useForm } from "react-hook-form";
|
||||||
|
|
||||||
import { Trans } from "@/components/trans";
|
import { Trans } from "@/components/trans";
|
||||||
|
|
||||||
|
import { useSafeAction } from "@/features/safe-action/client";
|
||||||
import { isSelfHosted } from "@/utils/constants";
|
import { isSelfHosted } from "@/utils/constants";
|
||||||
import { submitFeedback } from "../actions";
|
import { submitFeedbackAction } from "../actions";
|
||||||
import type { Feedback } from "../schema";
|
import type { Feedback } from "../schema";
|
||||||
import { feedbackSchema } from "../schema";
|
import { feedbackSchema } from "../schema";
|
||||||
|
|
||||||
export function FeedbackToggle() {
|
export function FeedbackToggle() {
|
||||||
|
const submitFeedback = useSafeAction(submitFeedbackAction);
|
||||||
const form = useForm<Feedback>({
|
const form = useForm<Feedback>({
|
||||||
resolver: zodResolver(feedbackSchema),
|
resolver: zodResolver(feedbackSchema),
|
||||||
});
|
});
|
||||||
|
@ -72,17 +74,7 @@ export function FeedbackToggle() {
|
||||||
</DialogHeader>
|
</DialogHeader>
|
||||||
|
|
||||||
<Form {...form}>
|
<Form {...form}>
|
||||||
<form
|
<form onSubmit={form.handleSubmit(submitFeedback.executeAsync)}>
|
||||||
onSubmit={form.handleSubmit(async (data) => {
|
|
||||||
const res = await submitFeedback(data);
|
|
||||||
|
|
||||||
if (res.error) {
|
|
||||||
form.setError("content", {
|
|
||||||
message: res.error,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
})}
|
|
||||||
>
|
|
||||||
<FormField
|
<FormField
|
||||||
control={form.control}
|
control={form.control}
|
||||||
name="content"
|
name="content"
|
||||||
|
|
|
@ -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);
|
|
||||||
}
|
|
Loading…
Add table
Add a link
Reference in a new issue