mirror of
https://github.com/formbricks/formbricks.git
synced 2026-02-09 18:58:46 -06:00
Compare commits
2 Commits
main
...
fix/7190-s
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
44dcd2c2f9 | ||
|
|
1c97ab3579 |
@@ -7,7 +7,6 @@ import { useTranslation } from "react-i18next";
|
||||
import { TOrganization } from "@formbricks/types/organizations";
|
||||
import { deleteOrganizationAction } from "@/app/(app)/environments/[environmentId]/settings/(organization)/general/actions";
|
||||
import { FORMBRICKS_ENVIRONMENT_ID_LS } from "@/lib/localStorage";
|
||||
import { getFormattedErrorMessage } from "@/lib/utils/helper";
|
||||
import { Alert, AlertDescription } from "@/modules/ui/components/alert";
|
||||
import { Button } from "@/modules/ui/components/button";
|
||||
import { DeleteDialog } from "@/modules/ui/components/delete-dialog";
|
||||
@@ -33,12 +32,7 @@ export const DeleteOrganization = ({
|
||||
setIsDeleting(true);
|
||||
|
||||
try {
|
||||
const result = await deleteOrganizationAction({ organizationId: organization.id });
|
||||
if (result?.serverError) {
|
||||
toast.error(getFormattedErrorMessage(result));
|
||||
setIsDeleting(false);
|
||||
return;
|
||||
}
|
||||
await deleteOrganizationAction({ organizationId: organization.id });
|
||||
toast.success(t("environments.settings.general.organization_deleted_successfully"));
|
||||
if (typeof localStorage !== "undefined") {
|
||||
localStorage.removeItem(FORMBRICKS_ENVIRONMENT_ID_LS);
|
||||
|
||||
@@ -21,7 +21,6 @@ import { createOrUpdateIntegrationAction } from "@/app/(app)/environments/[envir
|
||||
import { BaseSelectDropdown } from "@/app/(app)/environments/[environmentId]/workspace/integrations/airtable/components/BaseSelectDropdown";
|
||||
import { fetchTables } from "@/app/(app)/environments/[environmentId]/workspace/integrations/airtable/lib/airtable";
|
||||
import AirtableLogo from "@/images/airtableLogo.svg";
|
||||
import { getFormattedErrorMessage } from "@/lib/utils/helper";
|
||||
import { recallToHeadline } from "@/lib/utils/recall";
|
||||
import { getElementsFromBlocks } from "@/modules/survey/lib/client-utils";
|
||||
import { AdditionalIntegrationSettings } from "@/modules/ui/components/additional-integration-settings";
|
||||
@@ -269,14 +268,7 @@ export const AddIntegrationModal = ({
|
||||
airtableIntegrationData.config?.data.push(integrationData);
|
||||
}
|
||||
|
||||
const result = await createOrUpdateIntegrationAction({
|
||||
environmentId,
|
||||
integrationData: airtableIntegrationData,
|
||||
});
|
||||
if (result?.serverError) {
|
||||
toast.error(getFormattedErrorMessage(result));
|
||||
return;
|
||||
}
|
||||
await createOrUpdateIntegrationAction({ environmentId, integrationData: airtableIntegrationData });
|
||||
if (isEditMode) {
|
||||
toast.success(t("environments.integrations.integration_updated_successfully"));
|
||||
} else {
|
||||
@@ -312,11 +304,7 @@ export const AddIntegrationModal = ({
|
||||
const integrationData = structuredClone(airtableIntegrationData);
|
||||
integrationData.config.data.splice(index, 1);
|
||||
|
||||
const result = await createOrUpdateIntegrationAction({ environmentId, integrationData });
|
||||
if (result?.serverError) {
|
||||
toast.error(getFormattedErrorMessage(result));
|
||||
return;
|
||||
}
|
||||
await createOrUpdateIntegrationAction({ environmentId, integrationData });
|
||||
handleClose();
|
||||
router.refresh();
|
||||
|
||||
|
||||
@@ -165,14 +165,7 @@ export const AddIntegrationModal = ({
|
||||
// create action
|
||||
googleSheetIntegrationData.config.data.push(integrationData);
|
||||
}
|
||||
const result = await createOrUpdateIntegrationAction({
|
||||
environmentId,
|
||||
integrationData: googleSheetIntegrationData,
|
||||
});
|
||||
if (result?.serverError) {
|
||||
toast.error(getFormattedErrorMessage(result));
|
||||
return;
|
||||
}
|
||||
await createOrUpdateIntegrationAction({ environmentId, integrationData: googleSheetIntegrationData });
|
||||
if (selectedIntegration) {
|
||||
toast.success(t("environments.integrations.integration_updated_successfully"));
|
||||
} else {
|
||||
@@ -212,14 +205,7 @@ export const AddIntegrationModal = ({
|
||||
googleSheetIntegrationData.config.data.splice(selectedIntegration!.index, 1);
|
||||
try {
|
||||
setIsDeleting(true);
|
||||
const result = await createOrUpdateIntegrationAction({
|
||||
environmentId,
|
||||
integrationData: googleSheetIntegrationData,
|
||||
});
|
||||
if (result?.serverError) {
|
||||
toast.error(getFormattedErrorMessage(result));
|
||||
return;
|
||||
}
|
||||
await createOrUpdateIntegrationAction({ environmentId, integrationData: googleSheetIntegrationData });
|
||||
toast.success(t("environments.integrations.integration_removed_successfully"));
|
||||
setOpen(false);
|
||||
} catch (error) {
|
||||
@@ -280,7 +266,7 @@ export const AddIntegrationModal = ({
|
||||
<div className="space-y-4">
|
||||
<div>
|
||||
<Label htmlFor="Surveys">{t("common.questions")}</Label>
|
||||
<div className="mt-1 max-h-[15vh] overflow-y-auto overflow-x-hidden rounded-lg border border-slate-200">
|
||||
<div className="mt-1 max-h-[15vh] overflow-x-hidden overflow-y-auto rounded-lg border border-slate-200">
|
||||
<div className="grid content-center rounded-lg bg-slate-50 p-3 text-left text-sm text-slate-900">
|
||||
{surveyElements.map((question) => (
|
||||
<div key={question.id} className="my-1 flex items-center space-x-2">
|
||||
|
||||
@@ -22,7 +22,6 @@ import {
|
||||
createEmptyMapping,
|
||||
} from "@/app/(app)/environments/[environmentId]/workspace/integrations/notion/components/MappingRow";
|
||||
import NotionLogo from "@/images/notion.png";
|
||||
import { getFormattedErrorMessage } from "@/lib/utils/helper";
|
||||
import { recallToHeadline } from "@/lib/utils/recall";
|
||||
import { getElementsFromBlocks } from "@/modules/survey/lib/client-utils";
|
||||
import { Button } from "@/modules/ui/components/button";
|
||||
@@ -218,14 +217,7 @@ export const AddIntegrationModal = ({
|
||||
notionIntegrationData.config.data.push(integrationData);
|
||||
}
|
||||
|
||||
const result = await createOrUpdateIntegrationAction({
|
||||
environmentId,
|
||||
integrationData: notionIntegrationData,
|
||||
});
|
||||
if (result?.serverError) {
|
||||
toast.error(getFormattedErrorMessage(result));
|
||||
return;
|
||||
}
|
||||
await createOrUpdateIntegrationAction({ environmentId, integrationData: notionIntegrationData });
|
||||
if (selectedIntegration) {
|
||||
toast.success(t("environments.integrations.integration_updated_successfully"));
|
||||
} else {
|
||||
@@ -244,14 +236,7 @@ export const AddIntegrationModal = ({
|
||||
notionIntegrationData.config.data.splice(selectedIntegration!.index, 1);
|
||||
try {
|
||||
setIsDeleting(true);
|
||||
const result = await createOrUpdateIntegrationAction({
|
||||
environmentId,
|
||||
integrationData: notionIntegrationData,
|
||||
});
|
||||
if (result?.serverError) {
|
||||
toast.error(getFormattedErrorMessage(result));
|
||||
return;
|
||||
}
|
||||
await createOrUpdateIntegrationAction({ environmentId, integrationData: notionIntegrationData });
|
||||
toast.success(t("environments.integrations.integration_removed_successfully"));
|
||||
setOpen(false);
|
||||
} catch (error) {
|
||||
|
||||
@@ -17,7 +17,6 @@ import { TSurvey } from "@formbricks/types/surveys/types";
|
||||
import { getTextContent } from "@formbricks/types/surveys/validation";
|
||||
import { createOrUpdateIntegrationAction } from "@/app/(app)/environments/[environmentId]/workspace/integrations/actions";
|
||||
import SlackLogo from "@/images/slacklogo.png";
|
||||
import { getFormattedErrorMessage } from "@/lib/utils/helper";
|
||||
import { recallToHeadline } from "@/lib/utils/recall";
|
||||
import { getElementsFromBlocks } from "@/modules/survey/lib/client-utils";
|
||||
import { AdditionalIntegrationSettings } from "@/modules/ui/components/additional-integration-settings";
|
||||
@@ -145,14 +144,7 @@ export const AddChannelMappingModal = ({
|
||||
// create action
|
||||
slackIntegrationData.config.data.push(integrationData);
|
||||
}
|
||||
const result = await createOrUpdateIntegrationAction({
|
||||
environmentId,
|
||||
integrationData: slackIntegrationData,
|
||||
});
|
||||
if (result?.serverError) {
|
||||
toast.error(getFormattedErrorMessage(result));
|
||||
return;
|
||||
}
|
||||
await createOrUpdateIntegrationAction({ environmentId, integrationData: slackIntegrationData });
|
||||
if (selectedIntegration) {
|
||||
toast.success(t("environments.integrations.integration_updated_successfully"));
|
||||
} else {
|
||||
@@ -189,14 +181,7 @@ export const AddChannelMappingModal = ({
|
||||
slackIntegrationData.config.data.splice(selectedIntegration!.index, 1);
|
||||
try {
|
||||
setIsDeleting(true);
|
||||
const result = await createOrUpdateIntegrationAction({
|
||||
environmentId,
|
||||
integrationData: slackIntegrationData,
|
||||
});
|
||||
if (result?.serverError) {
|
||||
toast.error(getFormattedErrorMessage(result));
|
||||
return;
|
||||
}
|
||||
await createOrUpdateIntegrationAction({ environmentId, integrationData: slackIntegrationData });
|
||||
toast.success(t("environments.integrations.integration_removed_successfully"));
|
||||
setOpen(false);
|
||||
} catch (error) {
|
||||
|
||||
@@ -141,52 +141,5 @@ describe("Time Utilities", () => {
|
||||
expect(convertDatesInObject("string")).toBe("string");
|
||||
expect(convertDatesInObject(123)).toBe(123);
|
||||
});
|
||||
|
||||
test("should not convert dates in contactAttributes", () => {
|
||||
const input = {
|
||||
createdAt: "2024-03-20T15:30:00",
|
||||
contactAttributes: {
|
||||
createdAt: "2024-03-20T16:30:00",
|
||||
email: "test@example.com",
|
||||
},
|
||||
};
|
||||
|
||||
const result = convertDatesInObject(input);
|
||||
expect(result.createdAt).toBeInstanceOf(Date);
|
||||
expect(result.contactAttributes.createdAt).toBe("2024-03-20T16:30:00");
|
||||
expect(result.contactAttributes.email).toBe("test@example.com");
|
||||
});
|
||||
|
||||
test("should not convert dates in variables", () => {
|
||||
const input = {
|
||||
updatedAt: "2024-03-20T15:30:00",
|
||||
variables: {
|
||||
createdAt: "2024-03-20T16:30:00",
|
||||
userId: "123",
|
||||
},
|
||||
};
|
||||
|
||||
const result = convertDatesInObject(input);
|
||||
expect(result.updatedAt).toBeInstanceOf(Date);
|
||||
expect(result.variables.createdAt).toBe("2024-03-20T16:30:00");
|
||||
expect(result.variables.userId).toBe("123");
|
||||
});
|
||||
|
||||
test("should not convert dates in data or meta", () => {
|
||||
const input = {
|
||||
createdAt: "2024-03-20T15:30:00",
|
||||
data: {
|
||||
createdAt: "2024-03-20T16:30:00",
|
||||
},
|
||||
meta: {
|
||||
updatedAt: "2024-03-20T17:30:00",
|
||||
},
|
||||
};
|
||||
|
||||
const result = convertDatesInObject(input);
|
||||
expect(result.createdAt).toBeInstanceOf(Date);
|
||||
expect(result.data.createdAt).toBe("2024-03-20T16:30:00");
|
||||
expect(result.meta.updatedAt).toBe("2024-03-20T17:30:00");
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -160,12 +160,7 @@ export const convertDatesInObject = <T>(obj: T): T => {
|
||||
return obj.map((item) => convertDatesInObject(item)) as unknown as T;
|
||||
}
|
||||
const newObj: any = {};
|
||||
const keysToIgnore = new Set(["contactAttributes", "variables", "data", "meta"]);
|
||||
for (const key in obj) {
|
||||
if (keysToIgnore.has(key)) {
|
||||
newObj[key] = obj[key];
|
||||
continue;
|
||||
}
|
||||
if (
|
||||
(key === "createdAt" || key === "updatedAt") &&
|
||||
typeof obj[key] === "string" &&
|
||||
|
||||
@@ -109,13 +109,7 @@ export function SegmentSettings({
|
||||
const handleDeleteSegment = async () => {
|
||||
try {
|
||||
setIsDeletingSegment(true);
|
||||
const result = await deleteSegmentAction({ segmentId: segment.id });
|
||||
|
||||
if (result?.serverError) {
|
||||
toast.error(getFormattedErrorMessage(result));
|
||||
setIsDeletingSegment(false);
|
||||
return;
|
||||
}
|
||||
await deleteSegmentAction({ segmentId: segment.id });
|
||||
|
||||
setIsDeletingSegment(false);
|
||||
toast.success(t("environments.segments.segment_deleted_successfully"));
|
||||
|
||||
@@ -17,7 +17,6 @@ import type {
|
||||
import type { TSurvey } from "@formbricks/types/surveys/types";
|
||||
import { cn } from "@/lib/cn";
|
||||
import { structuredClone } from "@/lib/pollyfills/structuredClone";
|
||||
import { getFormattedErrorMessage } from "@/lib/utils/helper";
|
||||
import {
|
||||
cloneSegmentAction,
|
||||
createSegmentAction,
|
||||
@@ -136,11 +135,7 @@ export function TargetingCard({
|
||||
const handleSaveSegment = async (data: TSegmentUpdateInput) => {
|
||||
try {
|
||||
if (!segment) throw new Error(t("environments.segments.invalid_segment"));
|
||||
const result = await updateSegmentAction({ segmentId: segment.id, environmentId, data });
|
||||
if (result?.serverError) {
|
||||
toast.error(getFormattedErrorMessage(result));
|
||||
return;
|
||||
}
|
||||
await updateSegmentAction({ segmentId: segment.id, environmentId, data });
|
||||
toast.success(t("environments.segments.segment_saved_successfully"));
|
||||
|
||||
setIsSegmentEditorOpen(false);
|
||||
|
||||
@@ -154,12 +154,7 @@ export function EditLanguage({
|
||||
|
||||
const performLanguageDeletion = async (languageId: string) => {
|
||||
try {
|
||||
const result = await deleteLanguageAction({ languageId, projectId: project.id });
|
||||
if (result?.serverError) {
|
||||
toast.error(getFormattedErrorMessage(result));
|
||||
setConfirmationModal((prev) => ({ ...prev, isOpen: false }));
|
||||
return;
|
||||
}
|
||||
await deleteLanguageAction({ languageId, projectId: project.id });
|
||||
setLanguages((prev) => prev.filter((lang) => lang.id !== languageId));
|
||||
toast.success(t("environments.workspace.languages.language_deleted_successfully"));
|
||||
// Close the modal after deletion
|
||||
@@ -192,7 +187,7 @@ export function EditLanguage({
|
||||
|
||||
const handleSaveChanges = async () => {
|
||||
if (!validateLanguages(languages, t)) return;
|
||||
const results = await Promise.all(
|
||||
await Promise.all(
|
||||
languages.map((lang) => {
|
||||
return lang.id === "new"
|
||||
? createLanguageAction({
|
||||
@@ -206,11 +201,6 @@ export function EditLanguage({
|
||||
});
|
||||
})
|
||||
);
|
||||
const errorResult = results.find((result) => result?.serverError);
|
||||
if (errorResult) {
|
||||
toast.error(getFormattedErrorMessage(errorResult));
|
||||
return;
|
||||
}
|
||||
toast.success(t("environments.workspace.languages.languages_updated_successfully"));
|
||||
router.refresh();
|
||||
setIsEditing(false);
|
||||
@@ -249,7 +239,7 @@ export function EditLanguage({
|
||||
))}
|
||||
</>
|
||||
) : (
|
||||
<p className="text-sm italic text-slate-500">
|
||||
<p className="text-sm text-slate-500 italic">
|
||||
{t("environments.workspace.languages.no_language_found")}
|
||||
</p>
|
||||
)}
|
||||
|
||||
@@ -4,7 +4,6 @@ import { useRouter } from "next/navigation";
|
||||
import { useState } from "react";
|
||||
import toast from "react-hot-toast";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { getFormattedErrorMessage } from "@/lib/utils/helper";
|
||||
import { deleteTeamAction } from "@/modules/ee/teams/team-list/actions";
|
||||
import { TTeam } from "@/modules/ee/teams/team-list/types/team";
|
||||
import { Button } from "@/modules/ui/components/button";
|
||||
@@ -28,12 +27,6 @@ export const DeleteTeam = ({ teamId, onDelete, isOwnerOrManager }: DeleteTeamPro
|
||||
setIsDeleting(true);
|
||||
|
||||
const deleteTeamActionResponse = await deleteTeamAction({ teamId });
|
||||
if (deleteTeamActionResponse?.serverError) {
|
||||
toast.error(getFormattedErrorMessage(deleteTeamActionResponse));
|
||||
setIsDeleteDialogOpen(false);
|
||||
setIsDeleting(false);
|
||||
return;
|
||||
}
|
||||
if (deleteTeamActionResponse?.data) {
|
||||
toast.success(t("environments.settings.teams.team_deleted_successfully"));
|
||||
onDelete?.();
|
||||
|
||||
@@ -42,27 +42,14 @@ export const MemberActions = ({ organization, member, invite, showDeleteButton }
|
||||
if (!member && invite) {
|
||||
// This is an invite
|
||||
|
||||
const result = await deleteInviteAction({ inviteId: invite?.id, organizationId: organization.id });
|
||||
if (result?.serverError) {
|
||||
toast.error(getFormattedErrorMessage(result));
|
||||
setIsDeleting(false);
|
||||
return;
|
||||
}
|
||||
await deleteInviteAction({ inviteId: invite?.id, organizationId: organization.id });
|
||||
toast.success(t("environments.settings.general.invite_deleted_successfully"));
|
||||
}
|
||||
|
||||
if (member && !invite) {
|
||||
// This is a member
|
||||
|
||||
const result = await deleteMembershipAction({
|
||||
userId: member.userId,
|
||||
organizationId: organization.id,
|
||||
});
|
||||
if (result?.serverError) {
|
||||
toast.error(getFormattedErrorMessage(result));
|
||||
setIsDeleting(false);
|
||||
return;
|
||||
}
|
||||
await deleteMembershipAction({ userId: member.userId, organizationId: organization.id });
|
||||
toast.success(t("environments.settings.general.member_deleted_successfully"));
|
||||
}
|
||||
|
||||
|
||||
@@ -71,12 +71,7 @@ export const OrganizationActions = ({
|
||||
const handleLeaveOrganization = async () => {
|
||||
setLoading(true);
|
||||
try {
|
||||
const result = await leaveOrganizationAction({ organizationId: organization.id });
|
||||
if (result?.serverError) {
|
||||
toast.error(getFormattedErrorMessage(result));
|
||||
setLoading(false);
|
||||
return;
|
||||
}
|
||||
await leaveOrganizationAction({ organizationId: organization.id });
|
||||
toast.success(t("environments.settings.general.member_deleted_successfully"));
|
||||
router.refresh();
|
||||
setLoading(false);
|
||||
|
||||
@@ -8,7 +8,6 @@ import { FormProvider, useForm } from "react-hook-form";
|
||||
import { toast } from "react-hot-toast";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { TActionClass, TActionClassInput } from "@formbricks/types/action-classes";
|
||||
import { getFormattedErrorMessage } from "@/lib/utils/helper";
|
||||
import {
|
||||
deleteActionClassAction,
|
||||
updateActionClassAction,
|
||||
@@ -93,14 +92,10 @@ export const ActionSettingsTab = ({
|
||||
validatePermissions(isReadOnly, t);
|
||||
const updatedAction = buildActionObject(data, actionClass.environmentId, t);
|
||||
|
||||
const result = await updateActionClassAction({
|
||||
await updateActionClassAction({
|
||||
actionClassId: actionClass.id,
|
||||
updatedAction: updatedAction,
|
||||
});
|
||||
if (result?.serverError) {
|
||||
toast.error(getFormattedErrorMessage(result));
|
||||
return;
|
||||
}
|
||||
setOpen(false);
|
||||
router.refresh();
|
||||
toast.success(t("environments.actions.action_updated_successfully"));
|
||||
@@ -114,11 +109,7 @@ export const ActionSettingsTab = ({
|
||||
const handleDeleteAction = async () => {
|
||||
try {
|
||||
setIsDeletingAction(true);
|
||||
const result = await deleteActionClassAction({ actionClassId: actionClass.id });
|
||||
if (result?.serverError) {
|
||||
toast.error(getFormattedErrorMessage(result));
|
||||
return;
|
||||
}
|
||||
await deleteActionClassAction({ actionClassId: actionClass.id });
|
||||
router.refresh();
|
||||
toast.success(t("environments.actions.action_deleted_successfully"));
|
||||
setOpen(false);
|
||||
|
||||
@@ -69,11 +69,7 @@ export const SurveyDropDownMenu = ({
|
||||
const handleDeleteSurvey = async (surveyId: string) => {
|
||||
setLoading(true);
|
||||
try {
|
||||
const result = await deleteSurveyAction({ surveyId });
|
||||
if (result?.serverError) {
|
||||
toast.error(getFormattedErrorMessage(result));
|
||||
return;
|
||||
}
|
||||
await deleteSurveyAction({ surveyId });
|
||||
deleteSurvey(surveyId);
|
||||
toast.success(t("environments.surveys.survey_deleted_successfully"));
|
||||
} catch (error) {
|
||||
|
||||
@@ -19,8 +19,6 @@ import tailwindcss from "@tailwindcss/vite";
|
||||
*/
|
||||
export default defineConfig({
|
||||
build: {
|
||||
// Keep dist when running watch so surveys (and others) can resolve types during parallel go
|
||||
emptyOutDir: false,
|
||||
lib: {
|
||||
entry: "src/index.ts",
|
||||
formats: ["es"],
|
||||
|
||||
@@ -7,8 +7,7 @@
|
||||
"jsx": "react-jsx",
|
||||
"jsxImportSource": "preact",
|
||||
"paths": {
|
||||
"@/*": ["./src/*"],
|
||||
"@formbricks/survey-ui": ["../survey-ui"]
|
||||
"@/*": ["./src/*"]
|
||||
},
|
||||
"resolveJsonModule": true
|
||||
},
|
||||
|
||||
@@ -88,16 +88,16 @@
|
||||
"persistent": true
|
||||
},
|
||||
"@formbricks/surveys#build": {
|
||||
"dependsOn": ["^build", "@formbricks/survey-ui#build"],
|
||||
"dependsOn": ["^build"],
|
||||
"outputs": ["dist/**"]
|
||||
},
|
||||
"@formbricks/surveys#build:dev": {
|
||||
"dependsOn": ["^build:dev", "@formbricks/i18n-utils#build", "@formbricks/survey-ui#build:dev"],
|
||||
"dependsOn": ["^build:dev", "@formbricks/i18n-utils#build"],
|
||||
"outputs": ["dist/**"]
|
||||
},
|
||||
"@formbricks/surveys#go": {
|
||||
"cache": false,
|
||||
"dependsOn": ["@formbricks/survey-ui#build", "@formbricks/surveys#build"],
|
||||
"dependsOn": ["@formbricks/surveys#build"],
|
||||
"persistent": true
|
||||
},
|
||||
"@formbricks/surveys#test": {
|
||||
|
||||
Reference in New Issue
Block a user