feat: refactor organization update actions for name and AI settings

Updated the organization update actions to separate the handling of organization name and AI settings. Introduced `updateOrganizationNameAction` and `updateOrganizationAISettingsAction` for more specific updates. Adjusted related components to utilize the new actions accordingly.
This commit is contained in:
Dhruwang
2026-03-02 14:13:02 +05:30
parent 03ec8603bb
commit 421a732875
3 changed files with 79 additions and 42 deletions

View File

@@ -11,48 +11,85 @@ import { AuthenticatedActionClientCtx } from "@/lib/utils/action-client/types/co
import { withAuditLogging } from "@/modules/ee/audit-logs/lib/handler";
import { getIsMultiOrgEnabled } from "@/modules/ee/license-check/lib/utils";
const ZUpdateOrganizationAction = z.object({
const ZUpdateOrganizationNameAction = z.object({
organizationId: ZId,
data: ZOrganizationUpdateInput.partial().refine(
(data) => Object.keys(data ?? {}).length > 0,
"At least one field must be provided"
),
data: ZOrganizationUpdateInput.pick({ name: true }),
});
type UpdateOrganizationParsedInput = z.infer<typeof ZUpdateOrganizationAction>;
export const updateOrganizationNameAction = authenticatedActionClient
.schema(ZUpdateOrganizationNameAction)
.action(
withAuditLogging(
"updated",
"organization",
async ({
ctx,
parsedInput,
}: {
ctx: AuthenticatedActionClientCtx;
parsedInput: z.infer<typeof ZUpdateOrganizationNameAction>;
}) => {
await checkAuthorizationUpdated({
userId: ctx.user.id,
organizationId: parsedInput.organizationId,
access: [
{
type: "organization",
schema: ZOrganizationUpdateInput.pick({ name: true }),
data: parsedInput.data,
roles: ["owner"],
},
],
});
ctx.auditLoggingCtx.organizationId = parsedInput.organizationId;
const oldObject = await getOrganization(parsedInput.organizationId);
const result = await updateOrganization(parsedInput.organizationId, parsedInput.data);
ctx.auditLoggingCtx.oldObject = oldObject;
ctx.auditLoggingCtx.newObject = result;
return result;
}
)
);
export const updateOrganizationAction = authenticatedActionClient.schema(ZUpdateOrganizationAction).action(
withAuditLogging(
"updated",
"organization",
async ({
ctx,
parsedInput,
}: {
ctx: AuthenticatedActionClientCtx;
parsedInput: UpdateOrganizationParsedInput;
}) => {
await checkAuthorizationUpdated({
userId: ctx.user.id,
organizationId: parsedInput.organizationId,
access: [
{
type: "organization",
schema: ZOrganizationUpdateInput.partial(),
data: parsedInput.data,
roles: ["owner", "manager"],
},
],
});
ctx.auditLoggingCtx.organizationId = parsedInput.organizationId;
const oldObject = await getOrganization(parsedInput.organizationId);
const result = await updateOrganization(parsedInput.organizationId, parsedInput.data);
ctx.auditLoggingCtx.oldObject = oldObject;
ctx.auditLoggingCtx.newObject = result;
return result;
}
)
);
const ZUpdateOrganizationAISettingsAction = z.object({
organizationId: ZId,
data: ZOrganizationUpdateInput.pick({ isAIEnabled: true }),
});
export const updateOrganizationAISettingsAction = authenticatedActionClient
.schema(ZUpdateOrganizationAISettingsAction)
.action(
withAuditLogging(
"updated",
"organization",
async ({
ctx,
parsedInput,
}: {
ctx: AuthenticatedActionClientCtx;
parsedInput: z.infer<typeof ZUpdateOrganizationAISettingsAction>;
}) => {
await checkAuthorizationUpdated({
userId: ctx.user.id,
organizationId: parsedInput.organizationId,
access: [
{
type: "organization",
schema: ZOrganizationUpdateInput.pick({ isAIEnabled: true }),
data: parsedInput.data,
roles: ["owner", "manager"],
},
],
});
ctx.auditLoggingCtx.organizationId = parsedInput.organizationId;
const oldObject = await getOrganization(parsedInput.organizationId);
const result = await updateOrganization(parsedInput.organizationId, parsedInput.data);
ctx.auditLoggingCtx.oldObject = oldObject;
ctx.auditLoggingCtx.newObject = result;
return result;
}
)
);
const ZDeleteOrganizationAction = z.object({
organizationId: ZId,

View File

@@ -6,7 +6,7 @@ import toast from "react-hot-toast";
import { useTranslation } from "react-i18next";
import { TOrganizationRole } from "@formbricks/types/memberships";
import { TOrganization } from "@formbricks/types/organizations";
import { updateOrganizationAction } from "@/app/(app)/environments/[environmentId]/settings/(organization)/general/actions";
import { updateOrganizationAISettingsAction } from "@/app/(app)/environments/[environmentId]/settings/(organization)/general/actions";
import { getAccessFlags } from "@/lib/membership/utils";
import { getFormattedErrorMessage } from "@/lib/utils/helper";
import { Alert, AlertDescription } from "@/modules/ui/components/alert";
@@ -29,7 +29,7 @@ export const AISettingsToggle = ({ organization, membershipRole }: Readonly<AISe
const handleSwitchChange = async (checked: boolean) => {
setIsLoading(true);
try {
const response = await updateOrganizationAction({
const response = await updateOrganizationAISettingsAction({
organizationId: organization.id,
data: { isAIEnabled: checked },
});

View File

@@ -7,7 +7,7 @@ import { useTranslation } from "react-i18next";
import { z } from "zod";
import { TOrganizationRole } from "@formbricks/types/memberships";
import { TOrganization, ZOrganization } from "@formbricks/types/organizations";
import { updateOrganizationAction } from "@/app/(app)/environments/[environmentId]/settings/(organization)/general/actions";
import { updateOrganizationNameAction } from "@/app/(app)/environments/[environmentId]/settings/(organization)/general/actions";
import { getAccessFlags } from "@/lib/membership/utils";
import { getFormattedErrorMessage } from "@/lib/utils/helper";
import { Alert, AlertDescription } from "@/modules/ui/components/alert";
@@ -48,7 +48,7 @@ export const EditOrganizationNameForm = ({ organization, membershipRole }: EditO
const handleUpdateOrganizationName: SubmitHandler<EditOrganizationNameForm> = async (data) => {
try {
const name = data.name.trim();
const updatedOrganizationResponse = await updateOrganizationAction({
const updatedOrganizationResponse = await updateOrganizationNameAction({
organizationId: organization.id,
data: { name },
});