Skip to content

Commit

Permalink
feat(free-trial): adds free trial button, popover and modal. (#5345)
Browse files Browse the repository at this point in the history
* feat(trial): add free trial button

* implement designs for modal and popover

* add days left display into free trial

* disable show on load for modal

* feat(trial): add circle outline with progress

* feat(free-trial): update free trial button to use requests

* feat(free-trial): add mobile button

* feat(free-trial): remove fallback

* feat(free-trial): update props and popover position

* feat(free-trial): move logic to a context, avoid refetching on every mount of the sidebar

* fix(free-trial): update desktop button

* fix(free-trial): update free trial button click logic

* fix(free-trial): wait to render popover in mobile

* feat(free-trial): update response types and logic involved

* feat(free-trial): update dialogs designs and ux

* fix(free-trial): clear timer, remove unnecessary comment and update types for request

* fix(free-trial): updates to svg circle

* fix(free-trial): update how stroke is generated for image icons

* feat(free-trial): add support for trialDays in API response

* fix(free-trial): rename freeTrial type to sidebar and topbar, remove unnecessary wrapper

* fix(free-trial): re-focus on button after closing dialog

* fix(free-trial): add DynamicIcon fetch validation and controller

* fix(free-trial): replace trialDays for totalDays, update context
  • Loading branch information
pedrobonamin authored Dec 15, 2023
1 parent d4e5409 commit 16a8b58
Show file tree
Hide file tree
Showing 11 changed files with 773 additions and 106 deletions.
6 changes: 5 additions & 1 deletion packages/sanity/src/core/i18n/bundles/studio.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1523,7 +1523,11 @@ export const studioLocaleStrings = defineLocalesResources('studio', {
'timeline.since': 'Since: {{timestamp, datetime}}',
/** Label for missing change version for timeline menu dropdown are showing */
'timeline.since-version-missing': 'Since: unknown version',

/** Label for the button showed after trial ended */
'user-menu.action.free-trial-finished': 'Upgrade from free',
/** Label for button showing the free trial days left */
'user-menu.action.free-trial_one': '{{count}} day left in trial',
'user-menu.action.free-trial_other': '{{count}} days left in trial',
/** Label for action to invite members to the current sanity project */
'user-menu.action.invite-members': 'Invite members',
/** Accessibility label for action to invite members to the current sanity project */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {StudioThemeColorSchemeKey} from '../../../theme'
import {userHasRole} from '../../../util/userHasRole'
import {useTranslation} from '../../../i18n'
import {WorkspaceMenuButton} from './workspace'
import {FreeTrial} from './free-trial'

const ANIMATION_TRANSITION: Transition = {
duration: 0.2,
Expand Down Expand Up @@ -203,6 +204,7 @@ export const NavDrawer = memo(function NavDrawer(props: NavDrawerProps) {
{setScheme && <AppearanceMenu setScheme={setScheme} />}
<Card borderTop flex="none" padding={3}>
<Stack as="ul" space={1}>
<FreeTrial type="sidebar" />
<Stack as="li">
<Button
aria-label={t('user-menu.action.manage-project-aria-label')}
Expand Down
215 changes: 110 additions & 105 deletions packages/sanity/src/core/studio/components/navbar/StudioNavbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ import {LogoButton} from './LogoButton'
import {SearchDialog, SearchField} from './search'
import {SearchProvider} from './search/contexts/search/SearchProvider'
import {ResourcesButton} from './resources/ResourcesButton'
import {FreeTrial} from './free-trial'
import {FreeTrialProvider} from './free-trial/FreeTrialContext'
import {RouterState, useRouterState, useStateLink} from 'sanity/router'

const RootLayer = styled(Layer)`
Expand Down Expand Up @@ -139,123 +141,126 @@ export function StudioNavbar() {
}, [])

return (
<RootLayer zOffset={100} data-search-open={searchFullscreenOpen}>
<RootCard
data-testid="navbar"
data-ui="Navbar"
padding={2}
scheme="dark"
shadow={theme.__legacy || scheme === 'dark' ? 1 : undefined}
sizing="border"
>
<Flex align="center" justify="space-between">
<LeftFlex align="center" flex={shouldRender.brandingCenter ? undefined : 1}>
{!shouldRender.tools && (
<Box marginRight={1}>
<Button
mode="bleed"
icon={MenuIcon}
onClick={handleOpenDrawer}
ref={setDrawerButtonEl}
<FreeTrialProvider>
<RootLayer zOffset={100} data-search-open={searchFullscreenOpen}>
<RootCard
data-testid="navbar"
data-ui="Navbar"
padding={2}
scheme="dark"
shadow={theme.__legacy || scheme === 'dark' ? 1 : undefined}
sizing="border"
>
<Flex align="center" justify="space-between">
<LeftFlex align="center" flex={shouldRender.brandingCenter ? undefined : 1}>
{!shouldRender.tools && (
<Box marginRight={1}>
<Button
mode="bleed"
icon={MenuIcon}
onClick={handleOpenDrawer}
ref={setDrawerButtonEl}
/>
</Box>
)}

{!shouldRender.brandingCenter && (
<Box marginRight={1}>
<LogoButton href={rootHref} onClick={handleRootClick} title={title}>
<Logo title={title} />
</LogoButton>
</Box>
)}

{shouldRender.workspaces && (
<Box marginRight={2}>
<WorkspaceMenuButton collapsed />
</Box>
)}

<Box marginRight={shouldRender.brandingCenter ? undefined : 2}>
<NewDocumentButton
{...newDocumentOptions}
modal={shouldRender.brandingCenter ? 'dialog' : 'popover'}
/>
</Box>
)}

{!shouldRender.brandingCenter && (
<Box marginRight={1}>
{/* Search */}
<LayerProvider>
<SearchProvider fullscreen={shouldRender.searchFullscreen}>
<BoundaryElementProvider element={document.body}>
<PortalProvider element={searchFullscreenPortalEl}>
{shouldRender.searchFullscreen && (
<SearchDialog
onClose={handleCloseSearchFullscreen}
onOpen={handleOpenSearchFullscreen}
open={searchFullscreenOpen}
/>
)}
</PortalProvider>
{!shouldRender.searchFullscreen && <SearchField />}
</BoundaryElementProvider>
</SearchProvider>
</LayerProvider>

{shouldRender.tools && (
<Card flex={1} marginX={2} overflow="visible" paddingRight={1}>
<ToolMenu
activeToolName={activeToolName}
closeSidebar={handleCloseDrawer}
context="topbar"
isSidebarOpen={false}
tools={tools}
/>
</Card>
)}
</LeftFlex>

{shouldRender.brandingCenter && (
<Box marginX={1}>
<LogoButton href={rootHref} onClick={handleRootClick} title={title}>
<Logo title={title} />
</LogoButton>
</Box>
)}

{shouldRender.workspaces && (
<Box marginRight={2}>
<WorkspaceMenuButton collapsed />
</Box>
)}

<Box marginRight={shouldRender.brandingCenter ? undefined : 2}>
<NewDocumentButton
{...newDocumentOptions}
modal={shouldRender.brandingCenter ? 'dialog' : 'popover'}
/>
</Box>

{/* Search */}
<LayerProvider>
<SearchProvider fullscreen={shouldRender.searchFullscreen}>
<BoundaryElementProvider element={document.body}>
<PortalProvider element={searchFullscreenPortalEl}>
{shouldRender.searchFullscreen && (
<SearchDialog
onClose={handleCloseSearchFullscreen}
onOpen={handleOpenSearchFullscreen}
open={searchFullscreenOpen}
/>
)}
</PortalProvider>
{!shouldRender.searchFullscreen && <SearchField />}
</BoundaryElementProvider>
</SearchProvider>
</LayerProvider>

{shouldRender.tools && (
<Card flex={1} marginX={2} overflow="visible" paddingRight={1}>
<ToolMenu
activeToolName={activeToolName}
closeSidebar={handleCloseDrawer}
context="topbar"
isSidebarOpen={false}
tools={tools}
/>
</Card>
)}
</LeftFlex>

{shouldRender.brandingCenter && (
<Box marginX={1}>
<LogoButton href={rootHref} onClick={handleRootClick} title={title}>
<Logo title={title} />
</LogoButton>
</Box>
)}

<Flex gap={2}>
{(shouldRender.configIssues || shouldRender.resources) && (
<Card borderRight>
<Flex gap={1} paddingX={2}>
{shouldRender.configIssues && <ConfigIssuesButton />}
{shouldRender.resources && <ResourcesButton />}
</Flex>
</Card>
)}

<Flex align="center" gap={1}>
<PresenceMenu collapse={shouldRender.collapsedPresenceMenu} />
{shouldRender.tools && <UserMenu />}
{shouldRender.searchFullscreen && (
<Button
aria-label={t('search.action-open-aria-label')}
icon={SearchIcon}
mode="bleed"
onClick={handleOpenSearchFullscreen}
ref={setSearchOpenButtonEl}
/>
<Flex gap={2}>
{(shouldRender.configIssues || shouldRender.resources || shouldRender.tools) && (
<Card borderRight>
<Flex gap={1} paddingX={2}>
{shouldRender.tools && <FreeTrial type="topbar" />}
{shouldRender.configIssues && <ConfigIssuesButton />}
{shouldRender.resources && <ResourcesButton />}
</Flex>
</Card>
)}

<Flex align="center" gap={1}>
<PresenceMenu collapse={shouldRender.collapsedPresenceMenu} />
{shouldRender.tools && <UserMenu />}
{shouldRender.searchFullscreen && (
<Button
aria-label={t('search.action-open-aria-label')}
icon={SearchIcon}
mode="bleed"
onClick={handleOpenSearchFullscreen}
ref={setSearchOpenButtonEl}
/>
)}
</Flex>
</Flex>
</Flex>
</Flex>
</RootCard>
</RootCard>

{!shouldRender.tools && (
<NavDrawer
activeToolName={activeToolName}
isOpen={drawerOpen}
onClose={handleCloseDrawer}
tools={tools}
/>
)}
</RootLayer>
{!shouldRender.tools && (
<NavDrawer
activeToolName={activeToolName}
isOpen={drawerOpen}
onClose={handleCloseDrawer}
tools={tools}
/>
)}
</RootLayer>
</FreeTrialProvider>
)
}
Loading

2 comments on commit 16a8b58

@vercel
Copy link

@vercel vercel bot commented on 16a8b58 Dec 15, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

performance-studio – ./

performance-studio-git-next.sanity.build
performance-studio.sanity.build

@vercel
Copy link

@vercel vercel bot commented on 16a8b58 Dec 15, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

test-studio – ./

test-studio.sanity.build
test-studio-git-next.sanity.build

Please sign in to comment.