From d780ae1e597251b863e2dfd32e0ac4e0f5b93f49 Mon Sep 17 00:00:00 2001 From: Johannes Date: Sat, 5 Aug 2023 15:28:55 +0200 Subject: [PATCH 01/22] strapi setup working --- .../components/shared/MetaInformation.tsx | 7 +- .../index.mdx | 2 +- apps/formbricks-com/pages/learn/[slug].tsx | 42 ++++++++++++ apps/formbricks-com/pages/newblog/[slug].tsx | 66 +++++++++++++++++++ .../product-market-fit-survey/index.tsx | 49 ++++++++++++++ 5 files changed, 163 insertions(+), 3 deletions(-) create mode 100644 apps/formbricks-com/pages/learn/[slug].tsx create mode 100644 apps/formbricks-com/pages/newblog/[slug].tsx create mode 100644 apps/formbricks-com/pages/templates/product-market-fit-survey/index.tsx diff --git a/apps/formbricks-com/components/shared/MetaInformation.tsx b/apps/formbricks-com/components/shared/MetaInformation.tsx index 57ab4a8e16..39961f3c52 100644 --- a/apps/formbricks-com/components/shared/MetaInformation.tsx +++ b/apps/formbricks-com/components/shared/MetaInformation.tsx @@ -4,6 +4,7 @@ interface Props { title: string; description: string; publishedTime?: string; + updatedTime?: string; authors?: string[]; section?: string; tags?: string[]; @@ -13,6 +14,7 @@ export default function MetaInformation({ title, description, publishedTime, + updatedTime, authors, section, tags, @@ -31,9 +33,10 @@ export default function MetaInformation({ - - + + {publishedTime && } + {updatedTime && } {authors && } {section && } {tags && } diff --git a/apps/formbricks-com/pages/blog/best-open-source-survey-software-2023/index.mdx b/apps/formbricks-com/pages/blog/best-open-source-survey-software-2023/index.mdx index 79233124ae..fcb738a7c5 100644 --- a/apps/formbricks-com/pages/blog/best-open-source-survey-software-2023/index.mdx +++ b/apps/formbricks-com/pages/blog/best-open-source-survey-software-2023/index.mdx @@ -1,12 +1,12 @@ import Image from "next/image"; import LayoutMdx from "@/components/shared/LayoutMdx"; +import AuthorBox from "@/components/shared/AuthorBox"; import Formbricks from "./open-source-survey-software-free-2023-formbricks-typeform-alternative.png"; import Typebot from "./typebot-open-source-free-conversational-form-builder-survey-software-opensource.jpg"; import LimeSurvey from "./free-survey-tool-limesurvey-open-source-software-opensource.png"; import OpnForm from "./opnform-free-open-source-form-survey-tools-builder-2023-self-hostign.jpg"; import HeaderImage from "./2023-title-best-open-source-survey-software-tools-and-alternatives.png"; import SurveyJS from "./surveyjs-free-opensource-form-survey-tool-software-to-make-surveys-2023.png"; -import AuthorBox from "@/components/shared/AuthorBox"; export const meta = { title: "5 Open Source Survey and Form Tools maintained in 2023", diff --git a/apps/formbricks-com/pages/learn/[slug].tsx b/apps/formbricks-com/pages/learn/[slug].tsx new file mode 100644 index 0000000000..055a15f7b3 --- /dev/null +++ b/apps/formbricks-com/pages/learn/[slug].tsx @@ -0,0 +1,42 @@ +export async function getStaticPaths() { + const response = await fetch("http://localhost:1337/api/learn-articles?populate="); + const articles = await response.json(); + + console.log("articles.data", articles.data); + + const firstArticle = await fetch("http://localhost:1337/api/learn-articles/1?populate=*"); + const firstArticleJSON = await firstArticle.json(); + + console.log("firstArticleJSON", firstArticleJSON); + + if (!Array.isArray(articles.data)) { + console.error("Expected articles.data to be an array but got:", articles.data); + return { paths: [], fallback: true }; + } + + const paths = articles.data.map((article) => ({ + params: { slug: article.attributes.slug }, // Adjust this to match the actual path to the slug in your data + })); + + return { paths, fallback: true }; +} + +export async function getStaticProps({ params }) { + const article = await fetch(`http://localhost:1337/api/learn-articles?slug=${params.slug}`) + .then((response) => response.json()) + .then((data) => data[0]); + + return { props: { article } }; +} + +export default function ArticlePage({ article }) { + if (!article) return
Loading...
; // Render a loading state if data hasn't been fetched yet + + return ( +
+

{article.title}

+

By {article.author}

+ {/* Render the rest of the article data here */} +
+ ); +} diff --git a/apps/formbricks-com/pages/newblog/[slug].tsx b/apps/formbricks-com/pages/newblog/[slug].tsx new file mode 100644 index 0000000000..0c48004d00 --- /dev/null +++ b/apps/formbricks-com/pages/newblog/[slug].tsx @@ -0,0 +1,66 @@ +import Image from "next/image"; +import LayoutMdx from "@/components/shared/LayoutMdx"; +import AuthorBox from "@/components/shared/AuthorBox"; +import MetaInformation from "../../components/shared/MetaInformation"; + +export async function getStaticPaths() { + const response = await fetch("http://localhost:1337/api/blog-articles?populate=*"); + const articles = await response.json(); + + console.log("articles.data", JSON.stringify(articles.data, null, 2)); + console.log("articles", articles); + + const paths = articles.data.map((article) => ({ + params: { slug: article.attributes.article[0].slug }, + })); + + return { paths, fallback: true }; +} + +export async function getStaticProps({ params }) { + const res = await fetch(`http://localhost:1337/api/blog-articles?populate=*`); + if (!res.ok) { + throw new Error("Something went wrong"); + } + const resData = await res.json(); + const articles = resData.data; + // find article by slug attribute + console.log("articles", articles); + const article = articles.find((a) => a.attributes.article[0].slug === params.slug); + return { props: { article } }; +} + +export const meta = { + title: "5 Open Source Survey and Form Tools maintained in 2023", + description: + "Most open source projects get abandoned after a while. But these 5 open source survey tools are still alive and kicking in 2023.", + date: "2023-04-12", + publishedTime: "2023-04-12T12:00:00", + authors: ["Johannes"], + section: "Open Source Surveys", + tags: ["Open Source Surveys", "Formbricks", "Typeform", "SurveyJS", "Typebot", "OpnForm", "LimeSurvey"], +}; + +export default function ArticlePage({ article }) { + if (!article) return
Loading...
; // Render a loading state if data hasn't been fetched yet + + return ( +
+ +
{JSON.stringify(article, null, 2)}
+
+ ); +} diff --git a/apps/formbricks-com/pages/templates/product-market-fit-survey/index.tsx b/apps/formbricks-com/pages/templates/product-market-fit-survey/index.tsx new file mode 100644 index 0000000000..38e5ea52be --- /dev/null +++ b/apps/formbricks-com/pages/templates/product-market-fit-survey/index.tsx @@ -0,0 +1,49 @@ +import DemoPreview from "@/components/dummyUI/DemoPreview"; +import BestPracticeNavigation from "@/components/shared/BestPracticeNavigation"; +import Layout from "@/components/shared/Layout"; +import UseCaseHeader from "@/components/shared/UseCaseHeader"; +import { useEffect } from "react"; + +export default function OnboardingSegmentationPage() { + useEffect(() => { + fetch("http://localhost:1337/api/templates") + .then((response) => response.json()) + .then((data) => console.log(data)) + .catch((error) => console.error("An error occurred:", error)); + }, []); + + return ( + +
+
+ +

+ Why is it useful? +

+

+ In your Onboarding you likely want to ask two or three questions to be able to segment your users + best. These attributes can be used to create cohorts and survey users down the line. You can + identify who uses your product most and use Formbricks to gather relevant qualitative data on + scale. +

+

+ How to get started: +

+

+ Onboardings are unique to every product. Formbricks does not help you build the right onboarding. + Currently, you can use the Formbricks API to send survey data to Formbricks for later usage. Down + the line, we might offer a simple way to add survey questions to your Onboarding. +

+
+ + +
+

+ Other Best Practices +

+ +
+ ); +} From b8176ce80043b0929e3d9b94c32a31a52c7e585f Mon Sep 17 00:00:00 2001 From: Piyush Gupta Date: Sun, 23 Jul 2023 01:01:51 +0530 Subject: [PATCH 02/22] feat: added delete card and modal --- .../settings/members/DeleteTeam.tsx | 161 ++++++++++++++++++ .../[environmentId]/settings/members/page.tsx | 6 + .../settings/profile/editProfile.tsx | 4 +- .../[environmentId]/team/index.ts | 2 +- 4 files changed, 170 insertions(+), 3 deletions(-) create mode 100644 apps/web/app/(app)/environments/[environmentId]/settings/members/DeleteTeam.tsx diff --git a/apps/web/app/(app)/environments/[environmentId]/settings/members/DeleteTeam.tsx b/apps/web/app/(app)/environments/[environmentId]/settings/members/DeleteTeam.tsx new file mode 100644 index 0000000000..34a51e4ac0 --- /dev/null +++ b/apps/web/app/(app)/environments/[environmentId]/settings/members/DeleteTeam.tsx @@ -0,0 +1,161 @@ +"use client"; + +import DeleteDialog from "@/components/shared/DeleteDialog"; +import LoadingSpinner from "@/components/shared/LoadingSpinner"; +import { useEnvironment } from "@/lib/environments/environments"; +import { useMembers } from "@/lib/members"; +import { useProduct } from "@/lib/products/products"; +import { useProfile } from "@/lib/profile"; +import { truncate } from "@/lib/utils"; +import { Button, ErrorComponent, Input } from "@formbricks/ui"; +import { useTeamMutation } from "@/lib/teams/mutateTeams"; +import { useTeam } from "@/lib/teams/teams"; +import { useState, Dispatch, SetStateAction } from "react"; +import toast from "react-hot-toast"; +import { useMemberships } from "@/lib/memberships"; + +export default function DeleteTeam({ environmentId }) { + const [isDeleteDialogOpen, setIsDeleteDialogOpen] = useState(false); + + const { profile } = useProfile(); + const { memberships } = useMemberships(); + const { team } = useMembers(environmentId); + const { product, isLoadingProduct, isErrorProduct } = useProduct(environmentId); + const { environment } = useEnvironment(environmentId); + const { team: teamData } = useTeam(environmentId); + + console.log({ profile, team, product, environment, teamData, memberships }); + + const availableTeams = memberships?.length; + const role = team?.members?.filter((member) => member?.userId === profile?.id)[0]?.role; + const isUserAdminOrOwner = role === "admin" || role === "owner"; + const isDeleteDisabled = availableTeams <= 1 || !isUserAdminOrOwner; + + if (isLoadingProduct) { + return ; + } + if (isErrorProduct) { + return ; + } + + // const handleDeleteProduct = async () => { + // if (environment?.availableProducts?.length <= 1) { + // toast.error("Cannot delete product. Your team needs at least 1."); + // setIsDeleteDialogOpen(false); + // return; + // } + // const deleteProductRes = await deleteProduct(environmentId); + + // if (deleteProductRes?.id?.length > 0) { + // toast.success("Product deleted successfully."); + // // router.push("/"); + // } else if (deleteProductRes?.message?.length > 0) { + // toast.error(deleteProductRes.message); + // setIsDeleteDialogOpen(false); + // } else { + // toast.error("Error deleting product. Please try again."); + // } + // }; + + return ( +
+ {!isDeleteDisabled && ( +
+

+ Delete {truncate(teamData?.name, 30)} +  with all its products incl. all surveys, responses, people, actions and attributes.{" "} + This action cannot be undone. +

+ +
+ )} + {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 7d20959cd0..0eabc98196 100644 --- a/apps/web/app/(app)/environments/[environmentId]/settings/profile/editProfile.tsx +++ b/apps/web/app/(app)/environments/[environmentId]/settings/profile/editProfile.tsx @@ -99,13 +99,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 c22158515d288738915a39c1d9d57bdb38d66383 Mon Sep 17 00:00:00 2001 From: Piyush Gupta Date: Sat, 5 Aug 2023 09:32:23 +0530 Subject: [PATCH 03/22] feat: added delete team functionality --- .../settings/members/DeleteTeam.tsx | 107 +++++++----------- apps/web/lib/teams/teams.ts | 7 ++ .../[environmentId]/team/index.ts | 65 ++++++++++- pnpm-lock.yaml | 56 ++++----- 4 files changed, 141 insertions(+), 94 deletions(-) diff --git a/apps/web/app/(app)/environments/[environmentId]/settings/members/DeleteTeam.tsx b/apps/web/app/(app)/environments/[environmentId]/settings/members/DeleteTeam.tsx index 34a51e4ac0..4637e4df85 100644 --- a/apps/web/app/(app)/environments/[environmentId]/settings/members/DeleteTeam.tsx +++ b/apps/web/app/(app)/environments/[environmentId]/settings/members/DeleteTeam.tsx @@ -1,61 +1,56 @@ "use client"; +import toast from "react-hot-toast"; import DeleteDialog from "@/components/shared/DeleteDialog"; import LoadingSpinner from "@/components/shared/LoadingSpinner"; -import { useEnvironment } from "@/lib/environments/environments"; +import { useState, Dispatch, SetStateAction } from "react"; +import { useRouter } from "next/navigation"; import { useMembers } from "@/lib/members"; -import { useProduct } from "@/lib/products/products"; import { useProfile } from "@/lib/profile"; import { truncate } from "@/lib/utils"; import { Button, ErrorComponent, Input } from "@formbricks/ui"; -import { useTeamMutation } from "@/lib/teams/mutateTeams"; -import { useTeam } from "@/lib/teams/teams"; -import { useState, Dispatch, SetStateAction } from "react"; -import toast from "react-hot-toast"; +import { useTeam, deleteTeam } from "@/lib/teams/teams"; import { useMemberships } from "@/lib/memberships"; export default function DeleteTeam({ environmentId }) { const [isDeleteDialogOpen, setIsDeleteDialogOpen] = useState(false); + const router = useRouter(); const { profile } = useProfile(); const { memberships } = useMemberships(); - const { team } = useMembers(environmentId); - const { product, isLoadingProduct, isErrorProduct } = useProduct(environmentId); - const { environment } = useEnvironment(environmentId); - const { team: teamData } = useTeam(environmentId); - - console.log({ profile, team, product, environment, teamData, memberships }); + const { team, isErrorTeam: isErrorTeamMembers } = useMembers(environmentId); + const { team: teamData, isLoadingTeam, isErrorTeam } = useTeam(environmentId); const availableTeams = memberships?.length; const role = team?.members?.filter((member) => member?.userId === profile?.id)[0]?.role; - const isUserAdminOrOwner = role === "admin" || role === "owner"; - const isDeleteDisabled = availableTeams <= 1 || !isUserAdminOrOwner; + const isUserOwner = role === "owner"; + const isDeleteDisabled = availableTeams <= 1 || !isUserOwner; - if (isLoadingProduct) { + if (isLoadingTeam) { return ; } - if (isErrorProduct) { + if (isErrorTeam) { return ; } - // const handleDeleteProduct = async () => { - // if (environment?.availableProducts?.length <= 1) { - // toast.error("Cannot delete product. Your team needs at least 1."); - // setIsDeleteDialogOpen(false); - // return; - // } - // const deleteProductRes = await deleteProduct(environmentId); + const handleDeleteTeam = async () => { + if (memberships?.length <= 1) { + toast.error("Cannot delete team. You need at least 1."); + setIsDeleteDialogOpen(false); + return; + } + const deleteTeamRes = await deleteTeam(environmentId); - // if (deleteProductRes?.id?.length > 0) { - // toast.success("Product deleted successfully."); - // // router.push("/"); - // } else if (deleteProductRes?.message?.length > 0) { - // toast.error(deleteProductRes.message); - // setIsDeleteDialogOpen(false); - // } else { - // toast.error("Error deleting product. Please try again."); - // } - // }; + if (deleteTeamRes?.deletedTeam?.id?.length > 0) { + toast.success("Team deleted successfully."); + router.push("/"); + } else if (deleteTeamRes?.message?.length > 0) { + toast.error(deleteTeamRes.message); + setIsDeleteDialogOpen(false); + } else { + toast.error("Error deleting team. Please try again."); + } + }; return (
@@ -77,12 +72,17 @@ export default function DeleteTeam({ environmentId }) { )} {isDeleteDisabled && (

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

)} - +
); } @@ -91,64 +91,41 @@ interface DeleteTeamModalProps { open: boolean; setOpen: Dispatch>; teamData: { name: string; id: string; plan: string }; + deleteTeam: () => void; } -function DeleteTeamModal({ setOpen, open, teamData }: DeleteTeamModalProps) { - const [deleting, setDeleting] = useState(false); +function DeleteTeamModal({ setOpen, open, teamData, deleteTeam }: DeleteTeamModalProps) { 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()} + onDelete={deleteTeam} text="Before you proceed with deleting this team, please be aware of the following consequences:" - isDeleting={deleting} - disabled={inputValue !== teamData.name}> + 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.
{ mutateTeam: mutate, }; }; + +export const deleteTeam = async (environmentId: string) => { + const response = await fetch(`/api/v1/environments/${environmentId}/team/`, { + method: "DELETE", + }); + return response.json(); +}; 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 9a126c0fc1..27e63f69db 100644 --- a/apps/web/pages/api/v1/environments/[environmentId]/team/index.ts +++ b/apps/web/pages/api/v1/environments/[environmentId]/team/index.ts @@ -1,8 +1,12 @@ -import { hasEnvironmentAccess } from "@/lib/api/apiHelper"; +import { getSessionUser, hasEnvironmentAccess } from "@/lib/api/apiHelper"; import { prisma } from "@formbricks/database"; import type { NextApiRequest, NextApiResponse } from "next"; export default async function handle(req: NextApiRequest, res: NextApiResponse) { + const currentUser: any = await getSessionUser(req, res); + if (!currentUser) { + return res.status(401).json({ message: "Not authenticated" }); + } const environmentId = req.query?.environmentId?.toString(); if (!environmentId) { @@ -47,6 +51,65 @@ export default async function handle(req: NextApiRequest, res: NextApiResponse) } return res.json(team); } + + // DELETE + else if (req.method === "DELETE") { + try { + const environment = await prisma.environment.findUnique({ + where: { + id: environmentId, + }, + select: { + product: { + select: { + teamId: true, + }, + }, + }, + }); + if (environment === null) { + return res.status(404).json({ message: "This environment doesn't exist" }); + } + const team = await prisma.team.findUnique({ + where: { + id: environment.product.teamId, + }, + select: { + id: true, + name: true, + stripeCustomerId: true, + plan: true, + }, + }); + + if (team === null) { + return res.status(404).json({ message: "This team doesn't exist" }); + } + + const membership = await prisma.membership.findUnique({ + where: { + userId_teamId: { + userId: currentUser.id, + teamId: team.id, + }, + }, + }); + + if (membership?.role !== "owner") { + return res.status(403).json({ message: "You are not allowed to delete this team" }); + } + + const prismaRes = await prisma.team.delete({ + where: { + id: team.id, + }, + }); + + return res.status(200).json({ deletedTeam: prismaRes }); + } catch (error) { + return res.status(500).json({ message: error.message }); + } + } // Unknown HTTP Method else { throw new Error(`The HTTP ${req.method} method is not supported by this route.`); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 3b99627b33..ea906fcbe7 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1,4 +1,4 @@ -lockfileVersion: '6.0' +lockfileVersion: '6.1' settings: autoInstallPeers: true @@ -19,7 +19,7 @@ importers: version: 3.12.7 turbo: specifier: latest - version: 1.10.7 + version: 1.10.3 apps/demo: dependencies: @@ -352,7 +352,7 @@ importers: version: 8.10.0(eslint@8.46.0) eslint-config-turbo: specifier: latest - version: 1.8.8(eslint@8.46.0) + version: 1.10.3(eslint@8.46.0) eslint-plugin-react: specifier: 7.33.1 version: 7.33.1(eslint@8.46.0) @@ -9837,13 +9837,13 @@ packages: eslint: 8.46.0 dev: true - /eslint-config-turbo@1.8.8(eslint@8.46.0): - resolution: {integrity: sha512-+yT22sHOT5iC1sbBXfLIdXfbZuiv9bAyOXsxTxFCWelTeFFnANqmuKB3x274CFvf7WRuZ/vYP/VMjzU9xnFnxA==} + /eslint-config-turbo@1.10.3(eslint@8.46.0): + resolution: {integrity: sha512-ggzPfTJfMsMS383oZ4zfTP1zQvyMyiigOQJRUnLt1nqII6SKkTzdKZdwmXRDHU24KFwUfEFtT6c8vnm2VhL0uQ==} peerDependencies: eslint: '>6.6.0' dependencies: eslint: 8.46.0 - eslint-plugin-turbo: 1.8.8(eslint@8.46.0) + eslint-plugin-turbo: 1.10.3(eslint@8.46.0) dev: true /eslint-import-resolver-node@0.3.6: @@ -10031,8 +10031,8 @@ packages: semver: 6.3.1 string.prototype.matchall: 4.0.8 - /eslint-plugin-turbo@1.8.8(eslint@8.46.0): - resolution: {integrity: sha512-zqyTIvveOY4YU5jviDWw9GXHd4RiKmfEgwsjBrV/a965w0PpDwJgEUoSMB/C/dU310Sv9mF3DSdEjxjJLaw6rA==} + /eslint-plugin-turbo@1.10.3(eslint@8.46.0): + resolution: {integrity: sha512-g3Mnnk7el1FqxHfqbE/MayLvCsYjA/vKmAnUj66kV4AlM7p/EZqdt42NMcMSKtDVEm0w+utQkkzWG2Xsa0Pd/g==} peerDependencies: eslint: '>6.6.0' dependencies: @@ -19810,65 +19810,65 @@ packages: dependencies: safe-buffer: 5.2.1 - /turbo-darwin-64@1.10.7: - resolution: {integrity: sha512-N2MNuhwrl6g7vGuz4y3fFG2aR1oCs0UZ5HKl8KSTn/VC2y2YIuLGedQ3OVbo0TfEvygAlF3QGAAKKtOCmGPNKA==} + /turbo-darwin-64@1.10.3: + resolution: {integrity: sha512-IIB9IomJGyD3EdpSscm7Ip1xVWtYb7D0x7oH3vad3gjFcjHJzDz9xZ/iw/qItFEW+wGFcLSRPd+1BNnuLM8AsA==} cpu: [x64] os: [darwin] requiresBuild: true dev: true optional: true - /turbo-darwin-arm64@1.10.7: - resolution: {integrity: sha512-WbJkvjU+6qkngp7K4EsswOriO3xrNQag7YEGRtfLoDdMTk4O4QTeU6sfg2dKfDsBpTidTvEDwgIYJhYVGzrz9Q==} + /turbo-darwin-arm64@1.10.3: + resolution: {integrity: sha512-SBNmOZU9YEB0eyNIxeeQ+Wi0Ufd+nprEVp41rgUSRXEIpXjsDjyBnKnF+sQQj3+FLb4yyi/yZQckB+55qXWEsw==} cpu: [arm64] os: [darwin] requiresBuild: true dev: true optional: true - /turbo-linux-64@1.10.7: - resolution: {integrity: sha512-x1CF2CDP1pDz/J8/B2T0hnmmOQI2+y11JGIzNP0KtwxDM7rmeg3DDTtDM/9PwGqfPotN9iVGgMiMvBuMFbsLhg==} + /turbo-linux-64@1.10.3: + resolution: {integrity: sha512-kvAisGKE7xHJdyMxZLvg53zvHxjqPK1UVj4757PQqtx9dnjYHSc8epmivE6niPgDHon5YqImzArCjVZJYpIGHQ==} cpu: [x64] os: [linux] requiresBuild: true dev: true optional: true - /turbo-linux-arm64@1.10.7: - resolution: {integrity: sha512-JtnBmaBSYbs7peJPkXzXxsRGSGBmBEIb6/kC8RRmyvPAMyqF8wIex0pttsI+9plghREiGPtRWv/lfQEPRlXnNQ==} + /turbo-linux-arm64@1.10.3: + resolution: {integrity: sha512-Qgaqln0IYRgyL0SowJOi+PNxejv1I2xhzXOI+D+z4YHbgSx87ox1IsALYBlK8VRVYY8VCXl+PN12r1ioV09j7A==} cpu: [arm64] os: [linux] requiresBuild: true dev: true optional: true - /turbo-windows-64@1.10.7: - resolution: {integrity: sha512-7A/4CByoHdolWS8dg3DPm99owfu1aY/W0V0+KxFd0o2JQMTQtoBgIMSvZesXaWM57z3OLsietFivDLQPuzE75w==} + /turbo-windows-64@1.10.3: + resolution: {integrity: sha512-rbH9wManURNN8mBnN/ZdkpUuTvyVVEMiUwFUX4GVE5qmV15iHtZfDLUSGGCP2UFBazHcpNHG1OJzgc55GFFrUw==} cpu: [x64] os: [win32] requiresBuild: true dev: true optional: true - /turbo-windows-arm64@1.10.7: - resolution: {integrity: sha512-D36K/3b6+hqm9IBAymnuVgyePktwQ+F0lSXr2B9JfAdFPBktSqGmp50JNC7pahxhnuCLj0Vdpe9RqfnJw5zATA==} + /turbo-windows-arm64@1.10.3: + resolution: {integrity: sha512-ThlkqxhcGZX39CaTjsHqJnqVe+WImjX13pmjnpChz6q5HHbeRxaJSFzgrHIOt0sUUVx90W/WrNRyoIt/aafniw==} cpu: [arm64] os: [win32] requiresBuild: true dev: true optional: true - /turbo@1.10.7: - resolution: {integrity: sha512-xm0MPM28TWx1e6TNC3wokfE5eaDqlfi0G24kmeHupDUZt5Wd0OzHFENEHMPqEaNKJ0I+AMObL6nbSZonZBV2HA==} + /turbo@1.10.3: + resolution: {integrity: sha512-U4gKCWcKgLcCjQd4Pl8KJdfEKumpyWbzRu75A6FCj6Ctea1PIm58W6Ltw1QXKqHrl2pF9e1raAskf/h6dlrPCA==} hasBin: true requiresBuild: true optionalDependencies: - turbo-darwin-64: 1.10.7 - turbo-darwin-arm64: 1.10.7 - turbo-linux-64: 1.10.7 - turbo-linux-arm64: 1.10.7 - turbo-windows-64: 1.10.7 - turbo-windows-arm64: 1.10.7 + turbo-darwin-64: 1.10.3 + turbo-darwin-arm64: 1.10.3 + turbo-linux-64: 1.10.3 + turbo-linux-arm64: 1.10.3 + turbo-windows-64: 1.10.3 + turbo-windows-arm64: 1.10.3 dev: true /tween-functions@1.2.0: From 7e2773044746c78862f46b603b5af2d0c174139d Mon Sep 17 00:00:00 2001 From: Piyush Gupta Date: Sat, 5 Aug 2023 17:49:06 +0530 Subject: [PATCH 04/22] feat: added leave team --- .../settings/members/EditMemberships.tsx | 41 +++++++++++++++++++ apps/web/components/shared/DeleteDialog.tsx | 10 +++-- 2 files changed, 48 insertions(+), 3 deletions(-) diff --git a/apps/web/app/(app)/environments/[environmentId]/settings/members/EditMemberships.tsx b/apps/web/app/(app)/environments/[environmentId]/settings/members/EditMemberships.tsx index 562a9426c1..e2f825dd95 100644 --- a/apps/web/app/(app)/environments/[environmentId]/settings/members/EditMemberships.tsx +++ b/apps/web/app/(app)/environments/[environmentId]/settings/members/EditMemberships.tsx @@ -36,6 +36,8 @@ import { PaperAirplaneIcon, ShareIcon, TrashIcon } from "@heroicons/react/24/out import { useState } from "react"; import toast from "react-hot-toast"; import AddMemberModal from "./AddMemberModal"; +import { useRouter } from "next/navigation"; +import { useMemberships } from "@/lib/memberships"; type EditMembershipsProps = { environmentId: string; @@ -128,14 +130,21 @@ export function EditMemberships({ environmentId }: EditMembershipsProps) { const [isDeleteMemberModalOpen, setDeleteMemberModalOpen] = useState(false); const [isCreateTeamModalOpen, setCreateTeamModalOpen] = useState(false); const [showShareInviteModal, setShowShareInviteModal] = useState(false); + const [isLeaveTeamModalOpen, setLeaveTeamModalOpen] = useState(false); const [shareInviteToken, setShareInviteToken] = useState(""); const [activeMember, setActiveMember] = useState({} as any); const { profile } = useProfile(); + const { memberships } = useMemberships(); + + const router = useRouter(); const role = team?.members?.filter((member) => member?.userId === profile?.id)[0]?.role; const isAdminOrOwner = role === "admin" || role === "owner"; + const availableTeams = memberships?.length; + const isLeaveTeamDisabled = availableTeams <= 1; + const handleOpenDeleteMemberModal = (e, member) => { e.preventDefault(); setActiveMember(member); @@ -194,9 +203,26 @@ export function EditMemberships({ environmentId }: EditMembershipsProps) { return now > expiresAt; }; + const handleLeaveTeam = async () => { + const result = await removeMember(team.teamId, profile?.id); + if (!result) { + toast.error("Something went wrong"); + } else { + toast.success("You left the team successfully"); + router.push("/"); + } + }; + + console.log(profile, memberships); + return ( <>
+ {role !== "owner" && ( + + )}
From 0039647718841a16db83be325712ba6c654a529b Mon Sep 17 00:00:00 2001 From: Piyush Gupta Date: Sun, 6 Aug 2023 14:58:52 +0530 Subject: [PATCH 05/22] feat: added transfer ownership --- .../settings/members/DeleteTeam.tsx | 2 +- .../settings/members/EditMemberships.tsx | 116 ++++++++++++------ .../members/TransferOwnershipModal.tsx | 58 +++++++++ apps/web/components/shared/CustomDialog.tsx | 54 ++++++++ apps/web/components/shared/DeleteDialog.tsx | 10 +- apps/web/lib/api/apiHelper.ts | 15 +++ apps/web/lib/members.ts | 14 +++ .../[teamId]/transfer-ownership/index.ts | 83 +++++++++++++ 8 files changed, 309 insertions(+), 43 deletions(-) create mode 100644 apps/web/app/(app)/environments/[environmentId]/settings/members/TransferOwnershipModal.tsx create mode 100644 apps/web/components/shared/CustomDialog.tsx create mode 100644 apps/web/pages/api/v1/teams/[teamId]/transfer-ownership/index.ts diff --git a/apps/web/app/(app)/environments/[environmentId]/settings/members/DeleteTeam.tsx b/apps/web/app/(app)/environments/[environmentId]/settings/members/DeleteTeam.tsx index 4637e4df85..d4168ad66b 100644 --- a/apps/web/app/(app)/environments/[environmentId]/settings/members/DeleteTeam.tsx +++ b/apps/web/app/(app)/environments/[environmentId]/settings/members/DeleteTeam.tsx @@ -18,7 +18,7 @@ export default function DeleteTeam({ environmentId }) { const router = useRouter(); const { profile } = useProfile(); const { memberships } = useMemberships(); - const { team, isErrorTeam: isErrorTeamMembers } = useMembers(environmentId); + const { team } = useMembers(environmentId); const { team: teamData, isLoadingTeam, isErrorTeam } = useTeam(environmentId); const availableTeams = memberships?.length; diff --git a/apps/web/app/(app)/environments/[environmentId]/settings/members/EditMemberships.tsx b/apps/web/app/(app)/environments/[environmentId]/settings/members/EditMemberships.tsx index e2f825dd95..52ba615704 100644 --- a/apps/web/app/(app)/environments/[environmentId]/settings/members/EditMemberships.tsx +++ b/apps/web/app/(app)/environments/[environmentId]/settings/members/EditMemberships.tsx @@ -1,6 +1,7 @@ "use client"; import ShareInviteModal from "@/app/(app)/environments/[environmentId]/settings/members/ShareInviteModal"; +import TransferOwnershipModal from "@/app/(app)/environments/[environmentId]/settings/members/TransferOwnershipModal"; import DeleteDialog from "@/components/shared/DeleteDialog"; import LoadingSpinner from "@/components/shared/LoadingSpinner"; import CreateTeamModal from "@/components/team/CreateTeamModal"; @@ -11,6 +12,7 @@ import { removeMember, resendInvite, shareInvite, + transferOwnership, updateInviteeRole, updateMemberRole, useMembers, @@ -38,6 +40,7 @@ import toast from "react-hot-toast"; import AddMemberModal from "./AddMemberModal"; import { useRouter } from "next/navigation"; import { useMemberships } from "@/lib/memberships"; +import CustomDialog from "@/components/shared/CustomDialog"; type EditMembershipsProps = { environmentId: string; @@ -48,13 +51,16 @@ interface Role { memberRole: MembershipRole; teamId: string; memberId: string; + memberName: string; environmentId: string; userId: string; memberAccepted: boolean; inviteId: string; + currentUserRole: string; } enum MembershipRole { + Owner = "owner", Admin = "admin", Editor = "editor", Developer = "developer", @@ -66,13 +72,16 @@ function RoleElement({ memberRole, teamId, memberId, + memberName, environmentId, userId, memberAccepted, inviteId, + currentUserRole, }: Role) { const { mutateTeam } = useMembers(environmentId); const [loading, setLoading] = useState(false); + const [isTransferOwnershipModalOpen, setTransferOwnershipModalOpen] = useState(false); const disableRole = memberRole && memberId && userId ? memberRole === ("owner" as MembershipRole) || memberId === userId @@ -89,34 +98,70 @@ function RoleElement({ mutateTeam(); }; + const handleOwnershipTransfer = async () => { + setLoading(true); + const isTransfered = await transferOwnership(teamId, memberId); + if (isTransfered) { + toast.success("Ownership transferred successfully"); + } else { + toast.error("Something went wrong"); + } + setTransferOwnershipModalOpen(false); + setLoading(false); + mutateTeam(); + }; + + const handleRoleChange = (role: string) => { + if (role === "owner") { + setTransferOwnershipModalOpen(true); + } else { + handleMemberRoleUpdate(role); + } + }; + + const getMembershipRoles = () => { + if (currentUserRole === "owner" && memberAccepted) { + return Object.keys(MembershipRole); + } + return Object.keys(MembershipRole).filter((role) => role !== "Owner"); + }; + if (isAdminOrOwner) { return ( - - - - - {!disableRole && ( - - handleMemberRoleUpdate(value.toLowerCase())}> - {Object.keys(MembershipRole).map((role) => ( - - {capitalizeFirstLetter(role)} - - ))} - - - )} - + <> + + + + + {!disableRole && ( + + handleRoleChange(value.toLowerCase())}> + {getMembershipRoles().map((role) => ( + + {capitalizeFirstLetter(role)} + + ))} + + + )} + + + ); } @@ -213,8 +258,6 @@ export function EditMemberships({ environmentId }: EditMembershipsProps) { } }; - console.log(profile, memberships); - return ( <>
@@ -268,11 +311,13 @@ export function EditMemberships({ environmentId }: EditMembershipsProps) { isAdminOrOwner={isAdminOrOwner} memberRole={member.role} memberId={member.userId} + memberName={member.name} teamId={team.teamId} environmentId={environmentId} userId={profile?.id} memberAccepted={member.accepted} inviteId={member?.inviteId} + currentUserRole={role} />
@@ -336,21 +381,22 @@ export function EditMemberships({ environmentId }: EditMembershipsProps) { deleteWhat={activeMember.name + " from your team"} onDelete={handleDeleteMember} /> - {isLeaveTeamDisabled && (

You cannot leave this team as it is your only team. Create a new team first.

)} -
+ + {showShareInviteModal && ( >; + memberName: string; + onSubmit: () => void; +} + +export default function TransferOwnershipModal({ + setOpen, + open, + memberName, + onSubmit, +}: TransferOwnershipModalProps) { + const [inputValue, setInputValue] = useState(""); + + const handleInputChange = (e) => { + setInputValue(e.target.value); + }; + + return ( + +
+
    +
  • + There can only be one owner of each team. If you transfer your ownership to {memberName}, + you will lose all of your ownership rights. +
  • +
  • When you transfer the ownership, you will remain an Admin of the team.
  • +
+ + + + +
+
+ ); +} diff --git a/apps/web/components/shared/CustomDialog.tsx b/apps/web/components/shared/CustomDialog.tsx new file mode 100644 index 0000000000..0bec931d45 --- /dev/null +++ b/apps/web/components/shared/CustomDialog.tsx @@ -0,0 +1,54 @@ +"use client"; + +import Modal from "@/components/shared/Modal"; +import { Button } from "@formbricks/ui"; + +interface CustomDialogProps { + open: boolean; + setOpen: (open: boolean) => void; + title?: string; + text?: string; + isLoading?: boolean; + children?: React.ReactNode; + onOk: () => void; + okBtnText?: string; + onCancel?: () => void; + cancelBtnText?: string; + disabled?: boolean; +} + +export default function CustomDialog({ + open, + setOpen, + title, + text, + isLoading, + children, + onOk, + okBtnText, + onCancel, + cancelBtnText, + disabled, +}: CustomDialogProps) { + return ( + +

{text}

+
{children}
+
+ + +
+
+ ); +} diff --git a/apps/web/components/shared/DeleteDialog.tsx b/apps/web/components/shared/DeleteDialog.tsx index e1eea671dd..186e56f116 100644 --- a/apps/web/components/shared/DeleteDialog.tsx +++ b/apps/web/components/shared/DeleteDialog.tsx @@ -6,22 +6,19 @@ import { Button } from "@formbricks/ui"; interface DeleteDialogProps { open: boolean; setOpen: (open: boolean) => void; - customTitle?: string; - deleteWhat?: string; + deleteWhat: string; onDelete: () => void; text?: string; isDeleting?: boolean; useSaveInsteadOfCancel?: boolean; onSave?: () => void; children?: React.ReactNode; - deleteBtnText?: string; disabled?: boolean; } export default function DeleteDialog({ open, setOpen, - customTitle, deleteWhat, onDelete, text, @@ -29,11 +26,10 @@ export default function DeleteDialog({ useSaveInsteadOfCancel = false, onSave, children, - deleteBtnText, disabled, }: DeleteDialogProps) { return ( - +

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

{children}
@@ -48,7 +44,7 @@ export default function DeleteDialog({ {useSaveInsteadOfCancel ? "Save" : "Cancel"}
diff --git a/apps/web/lib/api/apiHelper.ts b/apps/web/lib/api/apiHelper.ts index 1e4e22f52c..010ebe48a8 100644 --- a/apps/web/lib/api/apiHelper.ts +++ b/apps/web/lib/api/apiHelper.ts @@ -131,6 +131,21 @@ export const getSessionUser = async (req?: NextApiRequest, res?: NextApiResponse if (session && "user" in session) return session.user; }; +export const isOwner = async (user, teamId) => { + const membership = await prisma.membership.findUnique({ + where: { + userId_teamId: { + userId: user.id, + teamId: teamId, + }, + }, + }); + if (membership && membership.role === "owner") { + return true; + } + return false; +}; + export const isAdminOrOwner = async (user, teamId) => { const membership = await prisma.membership.findUnique({ where: { diff --git a/apps/web/lib/members.ts b/apps/web/lib/members.ts index 414dd1f901..b8d82abc70 100644 --- a/apps/web/lib/members.ts +++ b/apps/web/lib/members.ts @@ -30,6 +30,20 @@ export const updateMemberRole = async (teamId: string, userId: string, role: str } }; +export const transferOwnership = async (teamId: string, userId: string) => { + try { + const result = await fetch(`/api/v1/teams/${teamId}/transfer-ownership/`, { + method: "PATCH", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ userId }), + }); + return result.status === 200; + } catch (error) { + console.error(error); + return false; + } +}; + export const removeMember = async (teamId: string, userId: string) => { try { const result = await fetch(`/api/v1/teams/${teamId}/members/${userId}/`, { diff --git a/apps/web/pages/api/v1/teams/[teamId]/transfer-ownership/index.ts b/apps/web/pages/api/v1/teams/[teamId]/transfer-ownership/index.ts new file mode 100644 index 0000000000..32a64acb74 --- /dev/null +++ b/apps/web/pages/api/v1/teams/[teamId]/transfer-ownership/index.ts @@ -0,0 +1,83 @@ +import { getSessionUser, hasTeamAccess, isOwner } from "@/lib/api/apiHelper"; +import { prisma } from "@formbricks/database"; +import type { NextApiRequest, NextApiResponse } from "next"; + +export default async function handle(req: NextApiRequest, res: NextApiResponse) { + // Check Authentication + const currentUser: any = await getSessionUser(req, res); + if (!currentUser) { + return res.status(401).json({ message: "Not authenticated" }); + } + + const teamId = req.query.teamId?.toString(); + if (teamId === undefined) { + return res.status(400).json({ message: "Missing teamId" }); + } + + const hasAccess = await hasTeamAccess(currentUser, teamId); + if (!hasAccess) { + return res.status(403).json({ message: "Not authorized" }); + } + + /** + * Transfer ownership of a team to another member + * @route PATCH /api/v1/teams/{teamId}/transfer-ownership + * @param {string} teamId - The id of the team to transfer ownership of + * @param {string} userId - The id of the user to transfer ownership to + * @returns {object} - The updated membership of the new owner and the updated membership of the old owner + * + */ + if (req.method === "PATCH") { + const { userId: newOwnerId } = req.body; + + const hasOwnerAccess = await isOwner(currentUser, teamId); + + if (!hasOwnerAccess) { + return res.status(403).json({ message: "You must be the owner of this team to transfer ownership" }); + } + + if (newOwnerId === currentUser.id) { + return res.status(403).json({ message: "You cannot transfer ownership to yourself" }); + } + + const isMember = await prisma.membership.findFirst({ + where: { + userId: newOwnerId, + teamId, + }, + }); + if (!isMember) { + return res.status(403).json({ message: "The new owner must be a member of the team" }); + } + + const updatedOwnerMembership = await prisma.membership.update({ + where: { + userId_teamId: { + teamId, + userId: newOwnerId, + }, + }, + data: { + role: "owner", + }, + }); + + const updatedAdminMembership = await prisma.membership.update({ + where: { + userId_teamId: { + teamId, + userId: currentUser.id, + }, + }, + data: { + role: "admin", + }, + }); + + return res.json({ + message: "Ownership transferred successfully", + updatedOwnerMembership, + updatedAdminMembership, + }); + } +} From a2f6677b547c2c2b2fde3b42c09e8af80c1e0948 Mon Sep 17 00:00:00 2001 From: Piyush Gupta Date: Sun, 6 Aug 2023 15:17:08 +0530 Subject: [PATCH 06/22] fix: independent queries -> Txn --- .../[teamId]/transfer-ownership/index.ts | 57 ++++++++++--------- 1 file changed, 29 insertions(+), 28 deletions(-) diff --git a/apps/web/pages/api/v1/teams/[teamId]/transfer-ownership/index.ts b/apps/web/pages/api/v1/teams/[teamId]/transfer-ownership/index.ts index 32a64acb74..d4afcecebc 100644 --- a/apps/web/pages/api/v1/teams/[teamId]/transfer-ownership/index.ts +++ b/apps/web/pages/api/v1/teams/[teamId]/transfer-ownership/index.ts @@ -50,34 +50,35 @@ export default async function handle(req: NextApiRequest, res: NextApiResponse) return res.status(403).json({ message: "The new owner must be a member of the team" }); } - const updatedOwnerMembership = await prisma.membership.update({ - where: { - userId_teamId: { - teamId, - userId: newOwnerId, - }, - }, - data: { - role: "owner", - }, - }); + try { + await prisma.$transaction([ + prisma.membership.update({ + where: { + userId_teamId: { + teamId, + userId: currentUser.id, + }, + }, + data: { + role: "admin", + }, + }), + prisma.membership.update({ + where: { + userId_teamId: { + teamId, + userId: newOwnerId, + }, + }, + data: { + role: "owner", + }, + }), + ]); + } catch (error) { + return res.status(500).json({ message: "Something went wrong" }); + } - const updatedAdminMembership = await prisma.membership.update({ - where: { - userId_teamId: { - teamId, - userId: currentUser.id, - }, - }, - data: { - role: "admin", - }, - }); - - return res.json({ - message: "Ownership transferred successfully", - updatedOwnerMembership, - updatedAdminMembership, - }); + return res.json({ message: "Ownership transferred successfully" }); } } From 4a09253234887ef824fb65db82b9a9b1607b2c93 Mon Sep 17 00:00:00 2001 From: Piyush Gupta Date: Sun, 6 Aug 2023 15:30:54 +0530 Subject: [PATCH 07/22] refactor: used isOwner in delete team --- .../environments/[environmentId]/team/index.ts | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) 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 27e63f69db..c0598a85b5 100644 --- a/apps/web/pages/api/v1/environments/[environmentId]/team/index.ts +++ b/apps/web/pages/api/v1/environments/[environmentId]/team/index.ts @@ -1,4 +1,4 @@ -import { getSessionUser, hasEnvironmentAccess } from "@/lib/api/apiHelper"; +import { getSessionUser, hasEnvironmentAccess, hasTeamAccess, isOwner } from "@/lib/api/apiHelper"; import { prisma } from "@formbricks/database"; import type { NextApiRequest, NextApiResponse } from "next"; @@ -70,6 +70,7 @@ export default async function handle(req: NextApiRequest, res: NextApiResponse) if (environment === null) { return res.status(404).json({ message: "This environment doesn't exist" }); } + const team = await prisma.team.findUnique({ where: { id: environment.product.teamId, @@ -81,21 +82,12 @@ export default async function handle(req: NextApiRequest, res: NextApiResponse) plan: true, }, }); - if (team === null) { return res.status(404).json({ message: "This team doesn't exist" }); } - const membership = await prisma.membership.findUnique({ - where: { - userId_teamId: { - userId: currentUser.id, - teamId: team.id, - }, - }, - }); - - if (membership?.role !== "owner") { + const hasOwnership = isOwner(currentUser, team.id); + if (!hasOwnership) { return res.status(403).json({ message: "You are not allowed to delete this team" }); } From a2c07d3be7a2137aa3a3742e9f6ffc8c3b43f0bc Mon Sep 17 00:00:00 2001 From: Piyush Gupta Date: Sun, 6 Aug 2023 15:46:11 +0530 Subject: [PATCH 08/22] added loading in transfer ownership CTA --- .../[environmentId]/settings/members/EditMemberships.tsx | 1 + .../settings/members/TransferOwnershipModal.tsx | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/apps/web/app/(app)/environments/[environmentId]/settings/members/EditMemberships.tsx b/apps/web/app/(app)/environments/[environmentId]/settings/members/EditMemberships.tsx index 52ba615704..b907c04efd 100644 --- a/apps/web/app/(app)/environments/[environmentId]/settings/members/EditMemberships.tsx +++ b/apps/web/app/(app)/environments/[environmentId]/settings/members/EditMemberships.tsx @@ -160,6 +160,7 @@ function RoleElement({ setOpen={setTransferOwnershipModalOpen} memberName={memberName} onSubmit={handleOwnershipTransfer} + isLoading={loading} /> ); diff --git a/apps/web/app/(app)/environments/[environmentId]/settings/members/TransferOwnershipModal.tsx b/apps/web/app/(app)/environments/[environmentId]/settings/members/TransferOwnershipModal.tsx index 3f1a645669..fdd297e57e 100644 --- a/apps/web/app/(app)/environments/[environmentId]/settings/members/TransferOwnershipModal.tsx +++ b/apps/web/app/(app)/environments/[environmentId]/settings/members/TransferOwnershipModal.tsx @@ -7,6 +7,7 @@ interface TransferOwnershipModalProps { setOpen: Dispatch>; memberName: string; onSubmit: () => void; + isLoading?: boolean; } export default function TransferOwnershipModal({ @@ -14,6 +15,7 @@ export default function TransferOwnershipModal({ open, memberName, onSubmit, + isLoading, }: TransferOwnershipModalProps) { const [inputValue, setInputValue] = useState(""); @@ -29,7 +31,8 @@ export default function TransferOwnershipModal({ okBtnText="Transfer ownership" title="There can only be ONE owner! Are you sure?" cancelBtnText="CANCEL" - disabled={inputValue !== memberName}> + disabled={inputValue !== memberName} + isLoading={isLoading}>
  • From 81ee4ade1e9d5c909f88bf8aad96166a3d41acc9 Mon Sep 17 00:00:00 2001 From: Piyush Gupta Date: Tue, 8 Aug 2023 10:16:48 +0530 Subject: [PATCH 09/22] fix: added loading states in CTA --- .../settings/members/DeleteTeam.tsx | 20 +++++++++---------- .../settings/members/EditMemberships.tsx | 7 ++++++- .../[environmentId]/settings/members/page.tsx | 2 +- 3 files changed, 16 insertions(+), 13 deletions(-) diff --git a/apps/web/app/(app)/environments/[environmentId]/settings/members/DeleteTeam.tsx b/apps/web/app/(app)/environments/[environmentId]/settings/members/DeleteTeam.tsx index d4168ad66b..06b6865a78 100644 --- a/apps/web/app/(app)/environments/[environmentId]/settings/members/DeleteTeam.tsx +++ b/apps/web/app/(app)/environments/[environmentId]/settings/members/DeleteTeam.tsx @@ -7,13 +7,13 @@ import { useState, Dispatch, SetStateAction } from "react"; import { useRouter } from "next/navigation"; import { useMembers } from "@/lib/members"; import { useProfile } from "@/lib/profile"; -import { truncate } from "@/lib/utils"; import { Button, ErrorComponent, Input } from "@formbricks/ui"; import { useTeam, deleteTeam } from "@/lib/teams/teams"; import { useMemberships } from "@/lib/memberships"; export default function DeleteTeam({ environmentId }) { const [isDeleteDialogOpen, setIsDeleteDialogOpen] = useState(false); + const [isDeleting, setIsDeleting] = useState(false); const router = useRouter(); const { profile } = useProfile(); @@ -34,19 +34,16 @@ export default function DeleteTeam({ environmentId }) { } const handleDeleteTeam = async () => { - if (memberships?.length <= 1) { - toast.error("Cannot delete team. You need at least 1."); - setIsDeleteDialogOpen(false); - return; - } + setIsDeleting(true); const deleteTeamRes = await deleteTeam(environmentId); + setIsDeleteDialogOpen(false); + setIsDeleting(false); if (deleteTeamRes?.deletedTeam?.id?.length > 0) { toast.success("Team deleted successfully."); router.push("/"); } else if (deleteTeamRes?.message?.length > 0) { toast.error(deleteTeamRes.message); - setIsDeleteDialogOpen(false); } else { toast.error("Error deleting team. Please try again."); } @@ -57,8 +54,6 @@ export default function DeleteTeam({ environmentId }) { {!isDeleteDisabled && (

    - Delete {truncate(teamData?.name, 30)} -  with all its products incl. all surveys, responses, people, actions and attributes.{" "} This action cannot be undone.

    ); @@ -92,9 +88,10 @@ interface DeleteTeamModalProps { setOpen: Dispatch>; teamData: { name: string; id: string; plan: string }; deleteTeam: () => void; + isDeleting?: boolean; } -function DeleteTeamModal({ setOpen, open, teamData, deleteTeam }: DeleteTeamModalProps) { +function DeleteTeamModal({ setOpen, open, teamData, deleteTeam, isDeleting }: DeleteTeamModalProps) { const [inputValue, setInputValue] = useState(""); const handleInputChange = (e) => { @@ -108,7 +105,8 @@ function DeleteTeamModal({ setOpen, open, teamData, deleteTeam }: DeleteTeamModa deleteWhat="team" onDelete={deleteTeam} text="Before you proceed with deleting this team, please be aware of the following consequences:" - disabled={inputValue !== teamData?.name}> + disabled={inputValue !== teamData?.name} + isDeleting={isDeleting}>
    • diff --git a/apps/web/app/(app)/environments/[environmentId]/settings/members/EditMemberships.tsx b/apps/web/app/(app)/environments/[environmentId]/settings/members/EditMemberships.tsx index b907c04efd..20bbe9e134 100644 --- a/apps/web/app/(app)/environments/[environmentId]/settings/members/EditMemberships.tsx +++ b/apps/web/app/(app)/environments/[environmentId]/settings/members/EditMemberships.tsx @@ -172,6 +172,7 @@ function RoleElement({ export function EditMemberships({ environmentId }: EditMembershipsProps) { const { team, isErrorTeam, isLoadingTeam, mutateTeam } = useMembers(environmentId); + const [loading, setLoading] = useState(false); const [isAddMemberModalOpen, setAddMemberModalOpen] = useState(false); const [isDeleteMemberModalOpen, setDeleteMemberModalOpen] = useState(false); const [isCreateTeamModalOpen, setCreateTeamModalOpen] = useState(false); @@ -250,7 +251,10 @@ export function EditMemberships({ environmentId }: EditMembershipsProps) { }; const handleLeaveTeam = async () => { + setLoading(true); const result = await removeMember(team.teamId, profile?.id); + setLeaveTeamModalOpen(false); + setLoading(false); if (!result) { toast.error("Something went wrong"); } else { @@ -390,7 +394,8 @@ export function EditMemberships({ environmentId }: EditMembershipsProps) { text="You wil leave this team and loose access to all surveys and responses. You can only rejoin if you are invited again." onOk={handleLeaveTeam} okBtnText="Yes, leave team" - disabled={isLeaveTeamDisabled}> + disabled={isLeaveTeamDisabled} + isLoading={loading}> {isLeaveTeamDisabled && (

      You cannot leave this team as it is your only team. Create a new team first. 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 27fc20aab8..481ffb3dee 100644 --- a/apps/web/app/(app)/environments/[environmentId]/settings/members/page.tsx +++ b/apps/web/app/(app)/environments/[environmentId]/settings/members/page.tsx @@ -16,7 +16,7 @@ export default function MembersSettingsPage({ params }) { + description="Delete team with all its products including all surveys, responses, people, actions and attributes">

    From 997f85bf32aac97355cf4b29758002b0f41213c4 Mon Sep 17 00:00:00 2001 From: Johannes Date: Tue, 8 Aug 2023 10:33:26 +0200 Subject: [PATCH 10/22] update formatting --- .../[environmentId]/settings/members/DeleteTeam.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/web/app/(app)/environments/[environmentId]/settings/members/DeleteTeam.tsx b/apps/web/app/(app)/environments/[environmentId]/settings/members/DeleteTeam.tsx index 06b6865a78..31ae560a53 100644 --- a/apps/web/app/(app)/environments/[environmentId]/settings/members/DeleteTeam.tsx +++ b/apps/web/app/(app)/environments/[environmentId]/settings/members/DeleteTeam.tsx @@ -54,7 +54,7 @@ export default function DeleteTeam({ environmentId }) { {!isDeleteDisabled && (

    - This action cannot be undone. + This action cannot be undone. If it's gone, it's gone.

    -

    {product.name} /

    +

    {product.name} /

    { @@ -180,9 +180,11 @@ export default function SurveyMenuBar({ />
    {!!localSurvey?.responseRate && ( -
    - - This survey received responses. To keep the data consistent, make changes with caution. +
    + +

    + This survey received responses. To keep the data consistent, make changes with caution. +

    )}
    From c667b7d9493542c1d0775d3cd9546e86abd626c3 Mon Sep 17 00:00:00 2001 From: Johannes Date: Thu, 17 Aug 2023 16:53:58 +0200 Subject: [PATCH 19/22] remove logs --- apps/formbricks-com/pages/learn/[slug].tsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/apps/formbricks-com/pages/learn/[slug].tsx b/apps/formbricks-com/pages/learn/[slug].tsx index 8e2f594a71..6462e0b78e 100644 --- a/apps/formbricks-com/pages/learn/[slug].tsx +++ b/apps/formbricks-com/pages/learn/[slug].tsx @@ -64,8 +64,6 @@ export async function getStaticPaths() { const articles = (await response.json()) as ArticleResponse; - console.log("articles", articles); - const paths = articles.data.map((article) => ({ params: { slug: article.attributes.slug }, })); From dd43a55e2051f623f4c2483185464e1761de85be Mon Sep 17 00:00:00 2001 From: Johannes Date: Thu, 17 Aug 2023 16:57:40 +0200 Subject: [PATCH 20/22] remove unfinished template subpage --- .../product-market-fit-survey/index.tsx | 49 ------------------- 1 file changed, 49 deletions(-) delete mode 100644 apps/formbricks-com/pages/templates/product-market-fit-survey/index.tsx diff --git a/apps/formbricks-com/pages/templates/product-market-fit-survey/index.tsx b/apps/formbricks-com/pages/templates/product-market-fit-survey/index.tsx deleted file mode 100644 index 38e5ea52be..0000000000 --- a/apps/formbricks-com/pages/templates/product-market-fit-survey/index.tsx +++ /dev/null @@ -1,49 +0,0 @@ -import DemoPreview from "@/components/dummyUI/DemoPreview"; -import BestPracticeNavigation from "@/components/shared/BestPracticeNavigation"; -import Layout from "@/components/shared/Layout"; -import UseCaseHeader from "@/components/shared/UseCaseHeader"; -import { useEffect } from "react"; - -export default function OnboardingSegmentationPage() { - useEffect(() => { - fetch("http://localhost:1337/api/templates") - .then((response) => response.json()) - .then((data) => console.log(data)) - .catch((error) => console.error("An error occurred:", error)); - }, []); - - return ( - -
    -
    - -

    - Why is it useful? -

    -

    - In your Onboarding you likely want to ask two or three questions to be able to segment your users - best. These attributes can be used to create cohorts and survey users down the line. You can - identify who uses your product most and use Formbricks to gather relevant qualitative data on - scale. -

    -

    - How to get started: -

    -

    - Onboardings are unique to every product. Formbricks does not help you build the right onboarding. - Currently, you can use the Formbricks API to send survey data to Formbricks for later usage. Down - the line, we might offer a simple way to add survey questions to your Onboarding. -

    -
    - - -
    -

    - Other Best Practices -

    - -
    - ); -} From 6b79e8a8882316cd09f3de83bc51761855a53367 Mon Sep 17 00:00:00 2001 From: Johannes Date: Thu, 17 Aug 2023 17:36:14 +0200 Subject: [PATCH 21/22] fix packages --- packages/database/package.json | 3 +-- packages/errors/package.json | 3 --- packages/eslint-config-formbricks/package.json | 3 --- packages/lib/package.json | 1 - packages/tsconfig/package.json | 3 --- packages/types/package.json | 1 - packages/ui/package.json | 1 - pnpm-lock.yaml | 18 ------------------ 8 files changed, 1 insertion(+), 32 deletions(-) diff --git a/packages/database/package.json b/packages/database/package.json index 1dd59d6135..b38ddf011b 100644 --- a/packages/database/package.json +++ b/packages/database/package.json @@ -25,8 +25,7 @@ }, "dependencies": { "@prisma/client": "^5.0.0", - "dotenv-cli": "^7.2.1", - "react-markdown": "^8.0.7" + "dotenv-cli": "^7.2.1" }, "devDependencies": { "@formbricks/tsconfig": "workspace:*", diff --git a/packages/errors/package.json b/packages/errors/package.json index 2e99749f71..94663b9c4d 100644 --- a/packages/errors/package.json +++ b/packages/errors/package.json @@ -21,8 +21,5 @@ "@formbricks/tsconfig": "workspace:*", "eslint-config-formbricks": "workspace:*", "tsup": "^7.2.0" - }, - "dependencies": { - "react-markdown": "^8.0.7" } } diff --git a/packages/eslint-config-formbricks/package.json b/packages/eslint-config-formbricks/package.json index 7c7f0b96a8..5f75b78479 100644 --- a/packages/eslint-config-formbricks/package.json +++ b/packages/eslint-config-formbricks/package.json @@ -13,8 +13,5 @@ "eslint-config-prettier": "^8.10.0", "eslint-config-turbo": "latest", "eslint-plugin-react": "7.33.1" - }, - "dependencies": { - "react-markdown": "^8.0.7" } } diff --git a/packages/lib/package.json b/packages/lib/package.json index a7bba498e3..fca9c1eaaa 100644 --- a/packages/lib/package.json +++ b/packages/lib/package.json @@ -19,7 +19,6 @@ "date-fns": "^2.30.0", "markdown-it": "^13.0.1", "posthog-node": "^3.1.1", - "react-markdown": "^8.0.7", "server-only": "^0.0.1", "tailwind-merge": "^1.14.0" }, diff --git a/packages/tsconfig/package.json b/packages/tsconfig/package.json index a0d42afa1f..acb4a9520e 100644 --- a/packages/tsconfig/package.json +++ b/packages/tsconfig/package.json @@ -10,8 +10,5 @@ "@types/react": "18.2.18", "@types/react-dom": "18.2.7", "typescript": "5.1.6" - }, - "dependencies": { - "react-markdown": "^8.0.7" } } diff --git a/packages/types/package.json b/packages/types/package.json index 15001fe7b9..f34100cb1f 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -10,7 +10,6 @@ "@formbricks/tsconfig": "workspace:*" }, "dependencies": { - "react-markdown": "^8.0.7", "zod": "^3.21.4" } } diff --git a/packages/ui/package.json b/packages/ui/package.json index 954cae50d9..a08c11b058 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -48,7 +48,6 @@ "react-confetti": "^6.1.0", "react-day-picker": "^8.8.0", "react-dom": "^18.2.0", - "react-markdown": "^8.0.7", "react-radio-group": "^3.0.3", "react-use": "^17.4.0" } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 61ec3069c6..e5547876ef 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -291,9 +291,6 @@ importers: next-seo: specifier: ^6.1.0 version: 6.1.0(next@13.4.12)(react-dom@18.2.0)(react@18.2.0) - react-markdown: - specifier: ^8.0.7 - version: 8.0.7(@types/react@18.2.18)(react@18.2.0) devDependencies: '@formbricks/tsconfig': specifier: workspace:* @@ -347,9 +344,6 @@ importers: next-seo: specifier: ^6.1.0 version: 6.1.0(next@13.4.12)(react-dom@18.2.0)(react@18.2.0) - react-markdown: - specifier: ^8.0.7 - version: 8.0.7(@types/react@18.2.18)(react@18.2.0) devDependencies: '@formbricks/tsconfig': specifier: workspace:* @@ -366,9 +360,6 @@ importers: next-seo: specifier: ^6.1.0 version: 6.1.0(next@13.4.12)(react-dom@18.2.0)(react@18.2.0) - react-markdown: - specifier: ^8.0.7 - version: 8.0.7(@types/react@18.2.18)(react@18.2.0) devDependencies: eslint: specifier: ^8.46.0 @@ -533,9 +524,6 @@ importers: next-seo: specifier: ^6.1.0 version: 6.1.0(next@13.4.12)(react-dom@18.2.0)(react@18.2.0) - react-markdown: - specifier: ^8.0.7 - version: 8.0.7(@types/react@18.2.18)(react@18.2.0) devDependencies: '@types/node': specifier: 20.4.6 @@ -555,9 +543,6 @@ importers: next-seo: specifier: ^6.1.0 version: 6.1.0(next@13.4.12)(react-dom@18.2.0)(react@18.2.0) - react-markdown: - specifier: ^8.0.7 - version: 8.0.7(@types/react@18.2.18)(react@18.2.0) zod: specifier: ^3.21.4 version: 3.21.4 @@ -655,9 +640,6 @@ importers: react-dom: specifier: ^18.2.0 version: 18.2.0(react@18.2.0) - react-markdown: - specifier: ^8.0.7 - version: 8.0.7(@types/react@18.2.18)(react@18.2.0) react-radio-group: specifier: ^3.0.3 version: 3.0.3(react-dom@18.2.0)(react@18.2.0) From 09b730bc0fac1c88c45ec33d16f851803163ee13 Mon Sep 17 00:00:00 2001 From: Matti Nannt Date: Fri, 18 Aug 2023 09:04:09 +0200 Subject: [PATCH 22/22] Update lock file (#709) --- pnpm-lock.yaml | 553 ++++++++++++++++++++++--------------------------- 1 file changed, 243 insertions(+), 310 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e5547876ef..b2c472cd2f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -19,7 +19,7 @@ importers: version: 3.12.7 turbo: specifier: latest - version: 1.10.12 + version: 1.10.7 apps/demo: dependencies: @@ -31,7 +31,7 @@ importers: version: 2.0.18(react@18.2.0) next: specifier: 13.4.12 - version: 13.4.12(@opentelemetry/api@1.3.0)(react-dom@18.2.0)(react@18.2.0) + version: 13.4.12(react-dom@18.2.0)(react@18.2.0) react: specifier: 18.2.0 version: 18.2.0 @@ -89,7 +89,7 @@ importers: version: 5.12.2 next: specifier: 13.4.12 - version: 13.4.12(@opentelemetry/api@1.3.0)(react-dom@18.2.0)(react@18.2.0) + version: 13.4.12(react-dom@18.2.0)(react@18.2.0) next-plausible: specifier: ^3.10.1 version: 3.10.1(next@13.4.12)(react-dom@18.2.0)(react@18.2.0) @@ -183,7 +183,7 @@ importers: version: 1.0.3(react-dom@18.2.0)(react@18.2.0) '@radix-ui/react-dropdown-menu': specifier: ^2.0.5 - version: 2.0.5(@types/react@18.2.18)(react-dom@18.2.0)(react@18.2.0) + version: 2.0.5(react-dom@18.2.0)(react@18.2.0) '@sentry/nextjs': specifier: ^7.61.0 version: 7.61.0(next@13.4.10)(react@18.2.0) @@ -288,9 +288,6 @@ importers: dotenv-cli: specifier: ^7.2.1 version: 7.2.1 - next-seo: - specifier: ^6.1.0 - version: 6.1.0(next@13.4.12)(react-dom@18.2.0)(react@18.2.0) devDependencies: '@formbricks/tsconfig': specifier: workspace:* @@ -324,7 +321,7 @@ importers: version: link:../database next: specifier: 13.4.12 - version: 13.4.12(@opentelemetry/api@1.3.0)(react-dom@18.2.0)(react@18.2.0) + version: 13.4.12(react-dom@18.2.0)(react@18.2.0) stripe: specifier: ^12.16.0 version: 12.16.0 @@ -340,10 +337,6 @@ importers: version: link:../eslint-config-formbricks packages/errors: - dependencies: - next-seo: - specifier: ^6.1.0 - version: 6.1.0(next@13.4.12)(react-dom@18.2.0)(react@18.2.0) devDependencies: '@formbricks/tsconfig': specifier: workspace:* @@ -356,10 +349,6 @@ importers: version: 7.2.0 packages/eslint-config-formbricks: - dependencies: - next-seo: - specifier: ^6.1.0 - version: 6.1.0(next@13.4.12)(react-dom@18.2.0)(react@18.2.0) devDependencies: eslint: specifier: ^8.46.0 @@ -372,7 +361,7 @@ importers: version: 8.10.0(eslint@8.46.0) eslint-config-turbo: specifier: latest - version: 1.10.12(eslint@8.46.0) + version: 1.8.8(eslint@8.46.0) eslint-plugin-react: specifier: 7.33.1 version: 7.33.1(eslint@8.46.0) @@ -469,15 +458,9 @@ importers: markdown-it: specifier: ^13.0.1 version: 13.0.1 - next-seo: - specifier: ^6.1.0 - version: 6.1.0(next@13.4.12)(react-dom@18.2.0)(react@18.2.0) posthog-node: specifier: ^3.1.1 version: 3.1.1 - react-markdown: - specifier: ^8.0.7 - version: 8.0.7(@types/react@18.2.18)(react@18.2.0) server-only: specifier: ^0.0.1 version: 0.0.1 @@ -520,10 +503,6 @@ importers: version: 3.3.3 packages/tsconfig: - dependencies: - next-seo: - specifier: ^6.1.0 - version: 6.1.0(next@13.4.12)(react-dom@18.2.0)(react@18.2.0) devDependencies: '@types/node': specifier: 20.4.6 @@ -540,9 +519,6 @@ importers: packages/types: dependencies: - next-seo: - specifier: ^6.1.0 - version: 6.1.0(next@13.4.12)(react-dom@18.2.0)(react@18.2.0) zod: specifier: ^3.21.4 version: 3.21.4 @@ -582,31 +558,31 @@ importers: version: 0.11.3(lexical@0.11.3) '@radix-ui/react-checkbox': specifier: ^1.0.4 - version: 1.0.4(@types/react@18.2.18)(react-dom@18.2.0)(react@18.2.0) + version: 1.0.4(react-dom@18.2.0)(react@18.2.0) '@radix-ui/react-dialog': specifier: ^1.0.4 - version: 1.0.4(@types/react@18.2.18)(react-dom@18.2.0)(react@18.2.0) + version: 1.0.4(react-dom@18.2.0)(react@18.2.0) '@radix-ui/react-dropdown-menu': specifier: ^2.0.5 - version: 2.0.5(@types/react@18.2.18)(react-dom@18.2.0)(react@18.2.0) + version: 2.0.5(react-dom@18.2.0)(react@18.2.0) '@radix-ui/react-label': specifier: ^2.0.2 - version: 2.0.2(@types/react@18.2.18)(react-dom@18.2.0)(react@18.2.0) + version: 2.0.2(react-dom@18.2.0)(react@18.2.0) '@radix-ui/react-popover': specifier: ^1.0.6 - version: 1.0.6(@types/react@18.2.18)(react-dom@18.2.0)(react@18.2.0) + version: 1.0.6(react-dom@18.2.0)(react@18.2.0) '@radix-ui/react-radio-group': specifier: ^1.1.3 - version: 1.1.3(@types/react@18.2.18)(react-dom@18.2.0)(react@18.2.0) + version: 1.1.3(react-dom@18.2.0)(react@18.2.0) '@radix-ui/react-select': specifier: ^1.2.2 - version: 1.2.2(@types/react@18.2.18)(react-dom@18.2.0)(react@18.2.0) + version: 1.2.2(react-dom@18.2.0)(react@18.2.0) '@radix-ui/react-switch': specifier: ^1.0.3 - version: 1.0.3(@types/react@18.2.18)(react-dom@18.2.0)(react@18.2.0) + version: 1.0.3(react-dom@18.2.0)(react@18.2.0) '@radix-ui/react-tooltip': specifier: ^1.0.6 - version: 1.0.6(@types/react@18.2.18)(react-dom@18.2.0)(react@18.2.0) + version: 1.0.6(react-dom@18.2.0)(react@18.2.0) boring-avatars: specifier: ^1.10.1 version: 1.10.1 @@ -618,16 +594,13 @@ importers: version: 2.0.0 cmdk: specifier: ^0.2.0 - version: 0.2.0(@types/react@18.2.18)(react-dom@18.2.0)(react@18.2.0) + version: 0.2.0(react-dom@18.2.0)(react@18.2.0) lucide-react: specifier: ^0.263.1 version: 0.263.1(react@18.2.0) next: specifier: 13.4.12 - version: 13.4.12(@opentelemetry/api@1.3.0)(react-dom@18.2.0)(react@18.2.0) - next-seo: - specifier: ^6.1.0 - version: 6.1.0(next@13.4.12)(react-dom@18.2.0)(react@18.2.0) + version: 13.4.12(react-dom@18.2.0)(react@18.2.0) react-colorful: specifier: ^5.6.1 version: 5.6.1(react-dom@18.2.0)(react@18.2.0) @@ -3858,6 +3831,7 @@ packages: /@opentelemetry/api@1.3.0: resolution: {integrity: sha512-YveTnGNsFFixTKJz09Oi4zYkiLT5af3WpZDu4aIUM7xX+2bHAkOJayFTVQd6zB8kkWPpbua4Ha6Ql00grdLlJQ==} engines: {node: '>=8.0.0'} + dev: true /@opentelemetry/core@1.8.0(@opentelemetry/api@1.3.0): resolution: {integrity: sha512-6SDjwBML4Am0AQmy7z1j6HGrWDgeK8awBRUvl1PGw6HayViMk4QpnUXvv4HTHisecgVBy43NE/cstWprm8tIfw==} @@ -4184,7 +4158,7 @@ packages: '@babel/runtime': 7.21.0 dev: false - /@radix-ui/react-arrow@1.0.3(@types/react@18.2.18)(react-dom@18.2.0)(react@18.2.0): + /@radix-ui/react-arrow@1.0.3(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-wSP+pHsB/jQRaL6voubsQ/ZlrGBHHrOjmBnr19hxYgtS0WvAFwZhK2WP/YY5yF9uKECCEEDGxuLxq1NBK51wFA==} peerDependencies: '@types/react': '*' @@ -4198,13 +4172,12 @@ packages: optional: true dependencies: '@babel/runtime': 7.21.0 - '@radix-ui/react-primitive': 1.0.3(@types/react@18.2.18)(react-dom@18.2.0)(react@18.2.0) - '@types/react': 18.2.18 + '@radix-ui/react-primitive': 1.0.3(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) dev: false - /@radix-ui/react-checkbox@1.0.4(@types/react@18.2.18)(react-dom@18.2.0)(react@18.2.0): + /@radix-ui/react-checkbox@1.0.4(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-CBuGQa52aAYnADZVt/KBQzXrwx6TqnlwtcIPGtVt5JkkzQwMOLJjPukimhfKEr4GQNd43C+djUh5Ikopj8pSLg==} peerDependencies: '@types/react': '*' @@ -4219,14 +4192,13 @@ packages: dependencies: '@babel/runtime': 7.21.0 '@radix-ui/primitive': 1.0.1 - '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.18)(react@18.2.0) - '@radix-ui/react-context': 1.0.1(@types/react@18.2.18)(react@18.2.0) - '@radix-ui/react-presence': 1.0.1(@types/react@18.2.18)(react-dom@18.2.0)(react@18.2.0) - '@radix-ui/react-primitive': 1.0.3(@types/react@18.2.18)(react-dom@18.2.0)(react@18.2.0) - '@radix-ui/react-use-controllable-state': 1.0.1(@types/react@18.2.18)(react@18.2.0) - '@radix-ui/react-use-previous': 1.0.1(@types/react@18.2.18)(react@18.2.0) - '@radix-ui/react-use-size': 1.0.1(@types/react@18.2.18)(react@18.2.0) - '@types/react': 18.2.18 + '@radix-ui/react-compose-refs': 1.0.1(react@18.2.0) + '@radix-ui/react-context': 1.0.1(react@18.2.0) + '@radix-ui/react-presence': 1.0.1(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-primitive': 1.0.3(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-use-controllable-state': 1.0.1(react@18.2.0) + '@radix-ui/react-use-previous': 1.0.1(react@18.2.0) + '@radix-ui/react-use-size': 1.0.1(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) dev: false @@ -4246,18 +4218,18 @@ packages: dependencies: '@babel/runtime': 7.21.0 '@radix-ui/primitive': 1.0.1 - '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.18)(react@18.2.0) - '@radix-ui/react-context': 1.0.1(@types/react@18.2.18)(react@18.2.0) - '@radix-ui/react-id': 1.0.1(@types/react@18.2.18)(react@18.2.0) - '@radix-ui/react-presence': 1.0.1(@types/react@18.2.18)(react-dom@18.2.0)(react@18.2.0) - '@radix-ui/react-primitive': 1.0.3(@types/react@18.2.18)(react-dom@18.2.0)(react@18.2.0) - '@radix-ui/react-use-controllable-state': 1.0.1(@types/react@18.2.18)(react@18.2.0) - '@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.2.18)(react@18.2.0) + '@radix-ui/react-compose-refs': 1.0.1(react@18.2.0) + '@radix-ui/react-context': 1.0.1(react@18.2.0) + '@radix-ui/react-id': 1.0.1(react@18.2.0) + '@radix-ui/react-presence': 1.0.1(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-primitive': 1.0.3(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-use-controllable-state': 1.0.1(react@18.2.0) + '@radix-ui/react-use-layout-effect': 1.0.1(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) dev: false - /@radix-ui/react-collection@1.0.3(@types/react@18.2.18)(react-dom@18.2.0)(react@18.2.0): + /@radix-ui/react-collection@1.0.3(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-3SzW+0PW7yBBoQlT8wNcGtaxaD0XSu0uLUFgrtHY08Acx05TaHaOmVLR73c0j/cqpDy53KBMO7s0dx2wmOIDIA==} peerDependencies: '@types/react': '*' @@ -4271,11 +4243,10 @@ packages: optional: true dependencies: '@babel/runtime': 7.21.0 - '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.18)(react@18.2.0) - '@radix-ui/react-context': 1.0.1(@types/react@18.2.18)(react@18.2.0) - '@radix-ui/react-primitive': 1.0.3(@types/react@18.2.18)(react-dom@18.2.0)(react@18.2.0) - '@radix-ui/react-slot': 1.0.2(@types/react@18.2.18)(react@18.2.0) - '@types/react': 18.2.18 + '@radix-ui/react-compose-refs': 1.0.1(react@18.2.0) + '@radix-ui/react-context': 1.0.1(react@18.2.0) + '@radix-ui/react-primitive': 1.0.3(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-slot': 1.0.2(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) dev: false @@ -4289,7 +4260,7 @@ packages: react: 18.2.0 dev: false - /@radix-ui/react-compose-refs@1.0.1(@types/react@18.2.18)(react@18.2.0): + /@radix-ui/react-compose-refs@1.0.1(react@18.2.0): resolution: {integrity: sha512-fDSBgd44FKHa1FRMU59qBMPFcl2PZE+2nmqunj+BWFyYYjnhIDWL2ItDs3rrbJDQOtzt5nIebLCQc4QRfz6LJw==} peerDependencies: '@types/react': '*' @@ -4299,7 +4270,6 @@ packages: optional: true dependencies: '@babel/runtime': 7.21.0 - '@types/react': 18.2.18 react: 18.2.0 dev: false @@ -4312,7 +4282,7 @@ packages: react: 18.2.0 dev: false - /@radix-ui/react-context@1.0.1(@types/react@18.2.18)(react@18.2.0): + /@radix-ui/react-context@1.0.1(react@18.2.0): resolution: {integrity: sha512-ebbrdFoYTcuZ0v4wG5tedGnp9tzcV8awzsxYph7gXUyvnNLuTIcCk1q17JEbnVhXAKG9oX3KtchwiMIAYp9NLg==} peerDependencies: '@types/react': '*' @@ -4322,11 +4292,10 @@ packages: optional: true dependencies: '@babel/runtime': 7.21.0 - '@types/react': 18.2.18 react: 18.2.0 dev: false - /@radix-ui/react-dialog@1.0.0(@types/react@18.2.18)(react-dom@18.2.0)(react@18.2.0): + /@radix-ui/react-dialog@1.0.0(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-Yn9YU+QlHYLWwV1XfKiqnGVpWYWk6MeBVM6x/bcoyPvxgjQGoeT35482viLPctTMWoMw0PoHgqfSox7Ig+957Q==} peerDependencies: react: ^16.8 || ^17.0 || ^18.0 @@ -4348,12 +4317,12 @@ packages: aria-hidden: 1.2.3 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - react-remove-scroll: 2.5.4(@types/react@18.2.18)(react@18.2.0) + react-remove-scroll: 2.5.4(react@18.2.0) transitivePeerDependencies: - '@types/react' dev: false - /@radix-ui/react-dialog@1.0.4(@types/react@18.2.18)(react-dom@18.2.0)(react@18.2.0): + /@radix-ui/react-dialog@1.0.4(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-hJtRy/jPULGQZceSAP2Re6/4NpKo8im6V8P2hUqZsdFiSL8l35kYsw3qbRI6Ay5mQd2+wlLqje770eq+RJ3yZg==} peerDependencies: '@types/react': '*' @@ -4368,25 +4337,24 @@ packages: dependencies: '@babel/runtime': 7.21.0 '@radix-ui/primitive': 1.0.1 - '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.18)(react@18.2.0) - '@radix-ui/react-context': 1.0.1(@types/react@18.2.18)(react@18.2.0) - '@radix-ui/react-dismissable-layer': 1.0.4(@types/react@18.2.18)(react-dom@18.2.0)(react@18.2.0) - '@radix-ui/react-focus-guards': 1.0.1(@types/react@18.2.18)(react@18.2.0) - '@radix-ui/react-focus-scope': 1.0.3(@types/react@18.2.18)(react-dom@18.2.0)(react@18.2.0) - '@radix-ui/react-id': 1.0.1(@types/react@18.2.18)(react@18.2.0) - '@radix-ui/react-portal': 1.0.3(@types/react@18.2.18)(react-dom@18.2.0)(react@18.2.0) - '@radix-ui/react-presence': 1.0.1(@types/react@18.2.18)(react-dom@18.2.0)(react@18.2.0) - '@radix-ui/react-primitive': 1.0.3(@types/react@18.2.18)(react-dom@18.2.0)(react@18.2.0) - '@radix-ui/react-slot': 1.0.2(@types/react@18.2.18)(react@18.2.0) - '@radix-ui/react-use-controllable-state': 1.0.1(@types/react@18.2.18)(react@18.2.0) - '@types/react': 18.2.18 + '@radix-ui/react-compose-refs': 1.0.1(react@18.2.0) + '@radix-ui/react-context': 1.0.1(react@18.2.0) + '@radix-ui/react-dismissable-layer': 1.0.4(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-focus-guards': 1.0.1(react@18.2.0) + '@radix-ui/react-focus-scope': 1.0.3(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-id': 1.0.1(react@18.2.0) + '@radix-ui/react-portal': 1.0.3(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-presence': 1.0.1(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-primitive': 1.0.3(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-slot': 1.0.2(react@18.2.0) + '@radix-ui/react-use-controllable-state': 1.0.1(react@18.2.0) aria-hidden: 1.2.3 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - react-remove-scroll: 2.5.5(@types/react@18.2.18)(react@18.2.0) + react-remove-scroll: 2.5.5(react@18.2.0) dev: false - /@radix-ui/react-direction@1.0.1(@types/react@18.2.18)(react@18.2.0): + /@radix-ui/react-direction@1.0.1(react@18.2.0): resolution: {integrity: sha512-RXcvnXgyvYvBEOhCBuddKecVkoMiI10Jcm5cTI7abJRAHYfFxeu+FBQs/DvdxSYucxR5mna0dNsL6QFlds5TMA==} peerDependencies: '@types/react': '*' @@ -4396,7 +4364,6 @@ packages: optional: true dependencies: '@babel/runtime': 7.21.0 - '@types/react': 18.2.18 react: 18.2.0 dev: false @@ -4416,7 +4383,7 @@ packages: react-dom: 18.2.0(react@18.2.0) dev: false - /@radix-ui/react-dismissable-layer@1.0.4(@types/react@18.2.18)(react-dom@18.2.0)(react@18.2.0): + /@radix-ui/react-dismissable-layer@1.0.4(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-7UpBa/RKMoHJYjie1gkF1DlK8l1fdU/VKDpoS3rCCo8YBJR294GwcEHyxHw72yvphJ7ld0AXEcSLAzY2F/WyCg==} peerDependencies: '@types/react': '*' @@ -4431,16 +4398,15 @@ packages: dependencies: '@babel/runtime': 7.21.0 '@radix-ui/primitive': 1.0.1 - '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.18)(react@18.2.0) - '@radix-ui/react-primitive': 1.0.3(@types/react@18.2.18)(react-dom@18.2.0)(react@18.2.0) - '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.18)(react@18.2.0) - '@radix-ui/react-use-escape-keydown': 1.0.3(@types/react@18.2.18)(react@18.2.0) - '@types/react': 18.2.18 + '@radix-ui/react-compose-refs': 1.0.1(react@18.2.0) + '@radix-ui/react-primitive': 1.0.3(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-use-callback-ref': 1.0.1(react@18.2.0) + '@radix-ui/react-use-escape-keydown': 1.0.3(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) dev: false - /@radix-ui/react-dropdown-menu@2.0.5(@types/react@18.2.18)(react-dom@18.2.0)(react@18.2.0): + /@radix-ui/react-dropdown-menu@2.0.5(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-xdOrZzOTocqqkCkYo8yRPCib5OkTkqN7lqNCdxwPOdE466DOaNl4N8PkUIlsXthQvW5Wwkd+aEmWpfWlBoDPEw==} peerDependencies: '@types/react': '*' @@ -4455,13 +4421,12 @@ packages: dependencies: '@babel/runtime': 7.21.0 '@radix-ui/primitive': 1.0.1 - '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.18)(react@18.2.0) - '@radix-ui/react-context': 1.0.1(@types/react@18.2.18)(react@18.2.0) - '@radix-ui/react-id': 1.0.1(@types/react@18.2.18)(react@18.2.0) - '@radix-ui/react-menu': 2.0.5(@types/react@18.2.18)(react-dom@18.2.0)(react@18.2.0) - '@radix-ui/react-primitive': 1.0.3(@types/react@18.2.18)(react-dom@18.2.0)(react@18.2.0) - '@radix-ui/react-use-controllable-state': 1.0.1(@types/react@18.2.18)(react@18.2.0) - '@types/react': 18.2.18 + '@radix-ui/react-compose-refs': 1.0.1(react@18.2.0) + '@radix-ui/react-context': 1.0.1(react@18.2.0) + '@radix-ui/react-id': 1.0.1(react@18.2.0) + '@radix-ui/react-menu': 2.0.5(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-primitive': 1.0.3(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-use-controllable-state': 1.0.1(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) dev: false @@ -4475,7 +4440,7 @@ packages: react: 18.2.0 dev: false - /@radix-ui/react-focus-guards@1.0.1(@types/react@18.2.18)(react@18.2.0): + /@radix-ui/react-focus-guards@1.0.1(react@18.2.0): resolution: {integrity: sha512-Rect2dWbQ8waGzhMavsIbmSVCgYxkXLxxR3ZvCX79JOglzdEy4JXMb98lq4hPxUbLr77nP0UOGf4rcMU+s1pUA==} peerDependencies: '@types/react': '*' @@ -4485,7 +4450,6 @@ packages: optional: true dependencies: '@babel/runtime': 7.21.0 - '@types/react': 18.2.18 react: 18.2.0 dev: false @@ -4503,7 +4467,7 @@ packages: react-dom: 18.2.0(react@18.2.0) dev: false - /@radix-ui/react-focus-scope@1.0.3(@types/react@18.2.18)(react-dom@18.2.0)(react@18.2.0): + /@radix-ui/react-focus-scope@1.0.3(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-upXdPfqI4islj2CslyfUBNlaJCPybbqRHAi1KER7Isel9Q2AtSJ0zRBZv8mWQiFXD2nyAJ4BhC3yXgZ6kMBSrQ==} peerDependencies: '@types/react': '*' @@ -4517,10 +4481,9 @@ packages: optional: true dependencies: '@babel/runtime': 7.21.0 - '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.18)(react@18.2.0) - '@radix-ui/react-primitive': 1.0.3(@types/react@18.2.18)(react-dom@18.2.0)(react@18.2.0) - '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.18)(react@18.2.0) - '@types/react': 18.2.18 + '@radix-ui/react-compose-refs': 1.0.1(react@18.2.0) + '@radix-ui/react-primitive': 1.0.3(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-use-callback-ref': 1.0.1(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) dev: false @@ -4535,7 +4498,7 @@ packages: react: 18.2.0 dev: false - /@radix-ui/react-id@1.0.1(@types/react@18.2.18)(react@18.2.0): + /@radix-ui/react-id@1.0.1(react@18.2.0): resolution: {integrity: sha512-tI7sT/kqYp8p96yGWY1OAnLHrqDgzHefRBKQ2YAkBS5ja7QLcZ9Z/uY7bEjPUatf8RomoXM8/1sMj1IJaE5UzQ==} peerDependencies: '@types/react': '*' @@ -4545,12 +4508,11 @@ packages: optional: true dependencies: '@babel/runtime': 7.21.0 - '@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.2.18)(react@18.2.0) - '@types/react': 18.2.18 + '@radix-ui/react-use-layout-effect': 1.0.1(react@18.2.0) react: 18.2.0 dev: false - /@radix-ui/react-label@2.0.2(@types/react@18.2.18)(react-dom@18.2.0)(react@18.2.0): + /@radix-ui/react-label@2.0.2(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-N5ehvlM7qoTLx7nWPodsPYPgMzA5WM8zZChQg8nyFJKnDO5WHdba1vv5/H6IO5LtJMfD2Q3wh1qHFGNtK0w3bQ==} peerDependencies: '@types/react': '*' @@ -4564,13 +4526,12 @@ packages: optional: true dependencies: '@babel/runtime': 7.21.0 - '@radix-ui/react-primitive': 1.0.3(@types/react@18.2.18)(react-dom@18.2.0)(react@18.2.0) - '@types/react': 18.2.18 + '@radix-ui/react-primitive': 1.0.3(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) dev: false - /@radix-ui/react-menu@2.0.5(@types/react@18.2.18)(react-dom@18.2.0)(react@18.2.0): + /@radix-ui/react-menu@2.0.5(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-Gw4f9pwdH+w5w+49k0gLjN0PfRDHvxmAgG16AbyJZ7zhwZ6PBHKtWohvnSwfusfnK3L68dpBREHpVkj8wEM7ZA==} peerDependencies: '@types/react': '*' @@ -4585,29 +4546,28 @@ packages: dependencies: '@babel/runtime': 7.21.0 '@radix-ui/primitive': 1.0.1 - '@radix-ui/react-collection': 1.0.3(@types/react@18.2.18)(react-dom@18.2.0)(react@18.2.0) - '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.18)(react@18.2.0) - '@radix-ui/react-context': 1.0.1(@types/react@18.2.18)(react@18.2.0) - '@radix-ui/react-direction': 1.0.1(@types/react@18.2.18)(react@18.2.0) - '@radix-ui/react-dismissable-layer': 1.0.4(@types/react@18.2.18)(react-dom@18.2.0)(react@18.2.0) - '@radix-ui/react-focus-guards': 1.0.1(@types/react@18.2.18)(react@18.2.0) - '@radix-ui/react-focus-scope': 1.0.3(@types/react@18.2.18)(react-dom@18.2.0)(react@18.2.0) - '@radix-ui/react-id': 1.0.1(@types/react@18.2.18)(react@18.2.0) - '@radix-ui/react-popper': 1.1.2(@types/react@18.2.18)(react-dom@18.2.0)(react@18.2.0) - '@radix-ui/react-portal': 1.0.3(@types/react@18.2.18)(react-dom@18.2.0)(react@18.2.0) - '@radix-ui/react-presence': 1.0.1(@types/react@18.2.18)(react-dom@18.2.0)(react@18.2.0) - '@radix-ui/react-primitive': 1.0.3(@types/react@18.2.18)(react-dom@18.2.0)(react@18.2.0) - '@radix-ui/react-roving-focus': 1.0.4(@types/react@18.2.18)(react-dom@18.2.0)(react@18.2.0) - '@radix-ui/react-slot': 1.0.2(@types/react@18.2.18)(react@18.2.0) - '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.18)(react@18.2.0) - '@types/react': 18.2.18 + '@radix-ui/react-collection': 1.0.3(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-compose-refs': 1.0.1(react@18.2.0) + '@radix-ui/react-context': 1.0.1(react@18.2.0) + '@radix-ui/react-direction': 1.0.1(react@18.2.0) + '@radix-ui/react-dismissable-layer': 1.0.4(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-focus-guards': 1.0.1(react@18.2.0) + '@radix-ui/react-focus-scope': 1.0.3(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-id': 1.0.1(react@18.2.0) + '@radix-ui/react-popper': 1.1.2(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-portal': 1.0.3(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-presence': 1.0.1(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-primitive': 1.0.3(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-roving-focus': 1.0.4(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-slot': 1.0.2(react@18.2.0) + '@radix-ui/react-use-callback-ref': 1.0.1(react@18.2.0) aria-hidden: 1.2.3 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - react-remove-scroll: 2.5.5(@types/react@18.2.18)(react@18.2.0) + react-remove-scroll: 2.5.5(react@18.2.0) dev: false - /@radix-ui/react-popover@1.0.6(@types/react@18.2.18)(react-dom@18.2.0)(react@18.2.0): + /@radix-ui/react-popover@1.0.6(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-cZ4defGpkZ0qTRtlIBzJLSzL6ht7ofhhW4i1+pkemjV1IKXm0wgCRnee154qlV6r9Ttunmh2TNZhMfV2bavUyA==} peerDependencies: '@types/react': '*' @@ -4622,26 +4582,25 @@ packages: dependencies: '@babel/runtime': 7.21.0 '@radix-ui/primitive': 1.0.1 - '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.18)(react@18.2.0) - '@radix-ui/react-context': 1.0.1(@types/react@18.2.18)(react@18.2.0) - '@radix-ui/react-dismissable-layer': 1.0.4(@types/react@18.2.18)(react-dom@18.2.0)(react@18.2.0) - '@radix-ui/react-focus-guards': 1.0.1(@types/react@18.2.18)(react@18.2.0) - '@radix-ui/react-focus-scope': 1.0.3(@types/react@18.2.18)(react-dom@18.2.0)(react@18.2.0) - '@radix-ui/react-id': 1.0.1(@types/react@18.2.18)(react@18.2.0) - '@radix-ui/react-popper': 1.1.2(@types/react@18.2.18)(react-dom@18.2.0)(react@18.2.0) - '@radix-ui/react-portal': 1.0.3(@types/react@18.2.18)(react-dom@18.2.0)(react@18.2.0) - '@radix-ui/react-presence': 1.0.1(@types/react@18.2.18)(react-dom@18.2.0)(react@18.2.0) - '@radix-ui/react-primitive': 1.0.3(@types/react@18.2.18)(react-dom@18.2.0)(react@18.2.0) - '@radix-ui/react-slot': 1.0.2(@types/react@18.2.18)(react@18.2.0) - '@radix-ui/react-use-controllable-state': 1.0.1(@types/react@18.2.18)(react@18.2.0) - '@types/react': 18.2.18 + '@radix-ui/react-compose-refs': 1.0.1(react@18.2.0) + '@radix-ui/react-context': 1.0.1(react@18.2.0) + '@radix-ui/react-dismissable-layer': 1.0.4(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-focus-guards': 1.0.1(react@18.2.0) + '@radix-ui/react-focus-scope': 1.0.3(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-id': 1.0.1(react@18.2.0) + '@radix-ui/react-popper': 1.1.2(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-portal': 1.0.3(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-presence': 1.0.1(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-primitive': 1.0.3(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-slot': 1.0.2(react@18.2.0) + '@radix-ui/react-use-controllable-state': 1.0.1(react@18.2.0) aria-hidden: 1.2.3 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - react-remove-scroll: 2.5.5(@types/react@18.2.18)(react@18.2.0) + react-remove-scroll: 2.5.5(react@18.2.0) dev: false - /@radix-ui/react-popper@1.1.2(@types/react@18.2.18)(react-dom@18.2.0)(react@18.2.0): + /@radix-ui/react-popper@1.1.2(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-1CnGGfFi/bbqtJZZ0P/NQY20xdG3E0LALJaLUEoKwPLwl6PPPfbeiCqMVQnhoFRAxjJj4RpBRJzDmUgsex2tSg==} peerDependencies: '@types/react': '*' @@ -4656,16 +4615,15 @@ packages: dependencies: '@babel/runtime': 7.21.0 '@floating-ui/react-dom': 2.0.0(react-dom@18.2.0)(react@18.2.0) - '@radix-ui/react-arrow': 1.0.3(@types/react@18.2.18)(react-dom@18.2.0)(react@18.2.0) - '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.18)(react@18.2.0) - '@radix-ui/react-context': 1.0.1(@types/react@18.2.18)(react@18.2.0) - '@radix-ui/react-primitive': 1.0.3(@types/react@18.2.18)(react-dom@18.2.0)(react@18.2.0) - '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.18)(react@18.2.0) - '@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.2.18)(react@18.2.0) - '@radix-ui/react-use-rect': 1.0.1(@types/react@18.2.18)(react@18.2.0) - '@radix-ui/react-use-size': 1.0.1(@types/react@18.2.18)(react@18.2.0) + '@radix-ui/react-arrow': 1.0.3(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-compose-refs': 1.0.1(react@18.2.0) + '@radix-ui/react-context': 1.0.1(react@18.2.0) + '@radix-ui/react-primitive': 1.0.3(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-use-callback-ref': 1.0.1(react@18.2.0) + '@radix-ui/react-use-layout-effect': 1.0.1(react@18.2.0) + '@radix-ui/react-use-rect': 1.0.1(react@18.2.0) + '@radix-ui/react-use-size': 1.0.1(react@18.2.0) '@radix-ui/rect': 1.0.1 - '@types/react': 18.2.18 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) dev: false @@ -4682,7 +4640,7 @@ packages: react-dom: 18.2.0(react@18.2.0) dev: false - /@radix-ui/react-portal@1.0.3(@types/react@18.2.18)(react-dom@18.2.0)(react@18.2.0): + /@radix-ui/react-portal@1.0.3(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-xLYZeHrWoPmA5mEKEfZZevoVRK/Q43GfzRXkWV6qawIWWK8t6ifIiLQdd7rmQ4Vk1bmI21XhqF9BN3jWf+phpA==} peerDependencies: '@types/react': '*' @@ -4696,8 +4654,7 @@ packages: optional: true dependencies: '@babel/runtime': 7.21.0 - '@radix-ui/react-primitive': 1.0.3(@types/react@18.2.18)(react-dom@18.2.0)(react@18.2.0) - '@types/react': 18.2.18 + '@radix-ui/react-primitive': 1.0.3(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) dev: false @@ -4715,7 +4672,7 @@ packages: react-dom: 18.2.0(react@18.2.0) dev: false - /@radix-ui/react-presence@1.0.1(@types/react@18.2.18)(react-dom@18.2.0)(react@18.2.0): + /@radix-ui/react-presence@1.0.1(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-UXLW4UAbIY5ZjcvzjfRFo5gxva8QirC9hF7wRE4U5gz+TP0DbRk+//qyuAQ1McDxBt1xNMBTaciFGvEmJvAZCg==} peerDependencies: '@types/react': '*' @@ -4729,9 +4686,8 @@ packages: optional: true dependencies: '@babel/runtime': 7.21.0 - '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.18)(react@18.2.0) - '@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.2.18)(react@18.2.0) - '@types/react': 18.2.18 + '@radix-ui/react-compose-refs': 1.0.1(react@18.2.0) + '@radix-ui/react-use-layout-effect': 1.0.1(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) dev: false @@ -4748,7 +4704,7 @@ packages: react-dom: 18.2.0(react@18.2.0) dev: false - /@radix-ui/react-primitive@1.0.3(@types/react@18.2.18)(react-dom@18.2.0)(react@18.2.0): + /@radix-ui/react-primitive@1.0.3(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-yi58uVyoAcK/Nq1inRY56ZSjKypBNKTa/1mcL8qdl6oJeEaDbOldlzrGn7P6Q3Id5d+SYNGc5AJgc4vGhjs5+g==} peerDependencies: '@types/react': '*' @@ -4762,13 +4718,12 @@ packages: optional: true dependencies: '@babel/runtime': 7.21.0 - '@radix-ui/react-slot': 1.0.2(@types/react@18.2.18)(react@18.2.0) - '@types/react': 18.2.18 + '@radix-ui/react-slot': 1.0.2(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) dev: false - /@radix-ui/react-radio-group@1.1.3(@types/react@18.2.18)(react-dom@18.2.0)(react@18.2.0): + /@radix-ui/react-radio-group@1.1.3(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-x+yELayyefNeKeTx4fjK6j99Fs6c4qKm3aY38G3swQVTN6xMpsrbigC0uHs2L//g8q4qR7qOcww8430jJmi2ag==} peerDependencies: '@types/react': '*' @@ -4783,21 +4738,20 @@ packages: dependencies: '@babel/runtime': 7.21.0 '@radix-ui/primitive': 1.0.1 - '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.18)(react@18.2.0) - '@radix-ui/react-context': 1.0.1(@types/react@18.2.18)(react@18.2.0) - '@radix-ui/react-direction': 1.0.1(@types/react@18.2.18)(react@18.2.0) - '@radix-ui/react-presence': 1.0.1(@types/react@18.2.18)(react-dom@18.2.0)(react@18.2.0) - '@radix-ui/react-primitive': 1.0.3(@types/react@18.2.18)(react-dom@18.2.0)(react@18.2.0) - '@radix-ui/react-roving-focus': 1.0.4(@types/react@18.2.18)(react-dom@18.2.0)(react@18.2.0) - '@radix-ui/react-use-controllable-state': 1.0.1(@types/react@18.2.18)(react@18.2.0) - '@radix-ui/react-use-previous': 1.0.1(@types/react@18.2.18)(react@18.2.0) - '@radix-ui/react-use-size': 1.0.1(@types/react@18.2.18)(react@18.2.0) - '@types/react': 18.2.18 + '@radix-ui/react-compose-refs': 1.0.1(react@18.2.0) + '@radix-ui/react-context': 1.0.1(react@18.2.0) + '@radix-ui/react-direction': 1.0.1(react@18.2.0) + '@radix-ui/react-presence': 1.0.1(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-primitive': 1.0.3(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-roving-focus': 1.0.4(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-use-controllable-state': 1.0.1(react@18.2.0) + '@radix-ui/react-use-previous': 1.0.1(react@18.2.0) + '@radix-ui/react-use-size': 1.0.1(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) dev: false - /@radix-ui/react-roving-focus@1.0.4(@types/react@18.2.18)(react-dom@18.2.0)(react@18.2.0): + /@radix-ui/react-roving-focus@1.0.4(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-2mUg5Mgcu001VkGy+FfzZyzbmuUWzgWkj3rvv4yu+mLw03+mTzbxZHvfcGyFp2b8EkQeMkpRQ5FiA2Vr2O6TeQ==} peerDependencies: '@types/react': '*' @@ -4812,20 +4766,19 @@ packages: dependencies: '@babel/runtime': 7.21.0 '@radix-ui/primitive': 1.0.1 - '@radix-ui/react-collection': 1.0.3(@types/react@18.2.18)(react-dom@18.2.0)(react@18.2.0) - '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.18)(react@18.2.0) - '@radix-ui/react-context': 1.0.1(@types/react@18.2.18)(react@18.2.0) - '@radix-ui/react-direction': 1.0.1(@types/react@18.2.18)(react@18.2.0) - '@radix-ui/react-id': 1.0.1(@types/react@18.2.18)(react@18.2.0) - '@radix-ui/react-primitive': 1.0.3(@types/react@18.2.18)(react-dom@18.2.0)(react@18.2.0) - '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.18)(react@18.2.0) - '@radix-ui/react-use-controllable-state': 1.0.1(@types/react@18.2.18)(react@18.2.0) - '@types/react': 18.2.18 + '@radix-ui/react-collection': 1.0.3(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-compose-refs': 1.0.1(react@18.2.0) + '@radix-ui/react-context': 1.0.1(react@18.2.0) + '@radix-ui/react-direction': 1.0.1(react@18.2.0) + '@radix-ui/react-id': 1.0.1(react@18.2.0) + '@radix-ui/react-primitive': 1.0.3(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-use-callback-ref': 1.0.1(react@18.2.0) + '@radix-ui/react-use-controllable-state': 1.0.1(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) dev: false - /@radix-ui/react-select@1.2.2(@types/react@18.2.18)(react-dom@18.2.0)(react@18.2.0): + /@radix-ui/react-select@1.2.2(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-zI7McXr8fNaSrUY9mZe4x/HC0jTLY9fWNhO1oLWYMQGDXuV4UCivIGTxwioSzO0ZCYX9iSLyWmAh/1TOmX3Cnw==} peerDependencies: '@types/react': '*' @@ -4841,28 +4794,27 @@ packages: '@babel/runtime': 7.21.0 '@radix-ui/number': 1.0.1 '@radix-ui/primitive': 1.0.1 - '@radix-ui/react-collection': 1.0.3(@types/react@18.2.18)(react-dom@18.2.0)(react@18.2.0) - '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.18)(react@18.2.0) - '@radix-ui/react-context': 1.0.1(@types/react@18.2.18)(react@18.2.0) - '@radix-ui/react-direction': 1.0.1(@types/react@18.2.18)(react@18.2.0) - '@radix-ui/react-dismissable-layer': 1.0.4(@types/react@18.2.18)(react-dom@18.2.0)(react@18.2.0) - '@radix-ui/react-focus-guards': 1.0.1(@types/react@18.2.18)(react@18.2.0) - '@radix-ui/react-focus-scope': 1.0.3(@types/react@18.2.18)(react-dom@18.2.0)(react@18.2.0) - '@radix-ui/react-id': 1.0.1(@types/react@18.2.18)(react@18.2.0) - '@radix-ui/react-popper': 1.1.2(@types/react@18.2.18)(react-dom@18.2.0)(react@18.2.0) - '@radix-ui/react-portal': 1.0.3(@types/react@18.2.18)(react-dom@18.2.0)(react@18.2.0) - '@radix-ui/react-primitive': 1.0.3(@types/react@18.2.18)(react-dom@18.2.0)(react@18.2.0) - '@radix-ui/react-slot': 1.0.2(@types/react@18.2.18)(react@18.2.0) - '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.18)(react@18.2.0) - '@radix-ui/react-use-controllable-state': 1.0.1(@types/react@18.2.18)(react@18.2.0) - '@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.2.18)(react@18.2.0) - '@radix-ui/react-use-previous': 1.0.1(@types/react@18.2.18)(react@18.2.0) - '@radix-ui/react-visually-hidden': 1.0.3(@types/react@18.2.18)(react-dom@18.2.0)(react@18.2.0) - '@types/react': 18.2.18 + '@radix-ui/react-collection': 1.0.3(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-compose-refs': 1.0.1(react@18.2.0) + '@radix-ui/react-context': 1.0.1(react@18.2.0) + '@radix-ui/react-direction': 1.0.1(react@18.2.0) + '@radix-ui/react-dismissable-layer': 1.0.4(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-focus-guards': 1.0.1(react@18.2.0) + '@radix-ui/react-focus-scope': 1.0.3(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-id': 1.0.1(react@18.2.0) + '@radix-ui/react-popper': 1.1.2(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-portal': 1.0.3(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-primitive': 1.0.3(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-slot': 1.0.2(react@18.2.0) + '@radix-ui/react-use-callback-ref': 1.0.1(react@18.2.0) + '@radix-ui/react-use-controllable-state': 1.0.1(react@18.2.0) + '@radix-ui/react-use-layout-effect': 1.0.1(react@18.2.0) + '@radix-ui/react-use-previous': 1.0.1(react@18.2.0) + '@radix-ui/react-visually-hidden': 1.0.3(react-dom@18.2.0)(react@18.2.0) aria-hidden: 1.2.3 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - react-remove-scroll: 2.5.5(@types/react@18.2.18)(react@18.2.0) + react-remove-scroll: 2.5.5(react@18.2.0) dev: false /@radix-ui/react-slot@1.0.0(react@18.2.0): @@ -4875,7 +4827,7 @@ packages: react: 18.2.0 dev: false - /@radix-ui/react-slot@1.0.2(@types/react@18.2.18)(react@18.2.0): + /@radix-ui/react-slot@1.0.2(react@18.2.0): resolution: {integrity: sha512-YeTpuq4deV+6DusvVUW4ivBgnkHwECUu0BiN43L5UCDFgdhsRUWAghhTF5MbvNTPzmiFOx90asDSUjWuCNapwg==} peerDependencies: '@types/react': '*' @@ -4885,12 +4837,11 @@ packages: optional: true dependencies: '@babel/runtime': 7.21.0 - '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.18)(react@18.2.0) - '@types/react': 18.2.18 + '@radix-ui/react-compose-refs': 1.0.1(react@18.2.0) react: 18.2.0 dev: false - /@radix-ui/react-switch@1.0.3(@types/react@18.2.18)(react-dom@18.2.0)(react@18.2.0): + /@radix-ui/react-switch@1.0.3(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-mxm87F88HyHztsI7N+ZUmEoARGkC22YVW5CaC+Byc+HRpuvCrOBPTAnXgf+tZ/7i0Sg/eOePGdMhUKhPaQEqow==} peerDependencies: '@types/react': '*' @@ -4905,18 +4856,17 @@ packages: dependencies: '@babel/runtime': 7.21.0 '@radix-ui/primitive': 1.0.1 - '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.18)(react@18.2.0) - '@radix-ui/react-context': 1.0.1(@types/react@18.2.18)(react@18.2.0) - '@radix-ui/react-primitive': 1.0.3(@types/react@18.2.18)(react-dom@18.2.0)(react@18.2.0) - '@radix-ui/react-use-controllable-state': 1.0.1(@types/react@18.2.18)(react@18.2.0) - '@radix-ui/react-use-previous': 1.0.1(@types/react@18.2.18)(react@18.2.0) - '@radix-ui/react-use-size': 1.0.1(@types/react@18.2.18)(react@18.2.0) - '@types/react': 18.2.18 + '@radix-ui/react-compose-refs': 1.0.1(react@18.2.0) + '@radix-ui/react-context': 1.0.1(react@18.2.0) + '@radix-ui/react-primitive': 1.0.3(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-use-controllable-state': 1.0.1(react@18.2.0) + '@radix-ui/react-use-previous': 1.0.1(react@18.2.0) + '@radix-ui/react-use-size': 1.0.1(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) dev: false - /@radix-ui/react-tooltip@1.0.6(@types/react@18.2.18)(react-dom@18.2.0)(react@18.2.0): + /@radix-ui/react-tooltip@1.0.6(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-DmNFOiwEc2UDigsYj6clJENma58OelxD24O4IODoZ+3sQc3Zb+L8w1EP+y9laTuKCLAysPw4fD6/v0j4KNV8rg==} peerDependencies: '@types/react': '*' @@ -4931,18 +4881,17 @@ packages: dependencies: '@babel/runtime': 7.21.0 '@radix-ui/primitive': 1.0.1 - '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.18)(react@18.2.0) - '@radix-ui/react-context': 1.0.1(@types/react@18.2.18)(react@18.2.0) - '@radix-ui/react-dismissable-layer': 1.0.4(@types/react@18.2.18)(react-dom@18.2.0)(react@18.2.0) - '@radix-ui/react-id': 1.0.1(@types/react@18.2.18)(react@18.2.0) - '@radix-ui/react-popper': 1.1.2(@types/react@18.2.18)(react-dom@18.2.0)(react@18.2.0) - '@radix-ui/react-portal': 1.0.3(@types/react@18.2.18)(react-dom@18.2.0)(react@18.2.0) - '@radix-ui/react-presence': 1.0.1(@types/react@18.2.18)(react-dom@18.2.0)(react@18.2.0) - '@radix-ui/react-primitive': 1.0.3(@types/react@18.2.18)(react-dom@18.2.0)(react@18.2.0) - '@radix-ui/react-slot': 1.0.2(@types/react@18.2.18)(react@18.2.0) - '@radix-ui/react-use-controllable-state': 1.0.1(@types/react@18.2.18)(react@18.2.0) - '@radix-ui/react-visually-hidden': 1.0.3(@types/react@18.2.18)(react-dom@18.2.0)(react@18.2.0) - '@types/react': 18.2.18 + '@radix-ui/react-compose-refs': 1.0.1(react@18.2.0) + '@radix-ui/react-context': 1.0.1(react@18.2.0) + '@radix-ui/react-dismissable-layer': 1.0.4(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-id': 1.0.1(react@18.2.0) + '@radix-ui/react-popper': 1.1.2(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-portal': 1.0.3(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-presence': 1.0.1(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-primitive': 1.0.3(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-slot': 1.0.2(react@18.2.0) + '@radix-ui/react-use-controllable-state': 1.0.1(react@18.2.0) + '@radix-ui/react-visually-hidden': 1.0.3(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) dev: false @@ -4956,7 +4905,7 @@ packages: react: 18.2.0 dev: false - /@radix-ui/react-use-callback-ref@1.0.1(@types/react@18.2.18)(react@18.2.0): + /@radix-ui/react-use-callback-ref@1.0.1(react@18.2.0): resolution: {integrity: sha512-D94LjX4Sp0xJFVaoQOd3OO9k7tpBYNOXdVhkltUbGv2Qb9OXdrg/CpsjlZv7ia14Sylv398LswWBVVu5nqKzAQ==} peerDependencies: '@types/react': '*' @@ -4966,7 +4915,6 @@ packages: optional: true dependencies: '@babel/runtime': 7.21.0 - '@types/react': 18.2.18 react: 18.2.0 dev: false @@ -4980,7 +4928,7 @@ packages: react: 18.2.0 dev: false - /@radix-ui/react-use-controllable-state@1.0.1(@types/react@18.2.18)(react@18.2.0): + /@radix-ui/react-use-controllable-state@1.0.1(react@18.2.0): resolution: {integrity: sha512-Svl5GY5FQeN758fWKrjM6Qb7asvXeiZltlT4U2gVfl8Gx5UAv2sMR0LWo8yhsIZh2oQ0eFdZ59aoOOMV7b47VA==} peerDependencies: '@types/react': '*' @@ -4990,8 +4938,7 @@ packages: optional: true dependencies: '@babel/runtime': 7.21.0 - '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.18)(react@18.2.0) - '@types/react': 18.2.18 + '@radix-ui/react-use-callback-ref': 1.0.1(react@18.2.0) react: 18.2.0 dev: false @@ -5005,7 +4952,7 @@ packages: react: 18.2.0 dev: false - /@radix-ui/react-use-escape-keydown@1.0.3(@types/react@18.2.18)(react@18.2.0): + /@radix-ui/react-use-escape-keydown@1.0.3(react@18.2.0): resolution: {integrity: sha512-vyL82j40hcFicA+M4Ex7hVkB9vHgSse1ZWomAqV2Je3RleKGO5iM8KMOEtfoSB0PnIelMd2lATjTGMYqN5ylTg==} peerDependencies: '@types/react': '*' @@ -5015,8 +4962,7 @@ packages: optional: true dependencies: '@babel/runtime': 7.21.0 - '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.18)(react@18.2.0) - '@types/react': 18.2.18 + '@radix-ui/react-use-callback-ref': 1.0.1(react@18.2.0) react: 18.2.0 dev: false @@ -5029,7 +4975,7 @@ packages: react: 18.2.0 dev: false - /@radix-ui/react-use-layout-effect@1.0.1(@types/react@18.2.18)(react@18.2.0): + /@radix-ui/react-use-layout-effect@1.0.1(react@18.2.0): resolution: {integrity: sha512-v/5RegiJWYdoCvMnITBkNNx6bCj20fiaJnWtRkU18yITptraXjffz5Qbn05uOiQnOvi+dbkznkoaMltz1GnszQ==} peerDependencies: '@types/react': '*' @@ -5039,11 +4985,10 @@ packages: optional: true dependencies: '@babel/runtime': 7.21.0 - '@types/react': 18.2.18 react: 18.2.0 dev: false - /@radix-ui/react-use-previous@1.0.1(@types/react@18.2.18)(react@18.2.0): + /@radix-ui/react-use-previous@1.0.1(react@18.2.0): resolution: {integrity: sha512-cV5La9DPwiQ7S0gf/0qiD6YgNqM5Fk97Kdrlc5yBcrF3jyEZQwm7vYFqMo4IfeHgJXsRaMvLABFtd0OVEmZhDw==} peerDependencies: '@types/react': '*' @@ -5053,11 +4998,10 @@ packages: optional: true dependencies: '@babel/runtime': 7.21.0 - '@types/react': 18.2.18 react: 18.2.0 dev: false - /@radix-ui/react-use-rect@1.0.1(@types/react@18.2.18)(react@18.2.0): + /@radix-ui/react-use-rect@1.0.1(react@18.2.0): resolution: {integrity: sha512-Cq5DLuSiuYVKNU8orzJMbl15TXilTnJKUCltMVQg53BQOF1/C5toAaGrowkgksdBQ9H+SRL23g0HDmg9tvmxXw==} peerDependencies: '@types/react': '*' @@ -5068,11 +5012,10 @@ packages: dependencies: '@babel/runtime': 7.21.0 '@radix-ui/rect': 1.0.1 - '@types/react': 18.2.18 react: 18.2.0 dev: false - /@radix-ui/react-use-size@1.0.1(@types/react@18.2.18)(react@18.2.0): + /@radix-ui/react-use-size@1.0.1(react@18.2.0): resolution: {integrity: sha512-ibay+VqrgcaI6veAojjofPATwledXiSmX+C0KrBk/xgpX9rBzPV3OsfwlhQdUOFbh+LKQorLYT+xTXW9V8yd0g==} peerDependencies: '@types/react': '*' @@ -5082,12 +5025,11 @@ packages: optional: true dependencies: '@babel/runtime': 7.21.0 - '@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.2.18)(react@18.2.0) - '@types/react': 18.2.18 + '@radix-ui/react-use-layout-effect': 1.0.1(react@18.2.0) react: 18.2.0 dev: false - /@radix-ui/react-visually-hidden@1.0.3(@types/react@18.2.18)(react-dom@18.2.0)(react@18.2.0): + /@radix-ui/react-visually-hidden@1.0.3(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-D4w41yN5YRKtu464TLnByKzMDG/JlMPHtfZgQAu9v6mNakUqGUI9vUrfQKz8NK41VMm/xbZbh76NUTVtIYqOMA==} peerDependencies: '@types/react': '*' @@ -5101,8 +5043,7 @@ packages: optional: true dependencies: '@babel/runtime': 7.21.0 - '@radix-ui/react-primitive': 1.0.3(@types/react@18.2.18)(react-dom@18.2.0)(react@18.2.0) - '@types/react': 18.2.18 + '@radix-ui/react-primitive': 1.0.3(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) dev: false @@ -8023,13 +7964,13 @@ packages: engines: {node: '>=6'} dev: false - /cmdk@0.2.0(@types/react@18.2.18)(react-dom@18.2.0)(react@18.2.0): + /cmdk@0.2.0(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-JQpKvEOb86SnvMZbYaFKYhvzFntWBeSZdyii0rZPhKJj9uwJBxu4DaVYDrRN7r3mPop56oPhRw+JYWTKs66TYw==} peerDependencies: react: ^18.0.0 react-dom: ^18.0.0 dependencies: - '@radix-ui/react-dialog': 1.0.0(@types/react@18.2.18)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-dialog': 1.0.0(react-dom@18.2.0)(react@18.2.0) command-score: 0.1.2 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) @@ -9915,13 +9856,13 @@ packages: eslint: 8.46.0 dev: true - /eslint-config-turbo@1.10.12(eslint@8.46.0): - resolution: {integrity: sha512-z3jfh+D7UGYlzMWGh+Kqz++hf8LOE96q3o5R8X4HTjmxaBWlLAWG+0Ounr38h+JLR2TJno0hU9zfzoPNkR9BdA==} + /eslint-config-turbo@1.8.8(eslint@8.46.0): + resolution: {integrity: sha512-+yT22sHOT5iC1sbBXfLIdXfbZuiv9bAyOXsxTxFCWelTeFFnANqmuKB3x274CFvf7WRuZ/vYP/VMjzU9xnFnxA==} peerDependencies: eslint: '>6.6.0' dependencies: eslint: 8.46.0 - eslint-plugin-turbo: 1.10.12(eslint@8.46.0) + eslint-plugin-turbo: 1.8.8(eslint@8.46.0) dev: true /eslint-import-resolver-node@0.3.6: @@ -10109,12 +10050,11 @@ packages: semver: 6.3.1 string.prototype.matchall: 4.0.8 - /eslint-plugin-turbo@1.10.12(eslint@8.46.0): - resolution: {integrity: sha512-uNbdj+ohZaYo4tFJ6dStRXu2FZigwulR1b3URPXe0Q8YaE7thuekKNP+54CHtZPH9Zey9dmDx5btAQl9mfzGOw==} + /eslint-plugin-turbo@1.8.8(eslint@8.46.0): + resolution: {integrity: sha512-zqyTIvveOY4YU5jviDWw9GXHd4RiKmfEgwsjBrV/a965w0PpDwJgEUoSMB/C/dU310Sv9mF3DSdEjxjJLaw6rA==} peerDependencies: eslint: '>6.6.0' dependencies: - dotenv: 16.0.3 eslint: 8.46.0 dev: true @@ -14740,7 +14680,7 @@ packages: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 dependencies: - next: 13.4.12(@opentelemetry/api@1.3.0)(react-dom@18.2.0)(react@18.2.0) + next: 13.4.12(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) dev: false @@ -14752,7 +14692,7 @@ packages: react: '>=16.0.0' react-dom: '>=16.0.0' dependencies: - next: 13.4.12(@opentelemetry/api@1.3.0)(react-dom@18.2.0)(react@18.2.0) + next: 13.4.12(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) dev: false @@ -14768,7 +14708,7 @@ packages: '@next/env': 13.4.8 fast-glob: 3.2.12 minimist: 1.2.8 - next: 13.4.12(@opentelemetry/api@1.3.0)(react-dom@18.2.0)(react@18.2.0) + next: 13.4.12(react-dom@18.2.0)(react@18.2.0) dev: false /next@13.4.10(react-dom@18.2.0)(react@18.2.0): @@ -14814,7 +14754,7 @@ packages: - babel-plugin-macros dev: false - /next@13.4.12(@opentelemetry/api@1.3.0)(react-dom@18.2.0)(react@18.2.0): + /next@13.4.12(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-eHfnru9x6NRmTMcjQp6Nz0J4XH9OubmzOa7CkWL+AUrUxpibub3vWwttjduu9No16dug1kq04hiUUpo7J3m3Xw==} engines: {node: '>=16.8.0'} hasBin: true @@ -14833,7 +14773,6 @@ packages: optional: true dependencies: '@next/env': 13.4.12 - '@opentelemetry/api': 1.3.0 '@swc/helpers': 0.5.1 busboy: 1.6.0 caniuse-lite: 1.0.30001512 @@ -17523,7 +17462,7 @@ packages: engines: {node: '>=0.10.0'} dev: true - /react-remove-scroll-bar@2.3.4(@types/react@18.2.18)(react@18.2.0): + /react-remove-scroll-bar@2.3.4(react@18.2.0): resolution: {integrity: sha512-63C4YQBUt0m6ALadE9XV56hV8BgJWDmmTPY758iIJjfQKt2nYwoUrPk0LXRXcB/yIj82T1/Ixfdpdk68LwIB0A==} engines: {node: '>=10'} peerDependencies: @@ -17533,13 +17472,12 @@ packages: '@types/react': optional: true dependencies: - '@types/react': 18.2.18 react: 18.2.0 - react-style-singleton: 2.2.1(@types/react@18.2.18)(react@18.2.0) + react-style-singleton: 2.2.1(react@18.2.0) tslib: 2.5.3 dev: false - /react-remove-scroll@2.5.4(@types/react@18.2.18)(react@18.2.0): + /react-remove-scroll@2.5.4(react@18.2.0): resolution: {integrity: sha512-xGVKJJr0SJGQVirVFAUZ2k1QLyO6m+2fy0l8Qawbp5Jgrv3DeLalrfMNBFSlmz5kriGGzsVBtGVnf4pTKIhhWA==} engines: {node: '>=10'} peerDependencies: @@ -17549,16 +17487,15 @@ packages: '@types/react': optional: true dependencies: - '@types/react': 18.2.18 react: 18.2.0 - react-remove-scroll-bar: 2.3.4(@types/react@18.2.18)(react@18.2.0) - react-style-singleton: 2.2.1(@types/react@18.2.18)(react@18.2.0) + react-remove-scroll-bar: 2.3.4(react@18.2.0) + react-style-singleton: 2.2.1(react@18.2.0) tslib: 2.5.3 - use-callback-ref: 1.3.0(@types/react@18.2.18)(react@18.2.0) - use-sidecar: 1.1.2(@types/react@18.2.18)(react@18.2.0) + use-callback-ref: 1.3.0(react@18.2.0) + use-sidecar: 1.1.2(react@18.2.0) dev: false - /react-remove-scroll@2.5.5(@types/react@18.2.18)(react@18.2.0): + /react-remove-scroll@2.5.5(react@18.2.0): resolution: {integrity: sha512-ImKhrzJJsyXJfBZ4bzu8Bwpka14c/fQt0k+cyFp/PBhTfyDnU5hjOtM4AG/0AMyy8oKzOTR0lDgJIM7pYXI0kw==} engines: {node: '>=10'} peerDependencies: @@ -17568,13 +17505,12 @@ packages: '@types/react': optional: true dependencies: - '@types/react': 18.2.18 react: 18.2.0 - react-remove-scroll-bar: 2.3.4(@types/react@18.2.18)(react@18.2.0) - react-style-singleton: 2.2.1(@types/react@18.2.18)(react@18.2.0) + react-remove-scroll-bar: 2.3.4(react@18.2.0) + react-style-singleton: 2.2.1(react@18.2.0) tslib: 2.5.3 - use-callback-ref: 1.3.0(@types/react@18.2.18)(react@18.2.0) - use-sidecar: 1.1.2(@types/react@18.2.18)(react@18.2.0) + use-callback-ref: 1.3.0(react@18.2.0) + use-sidecar: 1.1.2(react@18.2.0) dev: false /react-responsive-embed@2.1.0(prop-types@15.8.1)(react@18.2.0): @@ -17588,7 +17524,7 @@ packages: react: 18.2.0 dev: false - /react-style-singleton@2.2.1(@types/react@18.2.18)(react@18.2.0): + /react-style-singleton@2.2.1(react@18.2.0): resolution: {integrity: sha512-ZWj0fHEMyWkHzKYUr2Bs/4zU6XLmq9HsgBURm7g5pAVfyn49DgUiNgY2d4lXRlYSiCif9YBGpQleewkcqddc7g==} engines: {node: '>=10'} peerDependencies: @@ -17598,7 +17534,6 @@ packages: '@types/react': optional: true dependencies: - '@types/react': 18.2.18 get-nonce: 1.0.1 invariant: 2.2.4 react: 18.2.0 @@ -19974,65 +19909,65 @@ packages: dependencies: safe-buffer: 5.2.1 - /turbo-darwin-64@1.10.12: - resolution: {integrity: sha512-vmDfGVPl5/aFenAbOj3eOx3ePNcWVUyZwYr7taRl0ZBbmv2TzjRiFotO4vrKCiTVnbqjQqAFQWY2ugbqCI1kOQ==} + /turbo-darwin-64@1.10.7: + resolution: {integrity: sha512-N2MNuhwrl6g7vGuz4y3fFG2aR1oCs0UZ5HKl8KSTn/VC2y2YIuLGedQ3OVbo0TfEvygAlF3QGAAKKtOCmGPNKA==} cpu: [x64] os: [darwin] requiresBuild: true dev: true optional: true - /turbo-darwin-arm64@1.10.12: - resolution: {integrity: sha512-3JliEESLNX2s7g54SOBqqkqJ7UhcOGkS0ywMr5SNuvF6kWVTbuUq7uBU/sVbGq8RwvK1ONlhPvJne5MUqBCTCQ==} + /turbo-darwin-arm64@1.10.7: + resolution: {integrity: sha512-WbJkvjU+6qkngp7K4EsswOriO3xrNQag7YEGRtfLoDdMTk4O4QTeU6sfg2dKfDsBpTidTvEDwgIYJhYVGzrz9Q==} cpu: [arm64] os: [darwin] requiresBuild: true dev: true optional: true - /turbo-linux-64@1.10.12: - resolution: {integrity: sha512-siYhgeX0DidIfHSgCR95b8xPee9enKSOjCzx7EjTLmPqPaCiVebRYvbOIYdQWRqiaKh9yfhUtFmtMOMScUf1gg==} + /turbo-linux-64@1.10.7: + resolution: {integrity: sha512-x1CF2CDP1pDz/J8/B2T0hnmmOQI2+y11JGIzNP0KtwxDM7rmeg3DDTtDM/9PwGqfPotN9iVGgMiMvBuMFbsLhg==} cpu: [x64] os: [linux] requiresBuild: true dev: true optional: true - /turbo-linux-arm64@1.10.12: - resolution: {integrity: sha512-K/ZhvD9l4SslclaMkTiIrnfcACgos79YcAo4kwc8bnMQaKuUeRpM15sxLpZp3xDjDg8EY93vsKyjaOhdFG2UbA==} + /turbo-linux-arm64@1.10.7: + resolution: {integrity: sha512-JtnBmaBSYbs7peJPkXzXxsRGSGBmBEIb6/kC8RRmyvPAMyqF8wIex0pttsI+9plghREiGPtRWv/lfQEPRlXnNQ==} cpu: [arm64] os: [linux] requiresBuild: true dev: true optional: true - /turbo-windows-64@1.10.12: - resolution: {integrity: sha512-7FSgSwvktWDNOqV65l9AbZwcoueAILeE4L7JvjauNASAjjbuzXGCEq5uN8AQU3U5BOFj4TdXrVmO2dX+lLu8Zg==} + /turbo-windows-64@1.10.7: + resolution: {integrity: sha512-7A/4CByoHdolWS8dg3DPm99owfu1aY/W0V0+KxFd0o2JQMTQtoBgIMSvZesXaWM57z3OLsietFivDLQPuzE75w==} cpu: [x64] os: [win32] requiresBuild: true dev: true optional: true - /turbo-windows-arm64@1.10.12: - resolution: {integrity: sha512-gCNXF52dwom1HLY9ry/cneBPOKTBHhzpqhMylcyvJP0vp9zeMQQkt6yjYv+6QdnmELC92CtKNp2FsNZo+z0pyw==} + /turbo-windows-arm64@1.10.7: + resolution: {integrity: sha512-D36K/3b6+hqm9IBAymnuVgyePktwQ+F0lSXr2B9JfAdFPBktSqGmp50JNC7pahxhnuCLj0Vdpe9RqfnJw5zATA==} cpu: [arm64] os: [win32] requiresBuild: true dev: true optional: true - /turbo@1.10.12: - resolution: {integrity: sha512-WM3+jTfQWnB9W208pmP4oeehZcC6JQNlydb/ZHMRrhmQa+htGhWLCzd6Q9rLe0MwZLPpSPFV2/bN5egCLyoKjQ==} + /turbo@1.10.7: + resolution: {integrity: sha512-xm0MPM28TWx1e6TNC3wokfE5eaDqlfi0G24kmeHupDUZt5Wd0OzHFENEHMPqEaNKJ0I+AMObL6nbSZonZBV2HA==} hasBin: true requiresBuild: true optionalDependencies: - turbo-darwin-64: 1.10.12 - turbo-darwin-arm64: 1.10.12 - turbo-linux-64: 1.10.12 - turbo-linux-arm64: 1.10.12 - turbo-windows-64: 1.10.12 - turbo-windows-arm64: 1.10.12 + turbo-darwin-64: 1.10.7 + turbo-darwin-arm64: 1.10.7 + turbo-linux-64: 1.10.7 + turbo-linux-arm64: 1.10.7 + turbo-windows-64: 1.10.7 + turbo-windows-arm64: 1.10.7 dev: true /tween-functions@1.2.0: @@ -20500,7 +20435,7 @@ packages: querystring: 0.2.0 dev: true - /use-callback-ref@1.3.0(@types/react@18.2.18)(react@18.2.0): + /use-callback-ref@1.3.0(react@18.2.0): resolution: {integrity: sha512-3FT9PRuRdbB9HfXhEq35u4oZkvpJ5kuYbpqhCfmiZyReuRgpnhDlbr2ZEnnuS0RrJAPn6l23xjFg9kpDM+Ms7w==} engines: {node: '>=10'} peerDependencies: @@ -20510,7 +20445,6 @@ packages: '@types/react': optional: true dependencies: - '@types/react': 18.2.18 react: 18.2.0 tslib: 2.5.3 dev: false @@ -20523,7 +20457,7 @@ packages: react: 18.2.0 dev: false - /use-sidecar@1.1.2(@types/react@18.2.18)(react@18.2.0): + /use-sidecar@1.1.2(react@18.2.0): resolution: {integrity: sha512-epTbsLuzZ7lPClpz2TyryBfztm7m+28DlEv2ZCQ3MDr5ssiwyOwGH/e5F9CkfWjJ1t4clvI58yF822/GUkjjhw==} engines: {node: '>=10'} peerDependencies: @@ -20533,7 +20467,6 @@ packages: '@types/react': optional: true dependencies: - '@types/react': 18.2.18 detect-node-es: 1.1.0 react: 18.2.0 tslib: 2.5.3