diff --git a/LICENSE b/LICENSE index 81998a1128..549e017679 100644 --- a/LICENSE +++ b/LICENSE @@ -3,7 +3,7 @@ Copyright (c) 2023 Matthias Nannt, Johannes Dancker Portions of this software are licensed as follows: - All content that resides under the "packages/ee/" directory of this repository, if that directory exists, is licensed under the license defined in "packages/ee/LICENSE". -- All content that resides under the "packages/js/" directory of this repository, if that directory exists, is licensed under the "MIT" license as defined in "packages/js/LICENSE". +- All content that resides under the "packages/js/", "packages/errors/" and "packages/api/" directories of this repository, if that directories exist, is licensed under the "MIT" license as defined in the "LICENSE" files of these packages. - All third party components incorporated into the Formbricks Software are licensed under the original license provided by the owner of the applicable component. - Content outside of the above mentioned directories or restrictions above is available under the "AGPLv3" license as defined below. @@ -67,7 +67,7 @@ modification follow. TERMS AND CONDITIONS -0. Definitions. +1. Definitions. "This License" refers to version 3 of the GNU Affero General Public License. diff --git a/README.md b/README.md index a6677ea3ab..295c8c81c6 100644 --- a/README.md +++ b/README.md @@ -12,67 +12,83 @@

-License Join Formbricks Discord Github Stars +License Join Formbricks Discord Github Stars Hacker News Product Hunt + Github Accelerator +


-## About Formbricks +

+Trusted by      +      +      +      + +

-formbricks-sneak +## ✨ About Formbricks -Formbricks productizes best practices for qualitative in-app user discovery. Use micro-surveys to target the right users at the right time without making surveys annoying. +formbricks-sneak + +Formbricks is your go-to solution for in-product micro-surveys that will supercharge your product experience. Use micro-surveys to target the right users at the right time without making surveys annoying. **Try it out in the cloud at [formbricks.com](https://formbricks.com)** -### Mission: Base your decisions on qualitative data. +## 💪 Mission: Make customer-centric decisions based on data. -Formbricks helps you apply best practices from data-driven work and experience management to make better business decisions. Use Formbricks to collect and manage insights from your users; run a product market fit survey to know which audience to focus on and whether your value proposition is being recognized. +Formbricks helps you apply best practices from data-driven work and experience management to make better business decisions. Ask users as they experience your product - and leverage a significantly higher conversion rate. Gather all insights you can - including partial submissions and build conviction for the next product decision. Better data, better business. ### Features -- 📲 Create in-product surveys with our no code editor with multiple question types -- 📚 Choose from a variety of best-practice templates -- 👩🏻 Launch and target your surveys to specific user groups without changing your application code -- 🔗 Create shareable link surveys -- 👨‍👩‍👦 Invite your team members to collaborate on your surveys -- 🔌 Integrate Formbricks with Slack, Posthog, Zapier and more -- 🔒 All open source, transparent and self-hostable +- 📲 Create **in-product surveys** with our no code editor with multiple question types +- 📚 Choose from a variety of best-practice **templates** +- 👩🏻 Launch and **target your surveys to specific user groups** without changing your application code +- 🔗 Create shareable **link surveys** +- 👨‍👩‍👦 Invite your team members to **collaborate** on your surveys +- 🔌 Integrate Formbricks with **Slack, Posthog, Zapier and more** +- 🔒 All **open source**, transparent and self-hostable -### Built With +### Built on Open Source -- [Typescript](https://www.typescriptlang.org/) -- [Next.js](https://nextjs.org/) -- [React](https://reactjs.org/) -- [TailwindCSS](https://tailwindcss.com/) -- [Prisma](https://prisma.io/) +- 💻 [Typescript](https://www.typescriptlang.org/) +- 🚀 [Next.js](https://nextjs.org/) +- ⚛️ [React](https://reactjs.org/) +- 🎨 [TailwindCSS](https://tailwindcss.com/) +- 📚 [Prisma](https://prisma.io/) +- 🔒 [Auth.js](https://authjs.dev/) +- 🧘‍♂️ [Zod](https://zod.dev/) -### Upcoming Features +## 🚀 Getting started -| | Feature | -| --- | ------------------------------------------ | -| 👷 | Zapier, Slack & Posthog Integration | -| 👷 | Webhooks | -| 🗒️ | Filtering Options in Survey Analysis | -| 🗒️ | Multi-Language Functionality | -| 🗒️ | Auto-complete Surveys after at x responses | -| 🗒️ | Pre-Fill Link-Surveys | -| 🗒️ | E-Mail Surveys | +### ☁️ Cloud Version -_👷 In Progress | 🗒️ Up Next_ +Formbricks has a hosted cloud offering with a generous free plan to get you up and running as quickly as possible. To get started, please visit [formbricks.com](https://formbricks.com) -## Cloud vs. self-hosted +### 🐳 Self-hosted version -Formbricks is available Open-Source under AGPLv3 license. You can host Formbricks on your own servers without a subscription. Check out our [docs](https://formbricks.com/docs/self-hosting/deployment) to see how to self-host Formbricks. - -We also have a hosted cloud offering with a generous free plan to get you up and running as quickly as possible. For more information, please visit [formbricks.com](https://formbricks.com) +Formbricks is available Open-Source under AGPLv3 license. You can host Formbricks on your own servers using Docker without a subscription. To get started with self-hosting, take a look at our [self-hosting docs](https://formbricks.com/docs/self-hosting/deployment). (In the future we may develop additional features that aren't in the free Open-Source version) -## Contributing +## ✍️ Contribution We are very happy if you are interested in contributing to Formbricks 🤗 -There are many ways to contribute to Formbricks with writing Issues, fixing bugs, building new features or updating the docs. Please check out [our contribution guide](https://formbricks.com/docs/contributing/introduction) for more information. +Here are a few options: + +- Star this repo +- Create issues every time you feel something is missing or goes wrong +- Upvote issues with 👍 reaction so we know what's the demand for particular issue to prioritize it within roadmap + +Please check out [our contribution guide](https://formbricks.com/docs/contributing/introduction) and our [list of open issues](https://github.com/formbricks/formbricks/issues) for more information. + +## ⚖️ License + +Distributed under the AGPLv3 License. See `LICENSE` for more information. + +## 🔒 Security + +We take security very seriously. If you come across any security vulnerabilities, please disclose them by sending an email to security@formbricks.com. We appreciate your help in making our platform as secure as possible and are committed to working with you to resolve any issues quickly and efficiently. See `SECURITY.md` for more information. diff --git a/apps/demo/package.json b/apps/demo/package.json index fe1bdd65d8..4c78ae98e2 100644 --- a/apps/demo/package.json +++ b/apps/demo/package.json @@ -12,22 +12,21 @@ "dependencies": { "@formbricks/js": "workspace:*", "@heroicons/react": "^2.0.17", - "@types/node": "18.15.11", - "@types/react": "18.0.33", - "@types/react-dom": "18.0.11", "console-feed": "^3.5.0", - "eslint": "8.37.0", "eslint-config-formbricks": "workspace:*", "next": "13.2.4", "react": "18.2.0", - "react-dom": "18.2.0", - "typescript": "5.0.3" + "react-dom": "18.2.0" }, "devDependencies": { "@tailwindcss/forms": "^0.5.3", + "@types/node": "18.15.11", + "@types/react-dom": "18.0.11", + "@types/react": "18.0.33", "autoprefixer": "^10.4.14", "postcss": "^8.4.21", "rimraf": "^5.0.0", - "tailwindcss": "^3.3.1" + "tailwindcss": "^3.3.1", + "typescript": "5.0.3" } } diff --git a/apps/formbricks-com/lib/cn.ts b/apps/formbricks-com/lib/cn.ts deleted file mode 100644 index cec6ac9e86..0000000000 --- a/apps/formbricks-com/lib/cn.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { ClassValue, clsx } from "clsx"; -import { twMerge } from "tailwind-merge"; - -export function cn(...inputs: ClassValue[]) { - return twMerge(clsx(inputs)); -} diff --git a/apps/formbricks-com/package.json b/apps/formbricks-com/package.json index 1b5e4b9eb4..ff595434a8 100644 --- a/apps/formbricks-com/package.json +++ b/apps/formbricks-com/package.json @@ -12,44 +12,44 @@ }, "dependencies": { "@calcom/embed-react": "^1.1.1", - "@docsearch/react": "^3.3.3", + "@docsearch/react": "^3.5.1", "@formbricks/lib": "workspace:*", "@formbricks/types": "workspace:*", "@formbricks/ui": "workspace:*", - "@headlessui/react": "^1.7.14", - "@heroicons/react": "^2.0.17", + "@headlessui/react": "^1.7.15", + "@heroicons/react": "^2.0.18", "@mapbox/rehype-prism": "^0.8.0", "@mdx-js/loader": "^2.3.0", "@mdx-js/react": "^2.3.0", - "@next/mdx": "^13.3.0", - "add": "^2.0.6", + "@next/mdx": "^13.4.7", + "@paralleldrive/cuid2": "^2.2.0", "clsx": "^1.2.1", - "lottie-web": "^5.11.0", - "next": "13.3.0", - "next-plausible": "^3.7.2", - "next-sitemap": "^4.0.7", - "prism-react-renderer": "^1.3.5", + "lottie-web": "^5.12.2", + "next": "13.4.7", + "next-plausible": "^3.8.0", + "next-sitemap": "^4.1.3", + "prism-react-renderer": "^2.0.6", "prismjs": "^1.29.0", "react": "18.2.0", "react-dom": "18.2.0", - "react-hook-form": "^7.43.9", + "react-icons": "^4.8.0", "react-responsive-embed": "^2.1.0", "remark-gfm": "^3.0.1", - "sharp": "^0.32.0" + "sharp": "^0.32.1" }, "devDependencies": { "@formbricks/tsconfig": "workspace:*", "@tailwindcss/forms": "^0.5.3", "@tailwindcss/typography": "^0.5.9", - "@types/node": "18.15.11", + "@types/node": "20.3.2", "@types/prismjs": "^1.26.0", - "@types/react": "^18.0.35", - "@types/react-dom": "^18.0.11", + "@types/react": "18.2.7", + "@types/react-dom": "18.2.4", "autoprefixer": "^10.4.14", "eslint-config-formbricks": "workspace:*", - "postcss": "^8.4.22", - "rimraf": "^5.0.0", - "tailwindcss": "^3.3.1", - "typescript": "^5.0.4" + "postcss": "^8.4.24", + "rimraf": "^5.0.1", + "tailwindcss": "^3.3.2", + "typescript": "5.0.4" } } diff --git a/apps/web/app/ClientLogout.tsx b/apps/web/app/ClientLogout.tsx new file mode 100644 index 0000000000..d5f26fc4c8 --- /dev/null +++ b/apps/web/app/ClientLogout.tsx @@ -0,0 +1,11 @@ +"use client"; + +import { signOut } from "next-auth/react"; +import { useEffect } from "react"; + +export default function ClientLogout() { + useEffect(() => { + signOut(); + }); + return null; +} diff --git a/apps/web/app/api/v1/client/actions/route.ts b/apps/web/app/api/v1/client/actions/route.ts deleted file mode 100644 index 4db063e56e..0000000000 --- a/apps/web/app/api/v1/client/actions/route.ts +++ /dev/null @@ -1,63 +0,0 @@ -/* -THIS FILE IS WORK IN PROGRESS -PLEASE DO NOT USE IT YET -*/ - -import { responses } from "@/lib/api/response"; -import { prisma } from "@formbricks/database"; -import { NextResponse } from "next/server"; - -export async function OPTIONS(): Promise { - return responses.successResponse({}, true); -} - -export async function POST(request: Request): Promise { - const { sessionId, environmentId, eventName, properties } = await request.json(); - - if (!sessionId) { - return responses.missingFieldResponse("sessionId", true); - } - - if (!environmentId) { - return responses.missingFieldResponse("environmentId", true); - } - - if (!eventName) { - return responses.missingFieldResponse("eventName", true); - } - - const action = await prisma.event.create({ - data: { - properties, - session: { - connect: { - id: sessionId, - }, - }, - eventClass: { - connectOrCreate: { - where: { - name_environmentId: { - name: eventName, - environmentId, - }, - }, - create: { - name: eventName, - type: "code", - environment: { - connect: { - id: environmentId, - }, - }, - }, - }, - }, - }, - select: { - id: true, - }, - }); - - return responses.successResponse(action, true); -} diff --git a/apps/web/app/api/v1/client/sessions/route.ts b/apps/web/app/api/v1/client/sessions/route.ts deleted file mode 100644 index 55bb3bea60..0000000000 --- a/apps/web/app/api/v1/client/sessions/route.ts +++ /dev/null @@ -1,33 +0,0 @@ -/* -THIS FILE IS WORK IN PROGRESS -PLEASE DO NOT USE IT YET -*/ - -import { createSession } from "@/lib/api/clientSession"; -import { getSettings } from "@/lib/api/clientSettings"; -import { responses } from "@/lib/api/response"; -import { captureTelemetry } from "@formbricks/lib/telemetry"; -import { NextResponse } from "next/server"; - -export async function OPTIONS(): Promise { - return responses.successResponse({}, true); -} - -export async function POST(request: Request): Promise { - const { personId, environmentId } = await request.json(); - - if (!personId) { - return responses.missingFieldResponse("sessionId", true); - } - - if (!environmentId) { - return responses.missingFieldResponse("environmentId", true); - } - - const session = await createSession(personId); - const { surveys, noCodeEvents, brandColor } = await getSettings(environmentId, personId); - - captureTelemetry("session created"); - - return responses.successResponse({ session, surveys, noCodeEvents, brandColor }, true); -} diff --git a/apps/web/app/api/v1/client/settings/route.ts b/apps/web/app/api/v1/client/settings/route.ts deleted file mode 100644 index 23199d7383..0000000000 --- a/apps/web/app/api/v1/client/settings/route.ts +++ /dev/null @@ -1,43 +0,0 @@ -/* -THIS FILE IS WORK IN PROGRESS -PLEASE DO NOT USE IT YET -*/ - -import { getSettings } from "@/lib/api/clientSettings"; -import { responses } from "@/lib/api/response"; -import { prisma } from "@formbricks/database"; -import { captureTelemetry } from "@formbricks/lib/telemetry"; -import { NextResponse } from "next/server"; - -export async function OPTIONS(): Promise { - return responses.successResponse({}, true); -} - -export async function POST(request: Request): Promise { - const { userCuid } = await request.json(); - - if (!userCuid) { - return responses.missingFieldResponse("userCuid", true); - } - - // get user - const user = await prisma.person.findUnique({ - where: { - id: userCuid, - }, - select: { - id: true, - environmentId: true, - }, - }); - - if (!user) { - return responses.notFoundResponse("User", userCuid, true); - } - - const { surveys, noCodeEvents, brandColor } = await getSettings(user.environmentId, user.id); - - captureTelemetry("session created"); - - return responses.successResponse({ surveys, noCodeEvents, brandColor }, true); -} diff --git a/apps/web/app/api/v1/client/users/[userCuid]/attribute/route.ts b/apps/web/app/api/v1/client/users/[userCuid]/attribute/route.ts deleted file mode 100644 index 3925e2a2a1..0000000000 --- a/apps/web/app/api/v1/client/users/[userCuid]/attribute/route.ts +++ /dev/null @@ -1,135 +0,0 @@ -/* -THIS FILE IS WORK IN PROGRESS -PLEASE DO NOT USE IT YET -*/ - -import { getSettings } from "@/lib/api/clientSettings"; -import { responses } from "@/lib/api/response"; -import { prisma } from "@formbricks/database"; -import { NextResponse } from "next/server"; - -export async function OPTIONS(): Promise { - return responses.successResponse({}, true); -} - -export async function POST(request: Request, params: { userCuid: string }): Promise { - const { userCuid } = params; - const { key, value } = await request.json(); - - if (!key) { - return responses.missingFieldResponse("key", true); - } - - if (!value) { - return responses.missingFieldResponse("value", true); - } - - const currentPerson = await prisma.person.findUnique({ - where: { - id: userCuid, - }, - select: { - id: true, - environmentId: true, - attributes: { - select: { - id: true, - attributeClass: { - select: { - name: true, - }, - }, - }, - }, - }, - }); - - if (!currentPerson) { - return responses.notFoundResponse("User", userCuid, true); - } - - const environmentId = currentPerson.environmentId; - - // find attribute class - let attributeClass = await prisma.attributeClass.findUnique({ - where: { - name_environmentId: { - name: key, - environmentId, - }, - }, - select: { - id: true, - }, - }); - - // create new attribute class if not found - if (attributeClass === null) { - attributeClass = await prisma.attributeClass.create({ - data: { - name: key, - type: "code", - environment: { - connect: { - id: environmentId, - }, - }, - }, - select: { - id: true, - }, - }); - } - - // upsert attribute (update or create) - const attribute = await prisma.attribute.upsert({ - where: { - attributeClassId_personId: { - attributeClassId: attributeClass.id, - personId: userCuid, - }, - }, - update: { - value, - }, - create: { - attributeClass: { - connect: { - id: attributeClass.id, - }, - }, - person: { - connect: { - id: userCuid, - }, - }, - value, - }, - select: { - person: { - select: { - id: true, - environmentId: true, - attributes: { - select: { - id: true, - value: true, - attributeClass: { - select: { - id: true, - name: true, - }, - }, - }, - }, - }, - }, - }, - }); - - const user = attribute.person; - - const { surveys, noCodeEvents, brandColor } = await getSettings(environmentId, user.id); - - return responses.successResponse({ user, surveys, noCodeEvents, brandColor }, true); -} diff --git a/apps/web/app/api/v1/client/users/[userCuid]/user-id/route.ts b/apps/web/app/api/v1/client/users/[userCuid]/user-id/route.ts deleted file mode 100644 index e55f41977b..0000000000 --- a/apps/web/app/api/v1/client/users/[userCuid]/user-id/route.ts +++ /dev/null @@ -1,142 +0,0 @@ -/* -THIS FILE IS WORK IN PROGRESS -PLEASE DO NOT USE IT YET -*/ - -import { getSettings } from "@/lib/api/clientSettings"; -import { responses } from "@/lib/api/response"; -import { prisma } from "@formbricks/database"; -import { NextResponse } from "next/server"; - -export async function OPTIONS(): Promise { - return responses.successResponse({}, true); -} - -export async function POST(request: Request, params: { userCuid: string }): Promise { - const { userCuid } = params; - const { userId, sessionId } = await request.json(); - - if (!userId) { - return responses.missingFieldResponse("userId", true); - } - - if (!sessionId) { - return responses.missingFieldResponse("sessionId", true); - } - - let returnedUser; - - // find person - const person = await prisma.person.findUnique({ - where: { - id: userCuid, - }, - select: { - id: true, - environmentId: true, - }, - }); - - if (!person) { - return responses.notFoundResponse("User", userCuid, true); - } - - const environmentId = person.environmentId; - - // check if person with this userId already exists - const existingPerson = await prisma.person.findFirst({ - where: { - environmentId, - attributes: { - some: { - attributeClass: { - name: "userId", - }, - value: userId, - }, - }, - }, - select: { - id: true, - environmentId: true, - attributes: { - select: { - id: true, - value: true, - attributeClass: { - select: { - id: true, - name: true, - }, - }, - }, - }, - }, - }); - // if person exists, reconnect ression and delete old user - if (existingPerson) { - // reconnect session to new person - await prisma.session.update({ - where: { - id: sessionId, - }, - data: { - person: { - connect: { - id: existingPerson.id, - }, - }, - }, - }); - - // delete old person - await prisma.person.delete({ - where: { - id: userCuid, - }, - }); - returnedUser = existingPerson; - } else { - // update person - returnedUser = await prisma.person.update({ - where: { - id: userCuid, - }, - data: { - attributes: { - create: { - value: userId, - attributeClass: { - connect: { - name_environmentId: { - name: "userId", - environmentId, - }, - }, - }, - }, - }, - }, - select: { - id: true, - environmentId: true, - attributes: { - select: { - id: true, - value: true, - attributeClass: { - select: { - id: true, - name: true, - }, - }, - }, - }, - }, - }); - } - - const { surveys, noCodeEvents, brandColor } = await getSettings(environmentId, returnedUser.id); - - return responses.successResponse({ user: returnedUser, surveys, noCodeEvents, brandColor }, true); -} diff --git a/apps/web/app/api/v1/client/users/route.ts b/apps/web/app/api/v1/client/users/route.ts deleted file mode 100644 index d8e04b4b5c..0000000000 --- a/apps/web/app/api/v1/client/users/route.ts +++ /dev/null @@ -1,28 +0,0 @@ -/* -THIS FILE IS WORK IN PROGRESS -PLEASE DO NOT USE IT YET -*/ - -import { createPerson } from "@/lib/api/clientPerson"; -import { createSession } from "@/lib/api/clientSession"; -import { getSettings } from "@/lib/api/clientSettings"; -import { responses } from "@/lib/api/response"; -import { NextResponse } from "next/server"; - -export async function OPTIONS(): Promise { - return responses.successResponse({}, true); -} - -export async function POST(request: Request): Promise { - const { environmentId } = await request.json(); - - if (!environmentId) { - return responses.missingFieldResponse("environmentId", true); - } - - const user = await createPerson(environmentId); - const session = await createSession(user.id); - const { surveys, noCodeEvents, brandColor } = await getSettings(environmentId, user.id); - - return responses.successResponse({ user, session, surveys, noCodeEvents, brandColor }, true); -} diff --git a/apps/web/app/environments/[environmentId]/surveys/[surveyId]/edit/AudienceView.tsx b/apps/web/app/environments/[environmentId]/surveys/[surveyId]/edit/AudienceView.tsx index e37b7165f4..4a5759ab0b 100644 --- a/apps/web/app/environments/[environmentId]/surveys/[surveyId]/edit/AudienceView.tsx +++ b/apps/web/app/environments/[environmentId]/surveys/[surveyId]/edit/AudienceView.tsx @@ -32,7 +32,9 @@ export default function AudienceView({ environmentId, localSurvey, setLocalSurve environmentId={environmentId} /> - {localSurvey.type==="link" && } + {localSurvey.type === "link" && ( + + )} void; -} - -export default function SurveyCreatedSuccessModal({ open, setOpen }: SurveyCreatedSuccessModalProps) { - return ( - <> - - Your survey is live and collecting valuable insights! - - - ); -} diff --git a/apps/web/app/environments/[environmentId]/surveys/templates/TemplateMenuBar.tsx b/apps/web/app/environments/[environmentId]/surveys/templates/TemplateMenuBar.tsx deleted file mode 100644 index 511925e32d..0000000000 --- a/apps/web/app/environments/[environmentId]/surveys/templates/TemplateMenuBar.tsx +++ /dev/null @@ -1,44 +0,0 @@ -"use client"; - -import { createSurvey } from "@/lib/surveys/surveys"; -import type { Template } from "@formbricks/types/templates"; -import { Button } from "@formbricks/ui"; -import { ArrowLeftIcon, ArrowRightIcon } from "@heroicons/react/24/solid"; -import { useRouter } from "next/navigation"; -import { useState } from "react"; - -interface TemplateMenuBarProps { - activeTemplate: Template | null; - environmentId: string; -} - -export default function TemplateMenuBar({ activeTemplate, environmentId }: TemplateMenuBarProps) { - const router = useRouter(); - const [loading, setLoading] = useState(false); - const addSurvey = async (activeTemplate) => { - setLoading(true); - const survey = await createSurvey(environmentId, activeTemplate.preset); - router.push(`/environments/${environmentId}/surveys/${survey.id}/edit`); - }; - - return ( -
-
- -

Start with a template

-
-
- -
-
- ); -} diff --git a/apps/web/app/environments/[environmentId]/surveys/templates/page.tsx b/apps/web/app/environments/[environmentId]/surveys/templates/page.tsx index 15eb6badfa..6e9a1be8e1 100644 --- a/apps/web/app/environments/[environmentId]/surveys/templates/page.tsx +++ b/apps/web/app/environments/[environmentId]/surveys/templates/page.tsx @@ -6,12 +6,9 @@ import { useProduct } from "@/lib/products/products"; import { replacePresetPlaceholders } from "@/lib/templates"; import type { Template } from "@formbricks/types/templates"; import { ErrorComponent } from "@formbricks/ui"; -/* import { PaintBrushIcon } from "@heroicons/react/24/solid"; -import Link from "next/link"; */ import { useEffect, useState } from "react"; import PreviewSurvey from "../PreviewSurvey"; import TemplateList from "./TemplateList"; -/* import TemplateMenuBar from "./TemplateMenuBar"; */ import { templates } from "./templates"; export default function SurveyTemplatesPage({ params }) { @@ -36,7 +33,6 @@ export default function SurveyTemplatesPage({ params }) { return (
- {/* */}

Create a new survey

diff --git a/apps/web/app/page.tsx b/apps/web/app/page.tsx index b516bd63fc..8c0a36a8b7 100644 --- a/apps/web/app/page.tsx +++ b/apps/web/app/page.tsx @@ -1,5 +1,6 @@ -import { WEBAPP_URL } from "@/../../packages/lib/constants"; +import ClientLogout from "@/app/ClientLogout"; import { authOptions } from "@/app/api/auth/[...nextauth]/authOptions"; +import { WEBAPP_URL } from "@formbricks/lib/constants"; import type { Session } from "next-auth"; import { getServerSession } from "next-auth"; import { headers } from "next/headers"; @@ -14,6 +15,8 @@ async function getEnvironment() { }); if (!res.ok) { + const error = await res.json(); + console.error(error); throw new Error("Failed to fetch data"); } @@ -31,10 +34,16 @@ export default async function Home() { return redirect(`/onboarding`); } - const environment = await getEnvironment(); + let environment; + try { + environment = await getEnvironment(); + } catch (error) { + console.error("error getting environment", error); + } if (!environment) { - throw Error("No environment found for user"); + console.error("Failed to get first environment of user; signing out"); + return ; } return redirect(`/environments/${environment.id}`); diff --git a/apps/web/components/Smileys.tsx b/apps/web/components/Smileys.tsx index 8115f244d4..1dc7b009a6 100644 --- a/apps/web/components/Smileys.tsx +++ b/apps/web/components/Smileys.tsx @@ -460,5 +460,3 @@ export const GrinningSquintingFace: React.FC> = ); }; - -export let icons = []; diff --git a/apps/web/components/auth/SignupForm.tsx b/apps/web/components/auth/SignupForm.tsx index a9e0e40319..dc93f572fb 100644 --- a/apps/web/components/auth/SignupForm.tsx +++ b/apps/web/components/auth/SignupForm.tsx @@ -21,8 +21,8 @@ export const SignupForm = () => { const handleSubmit = async (e: any) => { e.preventDefault(); - if(!isValid){ - return + if (!isValid) { + return; } setSigningUp(true); try { @@ -48,8 +48,8 @@ export const SignupForm = () => { const [isButtonEnabled, setButtonEnabled] = useState(true); const [isPasswordFocused, setIsPasswordFocused] = useState(false); const formRef = useRef(null); - const [password, setPassword] = useState(null) - const [isValid, setIsValid] = useState(false) + const [password, setPassword] = useState(null); + const [isValid, setIsValid] = useState(false); const checkFormValidity = () => { // If all fields are filled, enable the button @@ -145,7 +145,7 @@ export const SignupForm = () => { )} diff --git a/apps/web/components/preview/RedirectCountDown.tsx b/apps/web/components/preview/RedirectCountDown.tsx index c3d2130048..40d7a70f15 100644 --- a/apps/web/components/preview/RedirectCountDown.tsx +++ b/apps/web/components/preview/RedirectCountDown.tsx @@ -1,33 +1,30 @@ -import React from 'react' -import { useEffect,useState } from 'react' +import React from "react"; +import { useEffect, useState } from "react"; -export default function RedirectCountDown({ - initiateCountdown -}:{ - initiateCountdown:boolean|undefined -}) { +export default function RedirectCountDown({ initiateCountdown }: { initiateCountdown: boolean | undefined }) { + const [timeRemaining, setTimeRemaining] = useState(3); - const [timeRemaining, setTimeRemaining] = useState(3) - - useEffect(() => { - const interval = setInterval(() => { - setTimeRemaining((prevTime) => prevTime - 1); - }, 1000); - - if (timeRemaining === 0) { - clearInterval(interval); - } - - // Clean up the interval when the component is unmounted - return () => clearInterval(interval); - }, [timeRemaining]); + useEffect(() => { + const interval = setInterval(() => { + setTimeRemaining((prevTime) => prevTime - 1); + }, 1000); - return ( -
- {initiateCountdown &&
- You're redirected in - {timeRemaining} -
} + if (timeRemaining === 0) { + clearInterval(interval); + } + + // Clean up the interval when the component is unmounted + return () => clearInterval(interval); + }, [timeRemaining]); + + return ( +
+ {initiateCountdown && ( +
+ You're redirected in + {timeRemaining}
- ) + )} +
+ ); } diff --git a/apps/web/components/preview/ThankYouCard.tsx b/apps/web/components/preview/ThankYouCard.tsx index 21cee6bdc8..0869b24037 100644 --- a/apps/web/components/preview/ThankYouCard.tsx +++ b/apps/web/components/preview/ThankYouCard.tsx @@ -9,7 +9,12 @@ interface ThankYouCardProps { initiateCountdown?: boolean; } -export default function ThankYouCard({ headline, subheader, brandColor,initiateCountdown }: ThankYouCardProps) { +export default function ThankYouCard({ + headline, + subheader, + brandColor, + initiateCountdown, +}: ThankYouCardProps) { return (
@@ -33,7 +38,7 @@ export default function ThankYouCard({ headline, subheader, brandColor,initiateC
- +
); diff --git a/apps/web/components/shared/ContentWrapper.tsx b/apps/web/components/shared/ContentWrapper.tsx index 60d1b9e7c1..373bd00888 100644 --- a/apps/web/components/shared/ContentWrapper.tsx +++ b/apps/web/components/shared/ContentWrapper.tsx @@ -1,4 +1,4 @@ -import clsx from "clsx"; +import { cn } from "@formbricks/lib/cn"; interface ContentWrapperProps { children: React.ReactNode; @@ -6,5 +6,5 @@ interface ContentWrapperProps { } export default function ContentWrapper({ children, className }: ContentWrapperProps) { - return
{children}
; + return
{children}
; } diff --git a/apps/web/lib/apiKeys.ts b/apps/web/lib/apiKeys.ts index d1e058efc4..584ded13f7 100644 --- a/apps/web/lib/apiKeys.ts +++ b/apps/web/lib/apiKeys.ts @@ -12,29 +12,6 @@ export const useApiKeys = (environmentId: string) => { }; }; -export const useApiKey = (environmentId: string, id: string) => { - const { data, error, mutate } = useSWR(`/api/v1/environments/${environmentId}/api-keys/${id}`, fetcher); - - return { - apiKey: data, - isLoadingApiKey: !error && !data, - isErrorApiKey: error, - mutateApiKey: mutate, - }; -}; - -export const persistApiKey = async (environmentId: string, apiKey) => { - try { - await fetch(`/api/v1/environments/${environmentId}/api-keys/${apiKey.id}`, { - method: "POST", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify(apiKey), - }); - } catch (error) { - console.error(error); - } -}; - export const createApiKey = async (environmentId: string, apiKey = {}) => { try { const res = await fetch(`/api/v1/environments/${environmentId}/api-keys`, { diff --git a/apps/web/lib/auth.ts b/apps/web/lib/auth.ts index e0560ed9a4..976b6c32ce 100644 --- a/apps/web/lib/auth.ts +++ b/apps/web/lib/auth.ts @@ -9,20 +9,3 @@ export async function verifyPassword(password: string, hashedPassword: string) { const isValid = await compare(password, hashedPassword); return isValid; } -export function requireAuthentication(gssp: any) { - return async (context: any) => { - const { req, resolvedUrl } = context; - const token = req.cookies.userToken; - - if (!token) { - return { - redirect: { - destination: `/auth/login?callbackUrl=${encodeURIComponent(resolvedUrl)}`, - statusCode: 302, - }, - }; - } - - return await gssp(context); // Continue on to call `getServerSideProps` logic - }; -} diff --git a/apps/web/lib/email.ts b/apps/web/lib/email.ts index a08164e7d9..b7598c5079 100644 --- a/apps/web/lib/email.ts +++ b/apps/web/lib/email.ts @@ -16,7 +16,7 @@ interface sendEmailData { html: string; } -export const sendEmail = async (emailData: sendEmailData) => { +const sendEmail = async (emailData: sendEmailData) => { let transporter = nodemailer.createTransport({ host: process.env.SMTP_HOST, port: process.env.SMTP_PORT, diff --git a/apps/web/lib/utils.ts b/apps/web/lib/utils.ts index 941ba55e4b..b4033a8b5c 100644 --- a/apps/web/lib/utils.ts +++ b/apps/web/lib/utils.ts @@ -1,18 +1,7 @@ -import platform from "platform"; - export function capitalizeFirstLetter(string = "") { return string.charAt(0).toUpperCase() + string.slice(1); } -export const onlyUnique = (value, index, self) => { - return self.indexOf(value) === index; -}; - -export const parseUserAgent = (userAgent: string) => { - const info = platform.parse(userAgent); - return info.description; -}; - // write a function that takes a string and truncates it to the specified length export const truncate = (str: string, length: number) => { if (!str) return ""; @@ -53,12 +42,3 @@ export function isLight(color) { } return r * 0.299 + g * 0.587 + b * 0.114 > 128; } - -export const toJson = (obj: any): Object | null => { - try { - return JSON.parse(JSON.stringify(obj)); - } catch (error) { - console.error(error); - return null; - } -}; diff --git a/apps/web/package.json b/apps/web/package.json index 5d55aec39e..7731dc277e 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -15,31 +15,22 @@ "@formbricks/js": "workspace:*", "@formbricks/lib": "workspace:*", "@formbricks/ui": "workspace:*", + "@headlessui/react": "^1.7.15", "@heroicons/react": "^2.0.18", "@json2csv/node": "^7.0.1", "@paralleldrive/cuid2": "^2.2.0", "@radix-ui/react-collapsible": "^1.0.2", "@radix-ui/react-dropdown-menu": "^2.0.4", - "@types/node": "20.2.3", - "@types/react": "18.2.7", - "@types/react-dom": "18.2.4", "bcryptjs": "^2.4.3", - "class-variance-authority": "^0.6.0", - "date-fns": "^2.30.0", "dotenv-webpack": "^8.0.1", - "eslint": "8.41.0", "eslint-config-next": "^13.4.3", "jsonwebtoken": "^9.0.0", "lodash": "^4.17.21", "lucide-react": "^0.221.0", - "markdown-it": "^13.0.1", "next": "13.4.3", "next-auth": "^4.22.1", "nodemailer": "^6.9.2", - "platform": "^1.3.6", "posthog-js": "^1.57.3", - "posthog-node": "^3.1.1", - "preact": "10.15.0", "prismjs": "^1.29.0", "react": "18.2.0", "react-beautiful-dnd": "^13.1.1", @@ -47,10 +38,7 @@ "react-hook-form": "^7.43.9", "react-hot-toast": "^2.4.1", "react-icons": "^4.8.0", - "react-use": "^17.4.0", - "stripe": "^12.6.0", "swr": "^2.1.5", - "typescript": "5.0.4", "ua-parser-js": "^1.0.35", "zod": "^3.21.4" }, @@ -63,12 +51,14 @@ "@types/bcryptjs": "^2.4.2", "@types/lodash": "^4.14.195", "@types/markdown-it": "^12.2.3", + "@types/node": "20.2.3", + "@types/react": "18.2.7", + "@types/react-dom": "18.2.4", "autoprefixer": "^10.4.14", "eslint-config-formbricks": "workspace:*", "postcss": "^8.4.23", "rimraf": "^5.0.1", - "tailwind-merge": "^1.12.0", "tailwindcss": "^3.3.2", - "tailwindcss-animate": "^1.0.5" + "typescript": "5.0.4" } } diff --git a/apps/web/pages/api/capture/forms/[formId]/schema/index.ts b/apps/web/pages/api/capture/forms/[formId]/schema/index.ts deleted file mode 100644 index dfaf4192af..0000000000 --- a/apps/web/pages/api/capture/forms/[formId]/schema/index.ts +++ /dev/null @@ -1,39 +0,0 @@ -import type { NextApiRequest, NextApiResponse } from "next"; - -export default async function handle(req: NextApiRequest, res: NextApiResponse) { - const formId = req.query.formId?.toString(); - - // CORS - if (req.method === "OPTIONS") { - res.status(200).end(); - } - - // POST/capture/forms/[formId]/schema - // Update form schema - // Required fields in body: - - // Optional fields in body: customerId, data - else if (req.method === "POST") { - if (process.env.FORMBRICKS_LEGACY_HOST) { - const response = await fetch( - `${process.env.FORMBRICKS_LEGACY_HOST}/api/capture/forms/${formId}/schema`, - { - method: "POST", - headers: { - "Content-Type": "application/json", - Authorization: `Bearer ${process.env.FORMBRICKS_LEGACY_HOST}`, - }, - body: JSON.stringify(req.body), - } - ); - const responseData = await response.json(); - res.json(responseData); - } else { - throw new Error(`The HTTP ${req.method} method is not supported by this route.`); - } - } - - // Unknown HTTP Method - else { - throw new Error(`The HTTP ${req.method} method is not supported by this route.`); - } -} diff --git a/apps/web/pages/api/capture/forms/[formId]/submissions/[submissionId]/index.ts b/apps/web/pages/api/capture/forms/[formId]/submissions/[submissionId]/index.ts deleted file mode 100644 index e545977740..0000000000 --- a/apps/web/pages/api/capture/forms/[formId]/submissions/[submissionId]/index.ts +++ /dev/null @@ -1,41 +0,0 @@ -import type { NextApiRequest, NextApiResponse } from "next"; - -export default async function handle(req: NextApiRequest, res: NextApiResponse) { - const formId = req.query.formId?.toString(); - const submissionId = req.query.submissionId?.toString(); - - // CORS - if (req.method === "OPTIONS") { - res.status(200).end(); - } - - // PUT /capture/forms/[formId]/submissions/[submissionId] - // Extend an existing form submission - // Required fields in body: - - // Optional fields in body: customerId, data - else if (req.method === "PUT") { - // redirect request and make a request to legacy.formbricks.com - if (process.env.FORMBRICKS_LEGACY_HOST) { - const response = await fetch( - `${process.env.FORMBRICKS_LEGACY_HOST}/api/capture/forms/${formId}/submissions/${submissionId}`, - { - method: "PUT", - headers: { - "Content-Type": "application/json", - Authorization: `Bearer ${process.env.FORMBRICKS_LEGACY_HOST}`, - }, - body: JSON.stringify(req.body), - } - ); - const responseData = await response.json(); - res.json(responseData); - } else { - throw new Error(`The HTTP ${req.method} method is not supported by this route.`); - } - } - - // Unknown HTTP Method - else { - throw new Error(`The HTTP ${req.method} method is not supported by this route.`); - } -} diff --git a/apps/web/pages/api/capture/forms/[formId]/submissions/index.ts b/apps/web/pages/api/capture/forms/[formId]/submissions/index.ts deleted file mode 100644 index 8158a39d2d..0000000000 --- a/apps/web/pages/api/capture/forms/[formId]/submissions/index.ts +++ /dev/null @@ -1,39 +0,0 @@ -import type { NextApiRequest, NextApiResponse } from "next"; - -export default async function handle(req: NextApiRequest, res: NextApiResponse) { - const formId = req.query.formId?.toString(); - - // CORS - if (req.method === "OPTIONS") { - res.status(200).end(); - } - - // POST/capture/forms/[formId]/submissions - // Create a new form submission - // Required fields in body: - - // Optional fields in body: customerId, data - else if (req.method === "POST") { - if (process.env.FORMBRICKS_LEGACY_HOST) { - const response = await fetch( - `${process.env.FORMBRICKS_LEGACY_HOST}/api/capture/forms/${formId}/submissions`, - { - method: "POST", - headers: { - "Content-Type": "application/json", - Authorization: `Bearer ${process.env.FORMBRICKS_LEGACY_HOST}`, - }, - body: JSON.stringify(req.body), - } - ); - const responseData = await response.json(); - res.json(responseData); - } else { - throw new Error(`The HTTP ${req.method} method is not supported by this route.`); - } - } - - // Unknown HTTP Method - else { - throw new Error(`The HTTP ${req.method} method is not supported by this route.`); - } -} diff --git a/apps/web/pages/api/v1/environments/[environmentId]/posthog/export/index.ts b/apps/web/pages/api/v1/environments/[environmentId]/posthog/export/index.ts deleted file mode 100644 index 099220241c..0000000000 --- a/apps/web/pages/api/v1/environments/[environmentId]/posthog/export/index.ts +++ /dev/null @@ -1,119 +0,0 @@ -import { 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 environmentId = req.query?.environmentId?.toString(); - - if (!environmentId) { - return res.status(400).json({ message: "Missing environmentId" }); - } - - const hasAccess = await hasEnvironmentAccess(req, res, environmentId); - if (!hasAccess) { - return res.status(403).json({ message: "Not authorized" }); - } - - // POST - if (req.method === "POST") { - // lastSyncedAt is the last time the environment was synced (iso string) - const { lastSyncedAt } = req.body; - - let lastSyncedCondition = lastSyncedAt - ? { - OR: [ - { - createdAt: { - gt: lastSyncedAt, - }, - }, - { - updatedAt: { - gt: lastSyncedAt, - }, - }, - ], - } - : {}; - - // Get all displays that have been created or updated since lastSyncedAt - const displays = await prisma.display.findMany({ - where: { - survey: { - environmentId, - }, - ...lastSyncedCondition, - }, - select: { - id: true, - createdAt: true, - updatedAt: true, - person: { - select: { - attributes: { - select: { - id: true, - value: true, - attributeClass: { - select: { - name: true, - }, - }, - }, - }, - }, - }, - }, - }); - - // Get all responses that have been created or updated since lastSyncedAt - const responses = await prisma.response.findMany({ - where: { - survey: { - environmentId, - }, - ...lastSyncedCondition, - }, - select: { - id: true, - createdAt: true, - updatedAt: true, - person: { - select: { - attributes: { - select: { - id: true, - value: true, - attributeClass: { - select: { - name: true, - }, - }, - }, - }, - }, - }, - }, - }); - - const events = [ - ...displays.map((display) => ({ - name: "formbricks_survey_displayed", - timestamp: display.createdAt, - userId: display.person?.attributes?.find((attr) => attr.attributeClass.name === "userId")?.value, - })), - ...responses.map((response) => ({ - name: "formbricks_response_created", - timestamp: response.createdAt, - userId: response.person?.attributes?.find((attr) => attr.attributeClass.name === "userId")?.value, - })), - ]; - - return res.json({ events, lastSyncedAt: new Date().toISOString() }); - } - - // Unknown HTTP Method - else { - throw new Error(`The HTTP ${req.method} method is not supported by this route.`); - } -} diff --git a/apps/web/pages/api/v1/environments/[environmentId]/posthog/import/index.ts b/apps/web/pages/api/v1/environments/[environmentId]/posthog/import/index.ts deleted file mode 100644 index d1022faf4b..0000000000 --- a/apps/web/pages/api/v1/environments/[environmentId]/posthog/import/index.ts +++ /dev/null @@ -1,121 +0,0 @@ -import { hasEnvironmentAccess } from "@/lib/api/apiHelper"; -import { prisma } from "@formbricks/database"; -import type { NextApiRequest, NextApiResponse } from "next"; - -interface FormbricksUser { - userId: string; - attributes: { [key: string]: string }; -} - -export default async function handle(req: NextApiRequest, res: NextApiResponse) { - const environmentId = req.query?.environmentId?.toString(); - - if (!environmentId) { - return res.status(400).json({ message: "Missing environmentId" }); - } - - const hasAccess = await hasEnvironmentAccess(req, res, environmentId); - if (!hasAccess) { - return res.status(403).json({ message: "Not authorized" }); - } - - // POST - if (req.method === "POST") { - // lastSyncedAt is the last time the environment was synced (iso string) - const { users }: { users: FormbricksUser[] } = req.body; - - for (const user of users) { - // check if user with this userId as attribute already exists - const existingUser = await prisma.person.findFirst({ - where: { - attributes: { - some: { - attributeClass: { - name: "userId", - environmentId, - }, - value: user.userId, - }, - }, - }, - select: { - id: true, - attributes: { - select: { - id: true, - value: true, - attributeClass: { - select: { - name: true, - }, - }, - }, - }, - }, - }); - - if (existingUser) { - // user already exists, loop through attributes and update or create them - const attributeType: "noCode" = "noCode"; - for (const key of Object.keys(user.attributes)) { - const existingAttribute = existingUser.attributes.find( - (attribute) => attribute.attributeClass.name === key - ); - if (existingAttribute) { - // skip if value is the same - if (existingAttribute.value === user.attributes[key]) { - continue; - } - await prisma.attribute.update({ - where: { - id: existingAttribute.id, - }, - data: { - value: user.attributes[key].toString(), - }, - }); - } else { - // create attribute - await prisma.attribute.create({ - data: { - value: user.attributes[key], - attributeClass: { - connectOrCreate: { - where: { - name_environmentId: { - name: key, - environmentId, - }, - }, - create: { - name: key, - description: "Created by Posthog Import", - type: attributeType, - environment: { - connect: { - id: environmentId, - }, - }, - }, - }, - }, - person: { - connect: { - id: existingUser.id, - }, - }, - }, - }); - } - } - } - } - - return res.status(200).end(); - } - - // Unknown HTTP Method - else { - throw new Error(`The HTTP ${req.method} method is not supported by this route.`); - } -} diff --git a/docker-compose.yml b/docker-compose.yml index b7f0a15512..9c21120984 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,7 +1,7 @@ version: "3.3" services: postgres: - restart: unless-stopped + restart: always image: postgres:15-alpine volumes: - postgres:/var/lib/postgresql/data @@ -9,7 +9,7 @@ services: - POSTGRES_PASSWORD=postgres formbricks: - restart: unless-stopped + restart: always build: context: . dockerfile: ./apps/web/Dockerfile diff --git a/packages/api/tsconfig.json b/packages/api/tsconfig.json index 431acb1f6a..cfb861011c 100644 --- a/packages/api/tsconfig.json +++ b/packages/api/tsconfig.json @@ -1,5 +1,5 @@ { "extends": "@formbricks/tsconfig/js-library.json", "include": ["**/*.ts", "tsup.config.ts"], - "exclude": ["node_modules"] + "exclude": ["node_modules", "dist"] } diff --git a/packages/database/package.json b/packages/database/package.json index e0bcb2267a..b898ec1e09 100644 --- a/packages/database/package.json +++ b/packages/database/package.json @@ -24,21 +24,21 @@ "studio": "prisma studio" }, "dependencies": { - "@formbricks/types": "workspace:*", - "@prisma/client": "^4.15.0", - "prisma-json-types-generator": "^2.4.0", + "@prisma/client": "^4.16.1", + "prisma-json-types-generator": "^2.5.0", "zod": "^3.21.4", "zod-prisma": "^0.5.4" }, "devDependencies": { "@formbricks/tsconfig": "workspace:*", - "eslint": "^8.41.0", + "@formbricks/types": "workspace:*", + "eslint": "^8.43.0", "eslint-config-formbricks": "workspace:*", - "prisma": "^4.15.0", + "prisma": "^4.16.1", "prisma-dbml-generator": "^0.10.0", "rimraf": "^5.0.1", - "tsup": "^6.7.0", + "tsup": "^7.1.0", "tsx": "^3.12.7", - "typescript": "^5.0.4" + "typescript": "^5.1.3" } } diff --git a/packages/database/schema.prisma b/packages/database/schema.prisma index 7dbcd3a2ce..732d78618d 100644 --- a/packages/database/schema.prisma +++ b/packages/database/schema.prisma @@ -8,7 +8,7 @@ datasource db { generator client { provider = "prisma-client-js" - previewFeatures = ["filteredRelationCount", "extendedWhereUnique"] + previewFeatures = ["extendedWhereUnique"] //provider = "prisma-dbml-generator" } diff --git a/packages/database/tsconfig.json b/packages/database/tsconfig.json index 9d6a826d01..eb408c5485 100644 --- a/packages/database/tsconfig.json +++ b/packages/database/tsconfig.json @@ -1,5 +1,5 @@ { "extends": "@formbricks/tsconfig/node16.json", "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", "tsup.config.ts"], - "exclude": ["node_modules"] + "exclude": ["node_modules", "dist", "zod"] } diff --git a/packages/ee/package.json b/packages/ee/package.json index 421d943b1d..7476c532e5 100644 --- a/packages/ee/package.json +++ b/packages/ee/package.json @@ -19,6 +19,7 @@ }, "dependencies": { "@formbricks/database": "workspace:*", - "next": "^13.4.4" + "next": "^13.4.4", + "stripe": "^12.6.0" } } diff --git a/packages/errors/LICENSE b/packages/errors/LICENSE new file mode 100644 index 0000000000..ade6b17980 --- /dev/null +++ b/packages/errors/LICENSE @@ -0,0 +1,9 @@ +MIT License + +Copyright (c) 2023 Matthias Nannt, Johannes Dancker + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/packages/errors/package.json b/packages/errors/package.json index 38a62238ce..7d6d46d19c 100644 --- a/packages/errors/package.json +++ b/packages/errors/package.json @@ -1,8 +1,8 @@ { "name": "@formbricks/errors", + "license": "MIT", "description": "A helper package containing general error classes for Formbricks", - "private": true, - "version": "1.0.0", + "version": "0.1.0", "main": "./dist/index.js", "module": "./dist/index.mjs", "types": "./dist/index.d.ts", @@ -15,8 +15,8 @@ "dev": "tsup --watch", "lint": "eslint ./src --fix", "clean": "rimraf .turbo node_modules dist" - }, - "devDependencies": { + }, + "devDependencies": { "@formbricks/tsconfig": "workspace:*", "eslint": "^8.41.0", "eslint-config-formbricks": "workspace:*", diff --git a/packages/errors/tsconfig.json b/packages/errors/tsconfig.json index 68efa55c17..ca019c54f7 100644 --- a/packages/errors/tsconfig.json +++ b/packages/errors/tsconfig.json @@ -1,5 +1,5 @@ { "extends": "@formbricks/tsconfig/node16.json", "include": ["**/*.ts", "tsup.config.ts"], - "exclude": ["node_modules"] + "exclude": ["node_modules", "dist"] } diff --git a/packages/js/package.json b/packages/js/package.json index 6c88fca444..1d5c433c91 100644 --- a/packages/js/package.json +++ b/packages/js/package.json @@ -23,7 +23,7 @@ }, "scripts": { "clean": "rimraf .turbo node_modules dist", - "dev": "microbundle --css inline", + "dev": "microbundle --css inline --watch", "lint": "eslint '{src,tests}/**/*.{ts,tsx}'", "test": "jest", "build": "microbundle --css inline" diff --git a/packages/js/tsconfig.json b/packages/js/tsconfig.json index e1026db534..b88de68d4e 100644 --- a/packages/js/tsconfig.json +++ b/packages/js/tsconfig.json @@ -58,5 +58,6 @@ "references": [ { "path": "../../../types/tsconfig.json" } // Add this line, adjust the path to the actual location ], - "include": ["src", "../types", "../lib/client"] + "include": ["src", "../types", "../lib/client"], + "exclude": ["node_modules", "dist", "coverage"] } diff --git a/packages/lib/package.json b/packages/lib/package.json index 4a5deb0f1c..0c5aafba78 100644 --- a/packages/lib/package.json +++ b/packages/lib/package.json @@ -14,7 +14,11 @@ "dependencies": { "@formbricks/database": "*", "@formbricks/types": "*", - "@formbricks/errors": "*" + "@formbricks/errors": "*", + "date-fns": "^2.30.0", + "markdown-it": "^13.0.1", + "posthog-node": "^3.1.1", + "tailwind-merge": "^1.12.0" }, "devDependencies": { "@formbricks/tsconfig": "*", diff --git a/packages/ui/components/PasswordInput.tsx b/packages/ui/components/PasswordInput.tsx index d5143acf90..853d1fae59 100644 --- a/packages/ui/components/PasswordInput.tsx +++ b/packages/ui/components/PasswordInput.tsx @@ -25,9 +25,8 @@ const PasswordInput = ({ className, ...rest }: PasswordInputProps) => { />