From af181eabdc45db17402204ab6052d45448fc6b5e Mon Sep 17 00:00:00 2001 From: Shubham Palriwala Date: Mon, 20 Nov 2023 21:46:39 +0530 Subject: [PATCH] feat: formbricks/api package as per js package 1.2.2 (#1640) Co-authored-by: Matthias Nannt --- apps/demo/pages/signin/index.tsx | 152 ---------------- apps/demo/pages/test-nocode-app/index.tsx | 202 ---------------------- packages/api/package.json | 2 +- packages/api/src/api/client/action.ts | 18 ++ packages/api/src/api/client/index.ts | 6 + packages/api/src/api/client/people.ts | 33 ++++ packages/js/src/lib/actions.ts | 24 +-- packages/js/src/lib/person.ts | 45 ++--- 8 files changed, 85 insertions(+), 397 deletions(-) delete mode 100644 apps/demo/pages/signin/index.tsx delete mode 100644 apps/demo/pages/test-nocode-app/index.tsx create mode 100644 packages/api/src/api/client/action.ts create mode 100644 packages/api/src/api/client/people.ts diff --git a/apps/demo/pages/signin/index.tsx b/apps/demo/pages/signin/index.tsx deleted file mode 100644 index b8b2d06665..0000000000 --- a/apps/demo/pages/signin/index.tsx +++ /dev/null @@ -1,152 +0,0 @@ -import formbricks from "@formbricks/js"; -import { useRouter } from "next/router"; -import { FormEvent } from "react"; - -export default function SiginPage() { - const router = useRouter(); - - const submitAction = (e: FormEvent) => { - e.preventDefault(); - if (process.env.NEXT_PUBLIC_FORMBRICKS_ENVIRONMENT_ID && process.env.NEXT_PUBLIC_FORMBRICKS_API_HOST) { - formbricks.setEmail("matti@example.com"); - formbricks.setUserId("123456"); - formbricks.setAttribute("Plan", "Premium"); - } - router.push("/app"); - }; - return ( -
-
-

- Sign in to your account -

-

- Or{" "} - - start your 14-day free trial - -

-
- -
-
-
-
- -
- -
-
- -
- -
- -
-
- -
-
- - -
- - -
- -
- -
-
- - -
-
- ); -} diff --git a/apps/demo/pages/test-nocode-app/index.tsx b/apps/demo/pages/test-nocode-app/index.tsx deleted file mode 100644 index c5d29f2244..0000000000 --- a/apps/demo/pages/test-nocode-app/index.tsx +++ /dev/null @@ -1,202 +0,0 @@ -import formbricks from "@formbricks/js"; -import Image from "next/image"; -import { useEffect, useState } from "react"; -import fbsetup from "../../public/fb-setup.png"; - -export default function AppPage({}) { - const [darkMode, setDarkMode] = useState(false); - - useEffect(() => { - if (darkMode) { - document.body.classList.add("dark"); - } else { - document.body.classList.remove("dark"); - } - }, [darkMode]); - - return ( -
-
-
-

- Formbricks In-product Survey Demo App -

-

- This app helps you test your in-app surveys. You can create and test user actions, create and - update user attributes, etc. -

-
- -
- -
-
-
-

1. Setup .env

-

- Copy the environment ID of your Formbricks app to the env variable in demo/.env -

- fb setup - -
-

You're connected with env:

-
- - {process.env.NEXT_PUBLIC_FORMBRICKS_ENVIRONMENT_ID} - - - - - -
-
-
-
-

2. Widget Logs

-

- Look at the logs to understand how the widget works.{" "} - Open your browser console to see the logs. -

- {/*
- -
*/} -
-
- -
-
-

- Reset person / pull data from Formbricks app -

-

- On formbricks.reset() a few things happen: New person is created and{" "} - surveys & no-code actions are pulled from Formbricks:. -

- -

- If you made a change in Formbricks app and it does not seem to work, hit 'Reset' and - try again. -

-
-
-
- -
-
-

Inner Text only

-
-
- -
-
- -
-
-

Inner Text + Css ID

-
-
- -
-
- -
-
-

Inner Text + CSS Class

-
-
- -
-
- -
-
-

ID + Class

-
-
- -
-
- -
-
-

ID only

-
-
- -
-
- -
-
-

Class only

-
-
- -
-
- -
-
-

Class + Class

-
-
-
-
-
- ); -} diff --git a/packages/api/package.json b/packages/api/package.json index 1daf6f89ec..5bcc234cce 100644 --- a/packages/api/package.json +++ b/packages/api/package.json @@ -1,7 +1,7 @@ { "name": "@formbricks/api", "license": "MIT", - "version": "1.0.0", + "version": "1.1.0", "description": "Formbricks-api is an api wrapper for the Formbricks client API", "keywords": [ "Formbricks", diff --git a/packages/api/src/api/client/action.ts b/packages/api/src/api/client/action.ts new file mode 100644 index 0000000000..ccd1aa0e75 --- /dev/null +++ b/packages/api/src/api/client/action.ts @@ -0,0 +1,18 @@ +import { Result } from "@formbricks/types/errorHandlers"; +import { NetworkError } from "@formbricks/types/errors"; +import { TActionInput } from "@formbricks/types/actions"; +import { makeRequest } from "../../utils/makeRequest"; + +export class ActionAPI { + private apiHost: string; + private environmentId: string; + + constructor(apiHost: string, environmentId: string) { + this.apiHost = apiHost; + this.environmentId = environmentId; + } + + async create(actionInput: Omit): Promise> { + return makeRequest(this.apiHost, `/api/v1/client/${this.environmentId}/actions`, "POST", actionInput); + } +} diff --git a/packages/api/src/api/client/index.ts b/packages/api/src/api/client/index.ts index f51842f98d..79fa336355 100644 --- a/packages/api/src/api/client/index.ts +++ b/packages/api/src/api/client/index.ts @@ -1,15 +1,21 @@ import { ResponseAPI } from "./response"; import { DisplayAPI } from "./display"; import { ApiConfig } from "../../types"; +import { ActionAPI } from "./action"; +import { PeopleAPI } from "./people"; export class Client { response: ResponseAPI; display: DisplayAPI; + action: ActionAPI; + people: PeopleAPI; constructor(options: ApiConfig) { const { apiHost, environmentId } = options; this.response = new ResponseAPI(apiHost, environmentId); this.display = new DisplayAPI(apiHost, environmentId); + this.action = new ActionAPI(apiHost, environmentId); + this.people = new PeopleAPI(apiHost, environmentId); } } diff --git a/packages/api/src/api/client/people.ts b/packages/api/src/api/client/people.ts new file mode 100644 index 0000000000..1d850a8b6c --- /dev/null +++ b/packages/api/src/api/client/people.ts @@ -0,0 +1,33 @@ +import { Result } from "@formbricks/types/errorHandlers"; +import { NetworkError } from "@formbricks/types/errors"; +import { makeRequest } from "../../utils/makeRequest"; +import { TPerson, TPersonUpdateInput } from "@formbricks/types/people"; + +export class PeopleAPI { + private apiHost: string; + private environmentId: string; + + constructor(apiHost: string, environmentId: string) { + this.apiHost = apiHost; + this.environmentId = environmentId; + } + + async create(userId: string): Promise> { + return makeRequest(this.apiHost, `/api/v1/client/${this.environmentId}/people`, "POST", { + environmentId: this.environmentId, + userId, + }); + } + + async update( + userId: string, + personInput: TPersonUpdateInput + ): Promise> { + return makeRequest( + this.apiHost, + `/api/v1/client/${this.environmentId}/people/${userId}`, + "POST", + personInput + ); + } +} diff --git a/packages/js/src/lib/actions.ts b/packages/js/src/lib/actions.ts index d5cab20cd0..41267077e3 100644 --- a/packages/js/src/lib/actions.ts +++ b/packages/js/src/lib/actions.ts @@ -4,6 +4,7 @@ import { Config } from "./config"; import { NetworkError, Result, err, okVoid } from "./errors"; import { Logger } from "./logger"; import { renderWidget } from "./widget"; +import { FormbricksAPI } from "@formbricks/api"; const logger = Logger.getInstance(); const config = Config.getInstance(); @@ -23,24 +24,23 @@ export const trackAction = async ( // don't send actions to the backend if the person is not identified if (config.get().state?.person?.userId && !intentsToNotCreateOnApp.includes(name)) { logger.debug(`Sending action "${name}" to backend`); - const res = await fetch(`${config.get().apiHost}/api/v1/client/${config.get().environmentId}/actions`, { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify(input), + const api = new FormbricksAPI({ + apiHost: config.get().apiHost, + environmentId: config.get().environmentId, + }); + const res = await api.client.action.create({ + ...input, + userId: config.get().state.person!.userId, }); if (!res.ok) { - const error = await res.json(); - return err({ code: "network_error", - message: `Error tracking action: ${JSON.stringify(error)}`, - status: res.status, - url: res.url, - responseMessage: error.message, + message: `Error tracking action ${name}`, + status: 500, + url: `${config.get().apiHost}/api/v1/client/${config.get().environmentId}/actions`, + responseMessage: res.error.message, }); } } diff --git a/packages/js/src/lib/person.ts b/packages/js/src/lib/person.ts index 531d8aed3f..c12053d1d0 100644 --- a/packages/js/src/lib/person.ts +++ b/packages/js/src/lib/person.ts @@ -1,18 +1,10 @@ -import { TJsState } from "@formbricks/types/js"; import { TPerson, TPersonUpdateInput } from "@formbricks/types/people"; import { Config } from "./config"; -import { - AttributeAlreadyExistsError, - MissingPersonError, - NetworkError, - Result, - err, - ok, - okVoid, -} from "./errors"; +import { AttributeAlreadyExistsError, MissingPersonError, NetworkError, Result, err, okVoid } from "./errors"; import { deinitalize, initialize } from "./initialize"; import { Logger } from "./logger"; import { sync } from "./sync"; +import { FormbricksAPI } from "@formbricks/api"; const config = Config.getInstance(); const logger = Logger.getInstance(); @@ -20,7 +12,7 @@ const logger = Logger.getInstance(); export const updatePersonAttribute = async ( key: string, value: string -): Promise> => { +): Promise> => { if (!config.get().state.person || !config.get().state.person?.id) { return err({ code: "missing_person", @@ -34,28 +26,21 @@ export const updatePersonAttribute = async ( }, }; - const res = await fetch( - `${config.get().apiHost}/api/v1/client/${config.get().environmentId}/people/${ - config.get().state.person?.userId - }`, - { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify(input), - } - ); - - const resJson = await res.json(); + const api = new FormbricksAPI({ + apiHost: config.get().apiHost, + environmentId: config.get().environmentId, + }); + const res = await api.client.people.update(config.get().state.person!.userId, input); if (!res.ok) { return err({ code: "network_error", - status: res.status, - message: "Error updating person", - url: res.url, - responseMessage: resJson.message, + status: 500, + message: `Error updating person with userId ${config.get().state.person?.userId}`, + url: `${config.get().apiHost}/api/v1/client/${config.get().environmentId}/people/${ + config.get().state.person?.userId + }`, + responseMessage: res.error.message, }); } @@ -67,7 +52,7 @@ export const updatePersonAttribute = async ( userId: config.get().state.person?.userId, }); - return ok(resJson.data as TJsState); + return okVoid(); }; export const hasAttributeValue = (key: string, value: string): boolean => {