'use client'; import React, { FC, useCallback, useEffect, useMemo, useState } from 'react'; import useSWR from 'swr'; import { useFetch } from '@gitroom/helpers/utils/custom.fetch'; import { useVariables } from '@gitroom/react/helpers/variable.context'; import { loadStripe, Stripe } from '@stripe/stripe-js'; import { useSearchParams } from 'next/navigation'; import { OrganizationSelector } from '@gitroom/frontend/components/layout/organization.selector'; import { LanguageComponent } from '@gitroom/frontend/components/layout/language.component'; import { AttachToFeedbackIcon } from '@gitroom/frontend/components/new-layout/sentry.feedback.component'; import NotificationComponent from '@gitroom/frontend/components/notifications/notification.component'; import dynamic from 'next/dynamic'; import { LogoTextComponent } from '@gitroom/frontend/components/ui/logo-text.component'; import { pricing } from '@gitroom/nestjs-libraries/database/prisma/subscriptions/pricing'; import { capitalize } from 'lodash'; import clsx from 'clsx'; import { LoadingComponent } from '@gitroom/frontend/components/layout/loading'; import { CheckIconComponent } from '@gitroom/frontend/components/ui/check.icon.component'; import { FAQComponent, FAQSection, } from '@gitroom/frontend/components/billing/faq.component'; import { useT } from '@gitroom/react/translation/get.transation.service.client'; import { useUser } from '@gitroom/frontend/components/layout/user.context'; import { useDubClickId } from '@gitroom/frontend/components/layout/dubAnalytics'; const ModeComponent = dynamic( () => import('@gitroom/frontend/components/layout/mode.component'), { ssr: false, } ); const EmbeddedBilling = dynamic( () => import('@gitroom/frontend/components/billing/embedded.billing').then( (mod) => mod.EmbeddedBilling ), { ssr: false, } ); export const FirstBillingComponent = () => { const { stripeClient } = useVariables(); const user = useUser(); const dub = useDubClickId(); const [stripe, setStripe] = useState>(null); const [tier, setTier] = useState('STANDARD'); const [period, setPeriod] = useState('MONTHLY'); const fetch = useFetch(); const t = useT(); useEffect(() => { setStripe(loadStripe(stripeClient)); }, []); const loadCheckout = useCallback(async () => { return ( await fetch('/billing/embedded', { method: 'POST', body: JSON.stringify({ billing: tier, period: period, ...(dub ? { dub } : {}), }), }) ).json(); }, [tier, period]); const { data, isLoading } = useSWR( `/billing-${tier}-${period}`, loadCheckout, { revalidateOnFocus: false, revalidateOnReconnect: false, revalidateIfStale: false, refreshWhenOffline: false, refreshWhenHidden: false, } ); const price = useMemo( () => Object.entries(pricing).filter(([key, value]) => key !== 'FREE'), [] ); const JoinOver = () => { return ( <>
{t('billing_join_over', 'Join Over')}{' '} {t('billing_entrepreneurs_count', '18,000+ Entrepreneurs')} {' '} {t('billing_who_use', 'who use')}{' '} {t( 'billing_postiz_grow_social', 'Postiz To Grow Their Social Presence' )}
{!!user?.allowTrial && (
{t('billing_no_risk_trial', '100% No-Risk Free Trial')}
{t( 'billing_pay_nothing_7_days', 'Pay NOTHING for the first 7-days' )}
{t('billing_cancel_anytime', 'Cancel anytime, from settings')}
)} ); }; return (
{!isLoading && data && stripe ? ( <> ) : ( )}
{t('billing_choose_plan', 'Choose a Plan')}
setPeriod('MONTHLY')} > {t('billing_monthly', 'Monthly')}
setPeriod('YEARLY')} >
{t('billing_yearly', 'Yearly')}
{t('billing_20_percent_off', '20% Off')}
{price.map( ([key, value]) => (
setTier(key)} key={key} className={clsx( 'cursor-pointer select-none w-[266px] h-[138px] tablet:w-full tablet:h-[124px] p-[24px] tablet:p-[15px] rounded-[20px] flex flex-col', key === tier ? 'border-[1.5px] border-[#618DFF]' : 'border-[1.5px] border-newColColor' )} >
{capitalize(key)}
$ { value[ period === 'MONTHLY' ? 'month_price' : 'year_price' ] } {' '} {period === 'MONTHLY' ? t('billing_per_month', '/ month') : t('billing_per_year', '/ year')}
), [] )}
{t('billing_features', 'Features')}
); }; type FeatureItem = { key: string; defaultValue: string; prefix?: string | number; }; export const BillingFeatures: FC<{ tier: string }> = ({ tier }) => { const t = useT(); const features = useMemo(() => { const currentPricing = pricing[tier]; const channelsOr = currentPricing.channel; const list: FeatureItem[] = []; list.push({ key: channelsOr === 1 ? 'billing_channel' : 'billing_channels', defaultValue: channelsOr === 1 ? 'channel' : 'channels', prefix: channelsOr, }); list.push({ key: 'billing_posts_per_month', defaultValue: 'posts per month', prefix: currentPricing.posts_per_month > 10000 ? 'unlimited' : currentPricing.posts_per_month, }); if (currentPricing.team_members) { list.push({ key: 'billing_unlimited_team_members', defaultValue: 'Unlimited team members', }); } if (currentPricing?.ai) { list.push({ key: 'billing_ai_auto_complete', defaultValue: 'AI auto-complete', }); list.push({ key: 'billing_ai_copilots', defaultValue: 'AI copilots' }); list.push({ key: 'billing_ai_autocomplete', defaultValue: 'AI Autocomplete', }); } list.push({ key: 'billing_advanced_picture_editor', defaultValue: 'Advanced Picture Editor', }); if (currentPricing?.image_generator) { list.push({ key: 'billing_ai_images_per_month', defaultValue: 'AI Images per month', prefix: currentPricing?.image_generation_count, }); } if (currentPricing?.generate_videos) { list.push({ key: 'billing_ai_videos_per_month', defaultValue: 'AI Videos per month', prefix: currentPricing?.generate_videos, }); } return list; }, [tier]); const renderFeature = (feature: FeatureItem) => { const translatedText = t(feature.key, feature.defaultValue); if (feature.prefix === 'unlimited') { return `${t('billing_unlimited', 'Unlimited')} ${translatedText}`; } if (feature.prefix !== undefined) { return `${feature.prefix} ${translatedText}`; } return translatedText; }; return (
{features.map((feature) => (
{renderFeature(feature)}
))}
); };