diff --git a/apps/formbricks-com/pages/api/oss-friends/index.ts b/apps/formbricks-com/pages/api/oss-friends/index.ts
index 1f31e4b3dd..97546e55ed 100644
--- a/apps/formbricks-com/pages/api/oss-friends/index.ts
+++ b/apps/formbricks-com/pages/api/oss-friends/index.ts
@@ -37,7 +37,7 @@ export default async function handle(req: NextApiRequest, res: NextApiResponse)
{
name: "Erxes",
description:
- "The Open-Source HubSpot Alternative. A single XOS enables to create unique and life-changing experiences that work for all types of business.",
+ "The Open-Source HubSpot Alternative. A single XOS enables to create unique and life-changing experiences that work for all types of business.",
href: "https://erxes.io",
},
{
@@ -46,6 +46,12 @@ export default async function handle(req: NextApiRequest, res: NextApiResponse)
"Survey granular user segments at any point in the user journey. Gather up to 6x more insights with targeted micro-surveys. All open-source.",
href: "https://formbricks.com",
},
+ {
+ name: "Ghostfolio",
+ description:
+ "Ghostfolio is a privacy-first, open source dashboard for your personal finances. Designed to simplify asset tracking and empower informed investment decisions.",
+ href: "https://ghostfol.io",
+ },
{
name: "GitWonk",
description:
diff --git a/apps/web/app/(app)/environments/[environmentId]/people/[personId]/DeletePersonButton.tsx b/apps/web/app/(app)/environments/[environmentId]/people/[personId]/DeletePersonButton.tsx
new file mode 100644
index 0000000000..2e233bce4d
--- /dev/null
+++ b/apps/web/app/(app)/environments/[environmentId]/people/[personId]/DeletePersonButton.tsx
@@ -0,0 +1,50 @@
+"use client";
+
+import { deletePersonAction } from "@/app/(app)/environments/[environmentId]/people/[personId]/actions";
+import DeleteDialog from "@/components/shared/DeleteDialog";
+import { TrashIcon } from "lucide-react";
+import { useRouter } from "next/navigation";
+import { useState } from "react";
+import toast from "react-hot-toast";
+
+interface DeletePersonButtonProps {
+ environmentId: string;
+ personId: string;
+}
+
+export function DeletePersonButton({ environmentId, personId }: DeletePersonButtonProps) {
+ const router = useRouter();
+
+ const [deleteDialogOpen, setDeleteDialogOpen] = useState(false);
+ const [isDeletingPerson, setIsDeletingPerson] = useState(false);
+
+ const handleDeletePerson = async () => {
+ try {
+ setIsDeletingPerson(true);
+ await deletePersonAction(personId);
+ router.push(`/environments/${environmentId}/people`);
+ toast.success("Person deleted successfully.");
+ } catch (error) {
+ toast.error(error.message);
+ } finally {
+ setIsDeletingPerson(false);
+ }
+ };
+ return (
+ <>
+
+
+ >
+ );
+}
diff --git a/apps/web/app/(app)/environments/[environmentId]/people/[personId]/HeadingSection.tsx b/apps/web/app/(app)/environments/[environmentId]/people/[personId]/HeadingSection.tsx
index 7652f6d830..a7ccdb7d4e 100644
--- a/apps/web/app/(app)/environments/[environmentId]/people/[personId]/HeadingSection.tsx
+++ b/apps/web/app/(app)/environments/[environmentId]/people/[personId]/HeadingSection.tsx
@@ -1,39 +1,18 @@
-"use client";
-
-import DeleteDialog from "@/components/shared/DeleteDialog";
import GoBackButton from "@/components/shared/GoBackButton";
-import { deletePersonAction } from "./actions";
-import { TPerson } from "@formbricks/types/v1/people";
-import { TrashIcon } from "lucide-react";
-import { useRouter } from "next/navigation";
-import { useState } from "react";
-import toast from "react-hot-toast";
+import { DeletePersonButton } from "./DeletePersonButton";
+import { getPerson } from "@formbricks/lib/services/person";
-export default function HeadingSection({
- environmentId,
- person,
-}: {
+interface HeadingSectionProps {
environmentId: string;
- person: TPerson;
-}) {
- const router = useRouter();
+ personId: string;
+}
- const [deleteDialogOpen, setDeleteDialogOpen] = useState(false);
- const [isDeletingPerson, setIsDeletingPerson] = useState(false);
-
- const handleDeletePerson = async () => {
- try {
- setIsDeletingPerson(true);
- await deletePersonAction(person.id);
- router.push(`/environments/${environmentId}/people`);
- toast.success("Person deleted successfully.");
- } catch (error) {
- toast.error(error.message);
- } finally {
- setIsDeletingPerson(false);
- }
- };
+export default async function HeadingSection({ environmentId, personId }: HeadingSectionProps) {
+ const person = await getPerson(personId);
+ if (!person) {
+ throw new Error("No such person found");
+ }
return (
<>
@@ -42,21 +21,9 @@ export default function HeadingSection({
{person.attributes.email || person.id}
-
+
-
>
);
}
diff --git a/apps/web/app/(app)/environments/[environmentId]/people/[personId]/page.tsx b/apps/web/app/(app)/environments/[environmentId]/people/[personId]/page.tsx
index 0e1b4058d4..02fd8bc4db 100644
--- a/apps/web/app/(app)/environments/[environmentId]/people/[personId]/page.tsx
+++ b/apps/web/app/(app)/environments/[environmentId]/people/[personId]/page.tsx
@@ -1,23 +1,17 @@
export const revalidate = REVALIDATION_INTERVAL;
-import { REVALIDATION_INTERVAL } from "@formbricks/lib/constants";
-import { getPerson } from "@formbricks/lib/services/person";
-import AttributesSection from "@/app/(app)/environments/[environmentId]/people/[personId]/(attributeSection)/AttributesSection";
import ActivitySection from "@/app/(app)/environments/[environmentId]/people/[personId]/(activitySection)/ActivitySection";
-import HeadingSection from "@/app/(app)/environments/[environmentId]/people/[personId]/HeadingSection";
+import AttributesSection from "@/app/(app)/environments/[environmentId]/people/[personId]/(attributeSection)/AttributesSection";
import ResponseSection from "@/app/(app)/environments/[environmentId]/people/[personId]/(responseSection)/ResponseSection";
+import HeadingSection from "@/app/(app)/environments/[environmentId]/people/[personId]/HeadingSection";
+import { REVALIDATION_INTERVAL } from "@formbricks/lib/constants";
export default async function PersonPage({ params }) {
- const person = await getPerson(params.personId);
- if (!person) {
- throw new Error("No such person found");
- }
-
return (
<>
-
+
diff --git a/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/SummaryHeader.tsx b/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/SummaryHeader.tsx
index 04113ca12a..50200bae19 100644
--- a/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/SummaryHeader.tsx
+++ b/apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/SummaryHeader.tsx
@@ -70,7 +70,7 @@ const SummaryHeader = ({ surveyId, environmentId, survey }: SummaryHeaderProps)
-
+
diff --git a/apps/web/components/shared/SurveyStatusDropdown.tsx b/apps/web/components/shared/SurveyStatusDropdown.tsx
index 8a9feda8e2..ae4f572358 100644
--- a/apps/web/components/shared/SurveyStatusDropdown.tsx
+++ b/apps/web/components/shared/SurveyStatusDropdown.tsx
@@ -52,33 +52,31 @@ export default function SurveyStatusDropdown({
{survey.status === "archived" && Archived
}
) : (
-
-
-
-
-
- To update the survey status, update the “Close
-
survey on date” setting in the Response Options.
-
-
-
+
+
+
+
+ In-progress
+
+
+
+ Paused
+
+
+
+ Completed
+
+
+
+
+ To update the survey status, update the “Close
+
survey on date” setting in the Response Options.
+
+
+
+
)}
>
);
diff --git a/packages/database/schema.prisma b/packages/database/schema.prisma
index 8042ca489d..3290727e0c 100644
--- a/packages/database/schema.prisma
+++ b/packages/database/schema.prisma
@@ -328,7 +328,7 @@ model Product {
teamId String
environments Environment[]
brandColor String @default("#64748b")
- highlightBorderColor String?
+ highlightBorderColor String?
recontactDays Int @default(7)
formbricksSignature Boolean @default(true)
placement WidgetPlacement @default(bottomRight)
diff --git a/packages/lib/constants.ts b/packages/lib/constants.ts
index 9cb888f9d9..7a6f7bd04e 100644
--- a/packages/lib/constants.ts
+++ b/packages/lib/constants.ts
@@ -1,6 +1,6 @@
export const RESPONSES_LIMIT_FREE = 100;
export const IS_FORMBRICKS_CLOUD = process.env.NEXT_PUBLIC_IS_FORMBRICKS_CLOUD === "1";
-export const REVALIDATION_INTERVAL = process.env.NODE_ENV === "production" ? 30 : 0; // 30 seconds in production, 10 seconds in development
+export const REVALIDATION_INTERVAL = 0; //TODO: find a good way to cache and revalidate data when it changes
// URLs
const VERCEL_URL = process.env.NEXT_PUBLIC_VERCEL_URL ? `https://${process.env.NEXT_PUBLIC_VERCEL_URL}` : "";
diff --git a/packages/lib/services/person.ts b/packages/lib/services/person.ts
index f26dd3d4ff..c47d73e50f 100644
--- a/packages/lib/services/person.ts
+++ b/packages/lib/services/person.ts
@@ -53,7 +53,7 @@ export const transformPrismaPerson = (person: TransformPersonInput): TPerson =>
};
};
-export const getPerson = async (personId: string): Promise => {
+export const getPerson = cache(async (personId: string): Promise => {
try {
const personPrisma = await prisma.person.findUnique({
where: {
@@ -76,7 +76,7 @@ export const getPerson = async (personId: string): Promise => {
throw error;
}
-};
+});
export const getPeople = cache(async (environmentId: string): Promise => {
try {