From d18fff9b1483de52f4044e487b6bda6a5262f9b0 Mon Sep 17 00:00:00 2001 From: Lucas Fernandes da Costa Date: Wed, 18 Dec 2024 17:52:14 -0300 Subject: [PATCH] show stars instead of plan on OSS version --- apps/web/package.json | 1 + apps/web/src/components/BlinkingSignal.tsx | 14 +- .../src/components/ConfigurationsMenuItem.tsx | 66 ++++ apps/web/src/components/DataSourceIcons.tsx | 8 +- apps/web/src/components/Layout.tsx | 84 +++-- apps/web/src/components/SubscriptionBadge.tsx | 353 +----------------- yarn.lock | 43 +-- 7 files changed, 160 insertions(+), 409 deletions(-) create mode 100644 apps/web/src/components/ConfigurationsMenuItem.tsx diff --git a/apps/web/package.json b/apps/web/package.json index 314e02a3..18de69fb 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -96,6 +96,7 @@ "react-dnd-html5-backend": "^16.0.1", "react-dom": "^18", "react-dropzone": "^14.2.3", + "react-github-btn": "^1.4.0", "react-grid-layout": "^1.2.5", "react-hook-form": "^7.47.0", "react-hotkeys-hook": "^4.5.0", diff --git a/apps/web/src/components/BlinkingSignal.tsx b/apps/web/src/components/BlinkingSignal.tsx index a523a33a..4802faa7 100644 --- a/apps/web/src/components/BlinkingSignal.tsx +++ b/apps/web/src/components/BlinkingSignal.tsx @@ -1,5 +1,3 @@ -import { useDataSources } from '@/hooks/useDatasources' -import { useStringQuery } from '@/hooks/useQueryArgs' import clsx from 'clsx' interface Props { @@ -26,17 +24,7 @@ function BlinkingSignal(props: Props) { ) } -export const DataSourceBlinkingSignal = () => { - const workspaceId = useStringQuery('workspaceId') ?? '' - const [{ datasources: allDataSources, isLoading }] = - useDataSources(workspaceId) - - const userDataSources = allDataSources.filter((ds) => !ds.config.data.isDemo) - - if (isLoading || !userDataSources || userDataSources.size > 0) { - return null - } - +export function ConfigurationsMenuBlinkingSignal() { return ( void +} + +const ConfigurationsMenuLink = (props: ConfigurationsMenuLinkProps) => { + return ( + +
+ {props.blink && } +
+ + ) +} + +const ConfigurationsMenuButton = (props: ConfigurationsMenuButtonProps) => { + return ( + + ) +} + +export { ConfigurationsMenuLink, ConfigurationsMenuButton } diff --git a/apps/web/src/components/DataSourceIcons.tsx b/apps/web/src/components/DataSourceIcons.tsx index 3bf14071..9b191207 100644 --- a/apps/web/src/components/DataSourceIcons.tsx +++ b/apps/web/src/components/DataSourceIcons.tsx @@ -10,9 +10,9 @@ const DataSourceBlock = ({ name, icon, href }: DataSourceBlockProps) => { return ( - + {name} ) @@ -69,9 +69,9 @@ export const DataSourceIcons = ({ /> diff --git a/apps/web/src/components/Layout.tsx b/apps/web/src/components/Layout.tsx index 6b9528ef..cded3fb5 100644 --- a/apps/web/src/components/Layout.tsx +++ b/apps/web/src/components/Layout.tsx @@ -23,6 +23,7 @@ import { AdjustmentsHorizontalIcon, PuzzlePieceIcon, MagnifyingGlassIcon, + RocketLaunchIcon, } from '@heroicons/react/24/outline' import clsx from 'clsx' import Link from 'next/link' @@ -31,18 +32,24 @@ import { Page } from '@/components/PagePath' import { useDocuments } from '@/hooks/useDocuments' import { useFavorites } from '@/hooks/useFavorites' import { useStringQuery } from '@/hooks/useQueryArgs' -import { SessionUser, useSession, useSignout } from '@/hooks/useAuth' -import { CpuChipIcon } from '@heroicons/react/24/solid' +import { CpuChipIcon, SparklesIcon } from '@heroicons/react/24/solid' import type { UserWorkspaceRole } from '@briefer/database' import ReactDOM from 'react-dom' import useDropdownPosition from '@/hooks/dropdownPosition' import DocumentTree from './DocumentsTree' import useSideBar from '@/hooks/useSideBar' -import { SubscriptionBadge } from './SubscriptionBadge' import MobileWarning from './MobileWarning' -import { DataSourceBlinkingSignal } from './BlinkingSignal' import CommandPalette from './commandPalette' import { useHotkeys } from 'react-hotkeys-hook' +import Onboarding from './onboarding' +import GitHubButton from 'react-github-btn' +import { useDataSources } from '@/hooks/useDatasources' +import { + ConfigurationsMenuButton, + ConfigurationsMenuLink, +} from './ConfigurationsMenuItem' +import { FeaturesDialog } from './SubscriptionBadge' +import { SessionUser, useSignout } from '@/hooks/useAuth' const syne = Syne({ subsets: ['latin'] }) @@ -54,6 +61,7 @@ type ConfigItem = { hidden?: boolean allowedRoles: Set } + const configs = (workspaceId: string): ConfigItem[] => [ { id: 'environments', @@ -134,6 +142,11 @@ export default function Layout({ const workspaceId = useStringQuery('workspaceId') const documentId = useStringQuery('documentId') + const [{ datasources: allDataSources, isLoading: isLoadingDataSources }] = + useDataSources(workspaceId) + const userDataSources = allDataSources.filter((ds) => !ds.config.data.isDemo) + const hasUserDataSource = !isLoadingDataSources && userDataSources.size > 0 + const [ documentsState, { @@ -285,6 +298,8 @@ export default function Layout({ } }, [workspaceId, scrollRef]) + const [isUpgradeDialogOpen, setUpgradeDialogOpen] = useState(false) + return (
@@ -295,14 +310,33 @@ export default function Layout({ setOpen={setSearchOpen} /> + + + {!hideOnboarding && } + {isSideBarOpen && (
-
- - briefer - +
+
+ + briefer +
- +
+ + Star + +
@@ -386,31 +420,23 @@ export default function Layout({ Configurations
    +
  • + setUpgradeDialogOpen(true)} + /> +
  • {configs(workspaceId) .filter(showConfigItem) .map((item) => (
  • - -
    - {item.id === 'data-sources' && ( - - )} -
    - + text={item.name} + icon={item.icon} + blink={item.id === 'data-sources' && !hasUserDataSource} + />
  • ))} diff --git a/apps/web/src/components/SubscriptionBadge.tsx b/apps/web/src/components/SubscriptionBadge.tsx index f15297f6..d6d067cc 100644 --- a/apps/web/src/components/SubscriptionBadge.tsx +++ b/apps/web/src/components/SubscriptionBadge.tsx @@ -1,83 +1,10 @@ -import clsx from 'clsx' -import { Fragment, useMemo, useRef, useState } from 'react' +import { Fragment, useRef } from 'react' import { Dialog, Transition } from '@headlessui/react' -import { CheckIcon, TicketIcon, XMarkIcon } from '@heroicons/react/24/outline' -import { HeartIcon, SparklesIcon } from '@heroicons/react/24/solid' +import { TicketIcon } from '@heroicons/react/24/outline' +import { HeartIcon } from '@heroicons/react/24/solid' type PlanName = 'open-source' | 'free' | 'trial' | 'professional' -const statusColors = { - free: 'bg-gray-100 text-gray-600 ring-gray-500/10 hover:bg-gray-200', - trial: 'bg-yellow-50 text-yellow-800 ring-yellow-600/20 hover:bg-yellow-100', - professional: 'bg-blue-50 text-blue-700 ring-blue-600/20 hover:bg-blue-100', - 'open-source': 'bg-green-50 text-green-700 ring-green-600/20', -} - -export const SubscriptionBadge = ({ - planName: status, -}: { - planName: PlanName -}) => { - const text: string | JSX.Element = (() => { - switch (status) { - case 'free': - return 'Free plan' - case 'trial': - return 'Trial active' - case 'professional': - return 'Professional' - case 'open-source': - return ( -
    - Briefer - - ♥ - - OSS -
    - ) - } - })() - - const icon: JSX.Element | null = (() => { - if (status === 'open-source') { - return null - } - - if (status === 'professional') { - return ( - - - - ) - } - - return ( - - - - ) - })() - - const [open, setOpen] = useState(false) - - return ( - <> - - - - ) -} - export function FeaturesDialog({ open, setOpen, @@ -89,64 +16,6 @@ export function FeaturesDialog({ }) { const cancelButtonRef = useRef(null) - const title = useMemo(() => { - switch (currentPlan) { - case 'free': - return 'Unlock extra features with the professional plan' - case 'trial': - return 'You have trial access to extra features' - case 'professional': - return 'You have access to extra features and seats' - case 'open-source': - return "You're using Briefer's open source version" - } - }, [currentPlan]) - - const description = useMemo(() => { - switch (currentPlan) { - case 'free': - return ( -
    -

    {'Hey, if the free plan suits your needs, that’s great!'}

    -

    - Anyway, if you need more, you can always upgrade to the - professional plan. -

    -
    - ) - case 'trial': - return ( -

    - You have trial access to all the extra features of the professional - plan. -

    - ) - case 'professional': - return ( -

    - { - "We're glad to have you on board! You have access to all the extra features of the professional plan." - } -

    - ) - case 'open-source': - return ( -
    -

    - { - "Briefer's open-source version includes all the main features of Briefer, like SQL, Python, Scheduling, and more." - } -

    -

    - { - 'If you need more granular permissions, PDF exports, embedded graphs, or integrations, please consider upgrading to the professional plan.' - } -

    -
    - ) - } - }, [currentPlan]) - return ( - +
    {currentPlan !== 'open-source' ? ( @@ -195,21 +64,23 @@ export function FeaturesDialog({
    - {title} + {"You're using Briefer's open source version"} -
    - {description} - - - - {currentPlan === 'trial' && ( +
    +
    +

    + { + "Briefer's open-source version includes an unlimited number of seats, pages, and schedules, as well as Python, SQL, and Visualizations." + } +

    - Don't worry! Once your trial period ends, you - will still have access to Briefer's free plan. + { + 'If you need SSO, granular permissions, PDF exports, or integrations, please consider upgrading your plan.' + }

    - )} +
    @@ -222,7 +93,7 @@ export function FeaturesDialog({ window.open('https://briefer.cloud/pricing') }} > - Upgrade + View plans