From cda85134102c4f2a1ff185d31365e7cd6c7429f7 Mon Sep 17 00:00:00 2001 From: Johannes <72809645+jobenjada@users.noreply.github.com> Date: Mon, 29 May 2023 11:46:07 +0200 Subject: [PATCH] Formbricks Branding Signature (#305) * Add Formbricks Signature Branding (can be deactivated in Look & Feel Settings) --------- Co-authored-by: Matthias Nannt --- .../[environmentId]/settings/SettingsCard.tsx | 4 +- .../settings/lookandfeel/editLookAndFeel.tsx | 64 ++++++++++++++----- .../settings/lookandfeel/page.tsx | 7 +- .../settings/notifications/EditAlerts.tsx | 2 +- .../[environmentId]/surveys/PreviewSurvey.tsx | 26 ++++---- apps/web/app/s/[surveyId]/LinkSurvey.tsx | 5 +- .../preview/FormbricksSignature.tsx | 15 +++++ apps/web/components/preview/ThankYouCard.tsx | 15 ----- apps/web/lib/api/clientSettings.ts | 4 +- .../api/v1/client/surveys/[surveyId]/index.ts | 18 ++++-- .../migration.sql | 2 + .../migration.sql | 2 + packages/database/prisma/schema.prisma | 19 +++--- packages/js/src/App.tsx | 8 +-- .../js/src/components/FormbricksSignature.tsx | 17 +++++ packages/js/src/components/SurveyView.tsx | 9 +-- packages/js/src/components/ThankYouCard.tsx | 15 ----- packages/types/js.ts | 1 + 18 files changed, 142 insertions(+), 91 deletions(-) create mode 100644 apps/web/components/preview/FormbricksSignature.tsx create mode 100644 packages/database/prisma/migrations/20230529092700_add_formbricks_signature_to_product/migration.sql create mode 100644 packages/database/prisma/migrations/20230529092737_make_formbricks_signature_default/migration.sql create mode 100644 packages/js/src/components/FormbricksSignature.tsx diff --git a/apps/web/app/environments/[environmentId]/settings/SettingsCard.tsx b/apps/web/app/environments/[environmentId]/settings/SettingsCard.tsx index 530f49fb26..4c9b1c7010 100644 --- a/apps/web/app/environments/[environmentId]/settings/SettingsCard.tsx +++ b/apps/web/app/environments/[environmentId]/settings/SettingsCard.tsx @@ -18,8 +18,8 @@ export default function SettingsCard({
-

{title}

- {soon && } +

{title}

+ {soon && }

{description}

diff --git a/apps/web/app/environments/[environmentId]/settings/lookandfeel/editLookAndFeel.tsx b/apps/web/app/environments/[environmentId]/settings/lookandfeel/editLookAndFeel.tsx index 33d369f924..e1c54a03df 100644 --- a/apps/web/app/environments/[environmentId]/settings/lookandfeel/editLookAndFeel.tsx +++ b/apps/web/app/environments/[environmentId]/settings/lookandfeel/editLookAndFeel.tsx @@ -1,5 +1,6 @@ "use client"; +import { cn } from "@formbricks/lib/cn"; import LoadingSpinner from "@/components/shared/LoadingSpinner"; import { useEnvironment } from "@/lib/environments/environments"; import { useProductMutation } from "@/lib/products/mutateProducts"; @@ -18,7 +19,6 @@ import toast from "react-hot-toast"; export function EditBrandColor({ environmentId }) { const { product, isLoadingProduct, isErrorProduct } = useProduct(environmentId); - const { triggerProductMutate, isMutatingProduct } = useProductMutation(environmentId); const [color, setColor] = useState(""); @@ -54,7 +54,6 @@ export function EditBrandColor({ environmentId }) { }}> Save - {/*
{JSON.stringify(environment, null, 2)}
; */}
); } @@ -89,7 +88,11 @@ export function EditPlacement({ environmentId }) { checked={placement.default} disabled={placement.disabled} /> - + ))} @@ -100,31 +103,58 @@ export function EditPlacement({ environmentId }) { - {/*
{JSON.stringify(environment, null, 2)}
; */} ); } export function EditFormbricksSignature({ environmentId }) { const { isLoadingEnvironment, isErrorEnvironment } = useEnvironment(environmentId); + const { product, isLoadingProduct, isErrorProduct } = useProduct(environmentId); + const { triggerProductMutate, isMutatingProduct } = useProductMutation(environmentId); - if (isLoadingEnvironment) { + const [formbricksSignature, setFormbricksSignature] = useState(false); + + useEffect(() => { + if (product) { + setFormbricksSignature(product.formbricksSignature); + } + }, [product]); + + const toggleSignature = () => { + const newSignatureState = !formbricksSignature; + setFormbricksSignature(newSignatureState); + triggerProductMutate({ formbricksSignature: newSignatureState }) + .then(() => { + toast.success(newSignatureState ? "Formbricks signature shown." : "Formbricks signature hidden."); + }) + .catch((error) => { + toast.error(`Error: ${error.message}`); + }); + }; + + if (isLoadingEnvironment || isLoadingProduct) { return ; } - if (isErrorEnvironment) { + + if (isErrorEnvironment || isErrorProduct) { return ; } - return ( -
-
- - + if (formbricksSignature !== null) { + return ( +
+
+ + +
- - {/*
{JSON.stringify(environment, null, 2)}
; */} -
- ); + ); + } + + return null; } diff --git a/apps/web/app/environments/[environmentId]/settings/lookandfeel/page.tsx b/apps/web/app/environments/[environmentId]/settings/lookandfeel/page.tsx index 40aa5039b3..c9f70203dd 100644 --- a/apps/web/app/environments/[environmentId]/settings/lookandfeel/page.tsx +++ b/apps/web/app/environments/[environmentId]/settings/lookandfeel/page.tsx @@ -11,14 +11,13 @@ export default function ProfileSettingsPage({ params }: { params: { environmentI + title="In-app Survey Placement" + description="Change where surveys will be shown in your web app."> + description="We love your support but understand if you toggle it off.">
diff --git a/apps/web/app/environments/[environmentId]/settings/notifications/EditAlerts.tsx b/apps/web/app/environments/[environmentId]/settings/notifications/EditAlerts.tsx index 7110e870ca..6bfeae6048 100644 --- a/apps/web/app/environments/[environmentId]/settings/notifications/EditAlerts.tsx +++ b/apps/web/app/environments/[environmentId]/settings/notifications/EditAlerts.tsx @@ -104,7 +104,7 @@ export default function EditAlerts({ memberships, user, environmentId }: EditAle

Want to loop in team mates?{" "} - + Invite them.

diff --git a/apps/web/app/environments/[environmentId]/surveys/PreviewSurvey.tsx b/apps/web/app/environments/[environmentId]/surveys/PreviewSurvey.tsx index 2bdd0703ba..bf85336893 100644 --- a/apps/web/app/environments/[environmentId]/surveys/PreviewSurvey.tsx +++ b/apps/web/app/environments/[environmentId]/surveys/PreviewSurvey.tsx @@ -3,9 +3,11 @@ import Progress from "@/components/preview/Progress"; import QuestionConditional from "@/components/preview/QuestionConditional"; import ThankYouCard from "@/components/preview/ThankYouCard"; import { useEnvironment } from "@/lib/environments/environments"; +import { useProduct } from "@/lib/products/products"; import type { Logic, Question } from "@formbricks/types/questions"; import { Survey } from "@formbricks/types/surveys"; import { useEffect, useState } from "react"; +import FormbricksSignature from "@/components/preview/FormbricksSignature"; interface PreviewSurveyProps { setActiveQuestionId: (id: string | null) => void; @@ -28,11 +30,20 @@ export default function PreviewSurvey({ thankYouCard, previewType, }: PreviewSurveyProps) { + const { environment } = useEnvironment(environmentId); + const { product } = useProduct(environmentId); + const [isModalOpen, setIsModalOpen] = useState(true); const [progress, setProgress] = useState(0); // [0, 1] const [widgetSetupCompleted, setWidgetSetupCompleted] = useState(false); - const { environment } = useEnvironment(environmentId); const [lastActiveQuestionId, setLastActiveQuestionId] = useState(""); + const [showFormbricksSignature, setShowFormbricksSignature] = useState(false); + + useEffect(() => { + if (product) { + setShowFormbricksSignature(product.formbricksSignature); + } + }, [product]); useEffect(() => { if (activeQuestionId) { @@ -155,15 +166,6 @@ export default function PreviewSurvey({ } }; - /* const resetPreview = () => { - setIsModalOpen(false); - setTimeout(() => { - setActiveQuestionId(questions[0].id); - setIsModalOpen(true); - }, 500); - }; - */ - useEffect(() => { if (environment && environment.widgetSetupCompleted) { setWidgetSetupCompleted(true); @@ -217,6 +219,7 @@ export default function PreviewSurvey({ ) : null ) )} + {showFormbricksSignature && } @@ -246,8 +249,9 @@ export default function PreviewSurvey({
-
+
+ {showFormbricksSignature && }
diff --git a/apps/web/app/s/[surveyId]/LinkSurvey.tsx b/apps/web/app/s/[surveyId]/LinkSurvey.tsx index b22e9f9f7b..692967291c 100644 --- a/apps/web/app/s/[surveyId]/LinkSurvey.tsx +++ b/apps/web/app/s/[surveyId]/LinkSurvey.tsx @@ -1,5 +1,6 @@ "use client"; +import FormbricksSignature from "@/components/preview/FormbricksSignature"; import Progress from "@/components/preview/Progress"; import QuestionConditional from "@/components/preview/QuestionConditional"; import ThankYouCard from "@/components/preview/ThankYouCard"; @@ -16,6 +17,7 @@ import { useEffect, useState } from "react"; type EnhancedSurvey = Survey & { brandColor: string; + formbricksSignature: boolean; }; interface LinkSurveyProps { @@ -235,8 +237,9 @@ export default function LinkSurvey({ survey }: LinkSurveyProps) {
-
+
+ {survey.formbricksSignature && }
diff --git a/apps/web/components/preview/FormbricksSignature.tsx b/apps/web/components/preview/FormbricksSignature.tsx new file mode 100644 index 0000000000..be57ab9cc4 --- /dev/null +++ b/apps/web/components/preview/FormbricksSignature.tsx @@ -0,0 +1,15 @@ +export default function FormbricksSignature() { + return ( + +

+ Powered by{" "} + + Formbricks + +

+
+ ); +} diff --git a/apps/web/components/preview/ThankYouCard.tsx b/apps/web/components/preview/ThankYouCard.tsx index 9d34466083..a7e984476b 100644 --- a/apps/web/components/preview/ThankYouCard.tsx +++ b/apps/web/components/preview/ThankYouCard.tsx @@ -32,21 +32,6 @@ export default function ThankYouCard({ headline, subheader, brandColor }: ThankY
- - {/* - -
-

- Powered by{" "} - - - Formbricks - - -

-
*/} ); } diff --git a/apps/web/lib/api/clientSettings.ts b/apps/web/lib/api/clientSettings.ts index 091750815b..2cb5a316c2 100644 --- a/apps/web/lib/api/clientSettings.ts +++ b/apps/web/lib/api/clientSettings.ts @@ -202,12 +202,14 @@ export const getSettings = async (environmentId: string, personId: string): Prom product: { select: { brandColor: true, + formbricksSignature: true, }, }, }, }); + const formbricksSignature = environmentProdut?.product.formbricksSignature; const brandColor = environmentProdut?.product.brandColor; - return { surveys, noCodeEvents, brandColor }; + return { surveys, noCodeEvents, brandColor, formbricksSignature }; }; diff --git a/apps/web/pages/api/v1/client/surveys/[surveyId]/index.ts b/apps/web/pages/api/v1/client/surveys/[surveyId]/index.ts index 30b631379b..ee588636d6 100644 --- a/apps/web/pages/api/v1/client/surveys/[surveyId]/index.ts +++ b/apps/web/pages/api/v1/client/surveys/[surveyId]/index.ts @@ -46,17 +46,27 @@ export default async function handle(req: NextApiRequest, res: NextApiResponse) }, select: { brandColor: true, + formbricksSignature: true, }, }); if (survey.status !== "inProgress") { - return res - .status(403) - .json({ message: "Survey not running", reason: survey.status, brandColor: product?.brandColor }); + return res.status(403).json({ + message: "Survey not running", + reason: survey.status, + brandColor: product?.brandColor, + formbricksSignature: product?.formbricksSignature, + }); } // if survey exists, return survey - return res.status(200).json({ ...survey, brandColor: product?.brandColor }); + return res + .status(200) + .json({ + ...survey, + brandColor: product?.brandColor, + formbricksSignature: product?.formbricksSignature, + }); } // Unknown HTTP Method diff --git a/packages/database/prisma/migrations/20230529092700_add_formbricks_signature_to_product/migration.sql b/packages/database/prisma/migrations/20230529092700_add_formbricks_signature_to_product/migration.sql new file mode 100644 index 0000000000..f688e238b3 --- /dev/null +++ b/packages/database/prisma/migrations/20230529092700_add_formbricks_signature_to_product/migration.sql @@ -0,0 +1,2 @@ +-- AlterTable +ALTER TABLE "Product" ADD COLUMN "formbricksSignature" BOOLEAN NOT NULL DEFAULT false; diff --git a/packages/database/prisma/migrations/20230529092737_make_formbricks_signature_default/migration.sql b/packages/database/prisma/migrations/20230529092737_make_formbricks_signature_default/migration.sql new file mode 100644 index 0000000000..578b42b1e6 --- /dev/null +++ b/packages/database/prisma/migrations/20230529092737_make_formbricks_signature_default/migration.sql @@ -0,0 +1,2 @@ +-- AlterTable +ALTER TABLE "Product" ALTER COLUMN "formbricksSignature" SET DEFAULT true; diff --git a/packages/database/prisma/schema.prisma b/packages/database/prisma/schema.prisma index b446e99e8a..55a7a8117e 100644 --- a/packages/database/prisma/schema.prisma +++ b/packages/database/prisma/schema.prisma @@ -238,15 +238,16 @@ model Environment { } model Product { - id String @id @default(cuid()) - createdAt DateTime @default(now()) @map(name: "created_at") - updatedAt DateTime @updatedAt @map(name: "updated_at") - name String - team Team @relation(fields: [teamId], references: [id], onDelete: Cascade) - teamId String - environments Environment[] - brandColor String @default("#64748b") - recontactDays Int @default(7) + id String @id @default(cuid()) + createdAt DateTime @default(now()) @map(name: "created_at") + updatedAt DateTime @updatedAt @map(name: "updated_at") + name String + team Team @relation(fields: [teamId], references: [id], onDelete: Cascade) + teamId String + environments Environment[] + brandColor String @default("#64748b") + recontactDays Int @default(7) + formbricksSignature Boolean @default(true) } enum Plan { diff --git a/packages/js/src/App.tsx b/packages/js/src/App.tsx index 21b51120f9..6fad36ab3f 100644 --- a/packages/js/src/App.tsx +++ b/packages/js/src/App.tsx @@ -25,13 +25,7 @@ export default function App({ config, survey, closeSurvey, errorHandler }: AppPr return (
- +
); diff --git a/packages/js/src/components/FormbricksSignature.tsx b/packages/js/src/components/FormbricksSignature.tsx new file mode 100644 index 0000000000..a705fa723d --- /dev/null +++ b/packages/js/src/components/FormbricksSignature.tsx @@ -0,0 +1,17 @@ +import { h } from "preact"; + +export default function FormbricksSignature() { + return ( + +

+ Powered by{" "} + + Formbricks + +

+
+ ); +} diff --git a/packages/js/src/components/SurveyView.tsx b/packages/js/src/components/SurveyView.tsx index e7fe5a5337..72eaf1606c 100644 --- a/packages/js/src/components/SurveyView.tsx +++ b/packages/js/src/components/SurveyView.tsx @@ -10,16 +10,16 @@ import { cn } from "../lib/utils"; import Progress from "./Progress"; import QuestionConditional from "./QuestionConditional"; import ThankYouCard from "./ThankYouCard"; +import FormbricksSignature from "./FormbricksSignature"; interface SurveyViewProps { config: JsConfig; survey: Survey; close: () => void; - brandColor: string; errorHandler: IErrorHandler; } -export default function SurveyView({ config, survey, close, brandColor, errorHandler }: SurveyViewProps) { +export default function SurveyView({ config, survey, close, errorHandler }: SurveyViewProps) { const [activeQuestionId, setActiveQuestionId] = useState(survey.questions[0].id); const [progress, setProgress] = useState(0); // [0, 1] const [responseId, setResponseId] = useState(null); @@ -185,7 +185,7 @@ export default function SurveyView({ config, survey, close, brandColor, errorHan activeQuestionId === question.id && ( - + {config.settings?.formbricksSignature && } + ); } diff --git a/packages/js/src/components/ThankYouCard.tsx b/packages/js/src/components/ThankYouCard.tsx index 2eb693a49e..c5002e8777 100644 --- a/packages/js/src/components/ThankYouCard.tsx +++ b/packages/js/src/components/ThankYouCard.tsx @@ -33,21 +33,6 @@ export default function ThankYouCard({ headline, subheader, brandColor }: ThankY - - {/* - -
-

- Powered by{" "} - - - Formbricks - - -

-
*/} ); } diff --git a/packages/types/js.ts b/packages/types/js.ts index 9016a5aac5..0abce5e70a 100644 --- a/packages/types/js.ts +++ b/packages/types/js.ts @@ -52,6 +52,7 @@ export interface Settings { surveys?: Survey[]; noCodeEvents?: any[]; brandColor?: string; + formbricksSignature?: boolean; } export interface JsConfig {