From 43a623a61ea6bfa047120976de92e4d6f629c547 Mon Sep 17 00:00:00 2001 From: Shubham Khunt Date: Sun, 16 Jul 2023 21:44:39 +0530 Subject: [PATCH 01/51] fix: edit team page input validation added --- .../settings/members/EditTeamName.tsx | 34 ++++++++++++++++--- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/apps/web/app/(app)/environments/[environmentId]/settings/members/EditTeamName.tsx b/apps/web/app/(app)/environments/[environmentId]/settings/members/EditTeamName.tsx index 38d1fe518f..8f8504ae46 100644 --- a/apps/web/app/(app)/environments/[environmentId]/settings/members/EditTeamName.tsx +++ b/apps/web/app/(app)/environments/[environmentId]/settings/members/EditTeamName.tsx @@ -5,18 +5,27 @@ import { useTeamMutation } from "@/lib/teams/mutateTeams"; import { useTeam } from "@/lib/teams/teams"; import { Button, ErrorComponent, Input, Label } from "@formbricks/ui"; import { useEffect, useState } from "react"; -import { useForm } from "react-hook-form"; +import { useForm, useWatch } from "react-hook-form"; import toast from "react-hot-toast"; export default function EditTeamName({ environmentId }) { const { team, isLoadingTeam, isErrorTeam, mutateTeam } = useTeam(environmentId); - const { register, handleSubmit } = useForm(); + const { register, control, handleSubmit, setValue } = useForm(); const [teamId, setTeamId] = useState(""); + const teamName = useWatch({ + control, + name: "name", + }); + const isTeamNameInputEmpty = !teamName?.trim(); + const currentTeamName = teamName?.trim().toLowerCase() ?? ""; + const previousTeamName = team?.name?.trim().toLowerCase() ?? ""; + useEffect(() => { if (team && team.id !== "") { setTeamId(team.id); } + setValue("name", team?.name ?? ""); }, [team]); const { isMutatingTeam, triggerTeamMutate } = useTeamMutation(teamId); @@ -32,6 +41,12 @@ export default function EditTeamName({ environmentId }) {
{ + if (isTeamNameInputEmpty) { + return toast.error("Team name should not be empty"); + } + if (currentTeamName === previousTeamName) { + return toast.error("Please change team name to update"); + } triggerTeamMutate({ ...data }) .catch((error) => { toast.error(`Error: ${error.message}`); @@ -42,9 +57,20 @@ export default function EditTeamName({ environmentId }) { }); })}> - + -
From 8b14559d5f118fd26379da389a93c6fc368dfc35 Mon Sep 17 00:00:00 2001 From: Shubham Khunt Date: Sat, 22 Jul 2023 18:44:04 +0530 Subject: [PATCH 02/51] fix: Edit product page input validation completed --- .../settings/product/editProduct.tsx | 36 ++++++++++++++++--- 1 file changed, 31 insertions(+), 5 deletions(-) diff --git a/apps/web/app/(app)/environments/[environmentId]/settings/product/editProduct.tsx b/apps/web/app/(app)/environments/[environmentId]/settings/product/editProduct.tsx index 6ff697255f..d4adf3af5c 100644 --- a/apps/web/app/(app)/environments/[environmentId]/settings/product/editProduct.tsx +++ b/apps/web/app/(app)/environments/[environmentId]/settings/product/editProduct.tsx @@ -1,7 +1,7 @@ "use client"; -import { useState } from "react"; -import { useForm } from "react-hook-form"; +import { useEffect, useState } from "react"; +import { useForm, useWatch } from "react-hook-form"; import toast from "react-hot-toast"; import { useRouter } from "next/navigation"; @@ -22,7 +22,19 @@ export function EditProductName({ environmentId }) { const { isMutatingProduct, triggerProductMutate } = useProductMutation(environmentId); const { mutateEnvironment } = useEnvironment(environmentId); - const { register, handleSubmit } = useForm(); + const { register, handleSubmit, control, setValue } = useForm(); + + const productName = useWatch({ + control, + name: "name", + }); + const isProductNameInputEmpty = !productName?.trim(); + const currentProductName = productName?.trim().toLowerCase() ?? ""; + const previousProductName = product?.name?.trim().toLowerCase() ?? ""; + + useEffect(() => { + setValue("name", product?.name ?? ""); + }, [product?.name]); if (isLoadingProduct) { return ; @@ -35,6 +47,9 @@ export function EditProductName({ environmentId }) {
{ + if (currentProductName === previousProductName) { + return toast.error("Please change team name to update"); + } triggerProductMutate(data) .then(() => { toast.success("Product name updated successfully."); @@ -45,9 +60,20 @@ export function EditProductName({ environmentId }) { }); })}> - + -
From aca32655cd6fa241b17a19f1fa3fb35edefad8c6 Mon Sep 17 00:00:00 2001 From: Shubham Khunt Date: Sat, 22 Jul 2023 18:50:28 +0530 Subject: [PATCH 03/51] fix: edit profile page input validation added --- .../settings/profile/editProfile.tsx | 36 ++++++++++++++++--- 1 file changed, 31 insertions(+), 5 deletions(-) diff --git a/apps/web/app/(app)/environments/[environmentId]/settings/profile/editProfile.tsx b/apps/web/app/(app)/environments/[environmentId]/settings/profile/editProfile.tsx index 193d49abc6..0cc465eec2 100644 --- a/apps/web/app/(app)/environments/[environmentId]/settings/profile/editProfile.tsx +++ b/apps/web/app/(app)/environments/[environmentId]/settings/profile/editProfile.tsx @@ -11,16 +11,28 @@ import { Button, ErrorComponent, Input, Label, ProfileAvatar } from "@formbricks import { Session } from "next-auth"; import { signOut } from "next-auth/react"; import Image from "next/image"; -import { Dispatch, SetStateAction, useState } from "react"; -import { useForm } from "react-hook-form"; +import { Dispatch, SetStateAction, useEffect, useState } from "react"; +import { useForm, useWatch } from "react-hook-form"; import toast from "react-hot-toast"; export function EditName() { - const { register, handleSubmit } = useForm(); + const { register, handleSubmit, control, setValue } = useForm(); const { profile, isLoadingProfile, isErrorProfile } = useProfile(); const { triggerProfileMutate, isMutatingProfile } = useProfileMutation(); + const profileName = useWatch({ + control, + name: "name", + }); + const isProfileNameInputEmpty = !profileName?.trim(); + const currentProfileName = profileName?.trim().toLowerCase() ?? ""; + const previousProfileName = profile?.name?.trim().toLowerCase() ?? ""; + + useEffect(() => { + setValue("name", profile?.name ?? ""); + }, [profile?.name]); + if (isLoadingProfile) { return ; } @@ -32,6 +44,9 @@ export function EditName() {
{ + if (currentProfileName === previousProfileName) { + return toast.error("Please change profile name to update"); + } triggerProfileMutate(data) .then(() => { toast.success("Your name was updated successfully."); @@ -41,13 +56,24 @@ export function EditName() { }); })}> - +
-
From b1a93de8db76f35dc41710e7b878a236d30a2c80 Mon Sep 17 00:00:00 2001 From: Shubham Khunt Date: Sat, 22 Jul 2023 18:50:54 +0530 Subject: [PATCH 04/51] fix: toast error message updated --- .../[environmentId]/settings/product/editProduct.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/web/app/(app)/environments/[environmentId]/settings/product/editProduct.tsx b/apps/web/app/(app)/environments/[environmentId]/settings/product/editProduct.tsx index d4adf3af5c..44fee728e5 100644 --- a/apps/web/app/(app)/environments/[environmentId]/settings/product/editProduct.tsx +++ b/apps/web/app/(app)/environments/[environmentId]/settings/product/editProduct.tsx @@ -48,7 +48,7 @@ export function EditProductName({ environmentId }) { className="w-full max-w-sm items-center" onSubmit={handleSubmit((data) => { if (currentProductName === previousProductName) { - return toast.error("Please change team name to update"); + return toast.error("Please change product name to update"); } triggerProductMutate(data) .then(() => { From 35057322a418b2dcc4d1d70b617cd34963e89eb6 Mon Sep 17 00:00:00 2001 From: Shubham Khunt Date: Sat, 22 Jul 2023 19:23:47 +0530 Subject: [PATCH 05/51] padding issue fixed in alert dialog --- apps/web/components/shared/AlertDialog.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/web/components/shared/AlertDialog.tsx b/apps/web/components/shared/AlertDialog.tsx index ace770622a..8c463b202f 100644 --- a/apps/web/components/shared/AlertDialog.tsx +++ b/apps/web/components/shared/AlertDialog.tsx @@ -25,7 +25,7 @@ export default function AlertDialog({ return (

{text || "Are you sure? This action cannot be undone."}

-
+
From 62a08f304b931169052d3be6dfae5ce7ed2346ef Mon Sep 17 00:00:00 2001 From: Shubham Khunt Date: Sat, 22 Jul 2023 19:23:55 +0530 Subject: [PATCH 06/51] padding issue fixed in delete dialog --- apps/web/components/shared/DeleteDialog.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/web/components/shared/DeleteDialog.tsx b/apps/web/components/shared/DeleteDialog.tsx index 8fb8f4ff77..186e56f116 100644 --- a/apps/web/components/shared/DeleteDialog.tsx +++ b/apps/web/components/shared/DeleteDialog.tsx @@ -32,7 +32,7 @@ export default function DeleteDialog({

{text || "Are you sure? This action cannot be undone."}

{children}
-
+
+
+ )} + {isDeleteDisabled && ( +

+ {!isUserAdminOrOwner + ? "Only Admin or Owners can delete teams." + : "This is your only team, it cannot be deleted. Create a new team first."} +

+ )} + +
+ ); +} + +interface DeleteTeamModalProps { + open: boolean; + setOpen: Dispatch>; + teamData: { name: string; id: string; plan: string }; +} + +function DeleteTeamModal({ setOpen, open, teamData }: DeleteTeamModalProps) { + const [deleting, setDeleting] = useState(false); + const [inputValue, setInputValue] = useState(""); + + const handleInputChange = (e) => { + setInputValue(e.target.value); + }; + + const deleteTeam = async () => { + try { + setDeleting(true); + // await deleteProfile(); + // await signOut(); + // await formbricksLogout(); + } catch (error) { + toast.error("Something went wrong"); + } finally { + setDeleting(false); + setOpen(false); + } + }; + + return ( + deleteTeam()} + text="Before you proceed with deleting this team, please be aware of the following consequences:" + isDeleting={deleting} + disabled={inputValue !== teamData.name}> +
+
    +
  • + Permanent removal of all products linked to this team. This includes all surveys, + responses, user actions and attributes associated with these products. +
  • +
  • + If you are the owner of a team with other admins, the ownership of that team will be transferred + to another admin. +
  • +
  • + If you are the only member of a team or there is no other admin present, the team will be + irreversibly deleted along with all associated data. +
  • +
  • This action cannot be undone. If it's gone, it's gone.
  • +
+ + + + +
+
+ ); +} diff --git a/apps/web/app/(app)/environments/[environmentId]/settings/members/page.tsx b/apps/web/app/(app)/environments/[environmentId]/settings/members/page.tsx index 83a3524346..27fc20aab8 100644 --- a/apps/web/app/(app)/environments/[environmentId]/settings/members/page.tsx +++ b/apps/web/app/(app)/environments/[environmentId]/settings/members/page.tsx @@ -2,6 +2,7 @@ import SettingsCard from "../SettingsCard"; import SettingsTitle from "../SettingsTitle"; import { EditMemberships } from "./EditMemberships"; import EditTeamName from "./EditTeamName"; +import DeleteTeam from "./DeleteTeam"; export default function MembersSettingsPage({ params }) { return ( @@ -13,6 +14,11 @@ export default function MembersSettingsPage({ params }) { + + +
); } diff --git a/apps/web/app/(app)/environments/[environmentId]/settings/profile/editProfile.tsx b/apps/web/app/(app)/environments/[environmentId]/settings/profile/editProfile.tsx index 193d49abc6..42aeaef46d 100644 --- a/apps/web/app/(app)/environments/[environmentId]/settings/profile/editProfile.tsx +++ b/apps/web/app/(app)/environments/[environmentId]/settings/profile/editProfile.tsx @@ -76,13 +76,13 @@ export function EditAvatar({ session }) { ); } -interface DeleteAccounModaltProps { +interface DeleteAccountModalProps { open: boolean; setOpen: Dispatch>; session: Session; } -function DeleteAccountModal({ setOpen, open, session }: DeleteAccounModaltProps) { +function DeleteAccountModal({ setOpen, open, session }: DeleteAccountModalProps) { const [deleting, setDeleting] = useState(false); const [inputValue, setInputValue] = useState(""); diff --git a/apps/web/pages/api/v1/environments/[environmentId]/team/index.ts b/apps/web/pages/api/v1/environments/[environmentId]/team/index.ts index 3af4f870b7..9a126c0fc1 100644 --- a/apps/web/pages/api/v1/environments/[environmentId]/team/index.ts +++ b/apps/web/pages/api/v1/environments/[environmentId]/team/index.ts @@ -43,7 +43,7 @@ export default async function handle(req: NextApiRequest, res: NextApiResponse) }); if (team === null) { - return res.status(404).json({ message: "This product doesn't exist" }); + return res.status(404).json({ message: "This team doesn't exist" }); } return res.json(team); } From 6335565bf9cfc6928bc83065870dd2201c1cf206 Mon Sep 17 00:00:00 2001 From: Meet Patel Date: Sat, 29 Jul 2023 11:20:14 +0530 Subject: [PATCH 09/51] search works --- .../surveys/templates/TemplateContainer.tsx | 21 ++++- .../surveys/templates/TemplateList.tsx | 82 ++++++++++++------- 2 files changed, 73 insertions(+), 30 deletions(-) diff --git a/apps/web/app/(app)/environments/[environmentId]/surveys/templates/TemplateContainer.tsx b/apps/web/app/(app)/environments/[environmentId]/surveys/templates/TemplateContainer.tsx index c5ba15c1fd..95351bfe0f 100644 --- a/apps/web/app/(app)/environments/[environmentId]/surveys/templates/TemplateContainer.tsx +++ b/apps/web/app/(app)/environments/[environmentId]/surveys/templates/TemplateContainer.tsx @@ -9,6 +9,9 @@ import PreviewSurvey from "../PreviewSurvey"; import TemplateList from "./TemplateList"; import type { TProduct } from "@formbricks/types/v1/product"; import type { TEnvironment } from "@formbricks/types/v1/environment"; +import { Input } from "@formbricks/ui"; +import { Inbox, Search } from "lucide-react"; +// import { Search } from "@formbricks/ui/components/S"; type TemplateContainerWithPreviewProps = { environmentId: string; @@ -23,7 +26,7 @@ export default function TemplateContainerWithPreview({ }: TemplateContainerWithPreviewProps) { const [activeTemplate, setActiveTemplate] = useState