From 56d1f94b6219e160b86a565a8b84e0af2daf6fc6 Mon Sep 17 00:00:00 2001 From: Matthieu Jacq <67386567+matthieujacq@users.noreply.github.com> Date: Tue, 24 Oct 2023 18:26:48 +0200 Subject: [PATCH] feat: upgrade to plus button (#1482) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit # Description Epic: #1429 User Story: #1430 ## Pour la mise en preview / prod: - Mettre à jour l'environnement ```env NEXT_PUBLIC_STRIPE_PRICING_TABLE_ID= NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY= ``` - Activer le feature flag `monetization` (booléen) ## Screenshots (if appropriate): Button: image Modal: image --- .frontend_env.example | 5 ++- .../components/BrainsList/BrainsList.tsx | 2 +- .../app/chat/components/ChatsList/index.tsx | 2 +- .../SidebarFooter/SidebarFooter.tsx | 12 ++++--- .../components/UpgradeToPlus.tsx | 35 +++++++++++++++++++ .../PricingModal/StripePricingModal.tsx | 16 +++++++++ .../components/PricingTable/PricingTable.tsx | 14 ++++++++ .../components/PricingTable/Types/types.d.ts | 12 +++++++ frontend/lib/components/Stripe/index.ts | 1 + frontend/lib/config/LocaleConfig/resources.ts | 13 +++++++ frontend/next.config.js | 9 ++++- frontend/public/locales/en/monetization.json | 4 +++ frontend/public/locales/es/monetization.json | 4 +++ frontend/public/locales/fr/monetization.json | 4 +++ .../public/locales/pt-br/monetization.json | 4 +++ frontend/public/locales/ru/monetization.json | 4 +++ .../public/locales/zh-cn/monetization.json | 4 +++ 17 files changed, 137 insertions(+), 8 deletions(-) create mode 100644 frontend/lib/components/Sidebar/components/SidebarFooter/components/UpgradeToPlus.tsx create mode 100644 frontend/lib/components/Stripe/PricingModal/StripePricingModal.tsx create mode 100644 frontend/lib/components/Stripe/PricingModal/components/PricingTable/PricingTable.tsx create mode 100644 frontend/lib/components/Stripe/PricingModal/components/PricingTable/Types/types.d.ts create mode 100644 frontend/lib/components/Stripe/index.ts create mode 100644 frontend/public/locales/en/monetization.json create mode 100644 frontend/public/locales/es/monetization.json create mode 100644 frontend/public/locales/fr/monetization.json create mode 100644 frontend/public/locales/pt-br/monetization.json create mode 100644 frontend/public/locales/ru/monetization.json create mode 100644 frontend/public/locales/zh-cn/monetization.json diff --git a/.frontend_env.example b/.frontend_env.example index 388686807..3214aedc4 100644 --- a/.frontend_env.example +++ b/.frontend_env.example @@ -14,4 +14,7 @@ NEXT_PUBLIC_E2E_URL=http://localhost:3003 NEXT_PUBLIC_E2E_EMAIL= NEXT_PUBLIC_E2E_PASSWORD= -NEXT_PUBLIC_CMS_URL=https://cms.quivr.app \ No newline at end of file +NEXT_PUBLIC_CMS_URL=https://cms.quivr.app + +NEXT_PUBLIC_STRIPE_PRICING_TABLE_ID= +NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY= diff --git a/frontend/app/brains-management/[brainId]/components/BrainsList/BrainsList.tsx b/frontend/app/brains-management/[brainId]/components/BrainsList/BrainsList.tsx index 797f51994..629df1fb7 100644 --- a/frontend/app/brains-management/[brainId]/components/BrainsList/BrainsList.tsx +++ b/frontend/app/brains-management/[brainId]/components/BrainsList/BrainsList.tsx @@ -17,7 +17,7 @@ export const BrainsList = (): JSX.Element => { const { t } = useTranslation(["brain", "chat"]); return ( - +
+ } + /> + ); +}; diff --git a/frontend/lib/components/Stripe/PricingModal/StripePricingModal.tsx b/frontend/lib/components/Stripe/PricingModal/StripePricingModal.tsx new file mode 100644 index 000000000..003d5c6bb --- /dev/null +++ b/frontend/lib/components/Stripe/PricingModal/StripePricingModal.tsx @@ -0,0 +1,16 @@ +import { StripePricingTable } from "./components/PricingTable/PricingTable"; +import { Modal } from "../../ui/Modal"; + +type StripePricingModalProps = { + Trigger: JSX.Element; +}; + +export const StripePricingModal = ({ + Trigger, +}: StripePricingModalProps): JSX.Element => { + return ( + }> + + + ); +}; diff --git a/frontend/lib/components/Stripe/PricingModal/components/PricingTable/PricingTable.tsx b/frontend/lib/components/Stripe/PricingModal/components/PricingTable/PricingTable.tsx new file mode 100644 index 000000000..5c8abbc83 --- /dev/null +++ b/frontend/lib/components/Stripe/PricingModal/components/PricingTable/PricingTable.tsx @@ -0,0 +1,14 @@ +const PRICING_TABLE_ID = process.env.NEXT_PUBLIC_STRIPE_PRICING_TABLE_ID; +const PUBLISHABLE_KEY = process.env.NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY; + +export const StripePricingTable = (): JSX.Element => { + return ( + <> + + + + ); +}; diff --git a/frontend/lib/components/Stripe/PricingModal/components/PricingTable/Types/types.d.ts b/frontend/lib/components/Stripe/PricingModal/components/PricingTable/Types/types.d.ts new file mode 100644 index 000000000..4da4688a0 --- /dev/null +++ b/frontend/lib/components/Stripe/PricingModal/components/PricingTable/Types/types.d.ts @@ -0,0 +1,12 @@ +import * as React from "react"; + +declare global { + namespace JSX { + interface IntrinsicElements { + "stripe-pricing-table": React.DetailedHTMLProps< + React.HTMLAttributes, + HTMLElement + >; + } + } +} diff --git a/frontend/lib/components/Stripe/index.ts b/frontend/lib/components/Stripe/index.ts new file mode 100644 index 000000000..3c8adb1df --- /dev/null +++ b/frontend/lib/components/Stripe/index.ts @@ -0,0 +1 @@ +export * from "./PricingModal/StripePricingModal"; diff --git a/frontend/lib/config/LocaleConfig/resources.ts b/frontend/lib/config/LocaleConfig/resources.ts index ca28da36f..0a6040c48 100644 --- a/frontend/lib/config/LocaleConfig/resources.ts +++ b/frontend/lib/config/LocaleConfig/resources.ts @@ -11,6 +11,7 @@ import invitation_en from "../../../public/locales/en/invitation.json"; import knowlegde_en from "../../../public/locales/en/knowledge.json"; import login_en from "../../../public/locales/en/login.json"; import logout_en from "../../../public/locales/en/logout.json"; +import monetization_en from "../../../public/locales/en/monetization.json"; import signUp_en from "../../../public/locales/en/signUp.json"; import translation_en from "../../../public/locales/en/translation.json"; import updatePassword_en from "../../../public/locales/en/updatePassword.json"; @@ -28,6 +29,7 @@ import invitation_es from "../../../public/locales/es/invitation.json"; import knowlegde_es from "../../../public/locales/es/knowledge.json"; import login_es from "../../../public/locales/es/login.json"; import logout_es from "../../../public/locales/es/logout.json"; +import monetization_es from "../../../public/locales/es/monetization.json"; import signUp_es from "../../../public/locales/es/signUp.json"; import translation_es from "../../../public/locales/es/translation.json"; import updatePassword_es from "../../../public/locales/es/updatePassword.json"; @@ -45,6 +47,7 @@ import invitation_fr from "../../../public/locales/fr/invitation.json"; import knowlegde_fr from "../../../public/locales/fr/knowledge.json"; import login_fr from "../../../public/locales/fr/login.json"; import logout_fr from "../../../public/locales/fr/logout.json"; +import monetization_fr from "../../../public/locales/fr/monetization.json"; import signUp_fr from "../../../public/locales/fr/signUp.json"; import translation_fr from "../../../public/locales/fr/translation.json"; import updatePassword_fr from "../../../public/locales/fr/updatePassword.json"; @@ -62,6 +65,7 @@ import invitation_ptbr from "../../../public/locales/pt-br/invitation.json"; import knowlegde_ptbr from "../../../public/locales/pt-br/knowledge.json"; import login_ptbr from "../../../public/locales/pt-br/login.json"; import logout_ptbr from "../../../public/locales/pt-br/logout.json"; +import monetization_ptbr from "../../../public/locales/pt-br/monetization.json"; import signUp_ptbr from "../../../public/locales/pt-br/signUp.json"; import translation_ptbr from "../../../public/locales/pt-br/translation.json"; import updatePassword_ptbr from "../../../public/locales/pt-br/updatePassword.json"; @@ -79,6 +83,7 @@ import invitation_ru from "../../../public/locales/ru/invitation.json"; import knowlegde_ru from "../../../public/locales/ru/knowledge.json"; import login_ru from "../../../public/locales/ru/login.json"; import logout_ru from "../../../public/locales/ru/logout.json"; +import monetization_ru from "../../../public/locales/ru/monetization.json"; import signUp_ru from "../../../public/locales/ru/signUp.json"; import translation_ru from "../../../public/locales/ru/translation.json"; import updatePassword_ru from "../../../public/locales/ru/updatePassword.json"; @@ -96,6 +101,7 @@ import invitation_zh_cn from "../../../public/locales/zh-cn/invitation.json"; import knowlegde_zh_cn from "../../../public/locales/zh-cn/knowledge.json"; import login_zh_cn from "../../../public/locales/zh-cn/login.json"; import logout_zh_cn from "../../../public/locales/zh-cn/logout.json"; +import monetization_zh_cn from "../../../public/locales/zh-cn/monetization.json"; import signUp_zh_cn from "../../../public/locales/zh-cn/signUp.json"; import translation_zh_cn from "../../../public/locales/zh-cn/translation.json"; import updatePassword_zh_cn from "../../../public/locales/zh-cn/updatePassword.json"; @@ -114,6 +120,7 @@ export type Translations = { invitation: typeof import("../../../public/locales/en/invitation.json"); login: typeof import("../../../public/locales/en/login.json"); logout: typeof import("../../../public/locales/en/logout.json"); + monetization: typeof import("../../../public/locales/en/monetization.json"); signUp: typeof import("../../../public/locales/en/signUp.json"); translation: typeof import("../../../public/locales/en/translation.json"); updatePassword: typeof import("../../../public/locales/en/updatePassword.json"); @@ -143,6 +150,7 @@ export const resources: Record = { invitation: invitation_en, login: login_en, logout: logout_en, + monetization: monetization_en, signUp: signUp_en, translation: translation_en, updatePassword: updatePassword_en, @@ -161,6 +169,7 @@ export const resources: Record = { invitation: invitation_es, login: login_es, logout: logout_es, + monetization: monetization_es, signUp: signUp_es, translation: translation_es, updatePassword: updatePassword_es, @@ -179,6 +188,7 @@ export const resources: Record = { invitation: invitation_fr, login: login_fr, logout: logout_fr, + monetization: monetization_fr, signUp: signUp_fr, translation: translation_fr, updatePassword: updatePassword_fr, @@ -197,6 +207,7 @@ export const resources: Record = { invitation: invitation_ptbr, login: login_ptbr, logout: logout_ptbr, + monetization: monetization_ptbr, signUp: signUp_ptbr, translation: translation_ptbr, updatePassword: updatePassword_ptbr, @@ -215,6 +226,7 @@ export const resources: Record = { invitation: invitation_ru, login: login_ru, logout: logout_ru, + monetization: monetization_ru, signUp: signUp_ru, translation: translation_ru, updatePassword: updatePassword_ru, @@ -233,6 +245,7 @@ export const resources: Record = { invitation: invitation_zh_cn, login: login_zh_cn, logout: logout_zh_cn, + monetization: monetization_zh_cn, signUp: signUp_zh_cn, translation: translation_zh_cn, updatePassword: updatePassword_zh_cn, diff --git a/frontend/next.config.js b/frontend/next.config.js index 41bcb01f4..cf8e6d413 100644 --- a/frontend/next.config.js +++ b/frontend/next.config.js @@ -37,7 +37,12 @@ const ContentSecurityPolicy = { "https://cdn.growthbook.io", "https://vitals.vercel-insights.com/v1/vitals", ], - "img-src": ["'self'", "https://www.gravatar.com","https://quivr-cms.s3.eu-west-3.amazonaws.com", "data:"], + "img-src": [ + "'self'", + "https://www.gravatar.com", + "https://quivr-cms.s3.eu-west-3.amazonaws.com", + "data:", + ], "media-src": [ "'self'", "https://user-images.githubusercontent.com", @@ -50,7 +55,9 @@ const ContentSecurityPolicy = { "https://va.vercel-scripts.com/", process.env.NEXT_PUBLIC_FRONTEND_URL, "https://www.google-analytics.com/", + "https://js.stripe.com", ], + "frame-src": ["https://js.stripe.com"], "frame-ancestors": ["'none'"], "style-src": ["'unsafe-inline'", process.env.NEXT_PUBLIC_FRONTEND_URL], }; diff --git a/frontend/public/locales/en/monetization.json b/frontend/public/locales/en/monetization.json new file mode 100644 index 000000000..20f621955 --- /dev/null +++ b/frontend/public/locales/en/monetization.json @@ -0,0 +1,4 @@ +{ + "upgrade": "Upgrade to plus", + "new": "New" +} diff --git a/frontend/public/locales/es/monetization.json b/frontend/public/locales/es/monetization.json new file mode 100644 index 000000000..c486c05f1 --- /dev/null +++ b/frontend/public/locales/es/monetization.json @@ -0,0 +1,4 @@ +{ + "upgrade": "Actualizar a plus", + "new": "Nuevo" +} diff --git a/frontend/public/locales/fr/monetization.json b/frontend/public/locales/fr/monetization.json new file mode 100644 index 000000000..278695a08 --- /dev/null +++ b/frontend/public/locales/fr/monetization.json @@ -0,0 +1,4 @@ +{ + "upgrade": "Passer à la version plus", + "new": "Nouveau" +} diff --git a/frontend/public/locales/pt-br/monetization.json b/frontend/public/locales/pt-br/monetization.json new file mode 100644 index 000000000..2e80e1f3a --- /dev/null +++ b/frontend/public/locales/pt-br/monetization.json @@ -0,0 +1,4 @@ +{ + "upgrade": "Atualizar para o plus", + "new": "Novo" +} diff --git a/frontend/public/locales/ru/monetization.json b/frontend/public/locales/ru/monetization.json new file mode 100644 index 000000000..21f6ff022 --- /dev/null +++ b/frontend/public/locales/ru/monetization.json @@ -0,0 +1,4 @@ +{ + "upgrade": "Обновить до плюса", + "new": "Новый" +} diff --git a/frontend/public/locales/zh-cn/monetization.json b/frontend/public/locales/zh-cn/monetization.json new file mode 100644 index 000000000..db6077df6 --- /dev/null +++ b/frontend/public/locales/zh-cn/monetization.json @@ -0,0 +1,4 @@ +{ + "upgrade": "升级至高级版", + "new": "新" +}