Skip to content

Commit

Permalink
feat: Free trial mutations (#9132)
Browse files Browse the repository at this point in the history
* feat(trials): Start Trial mutation

* GQL + FE updates

* Copy update

* Minor fixes

* End Trial mutation

* Some cleanup

* More fixes

* Rename var

* Extract 'getFeatureTier'

* More cleanup

* Tiny cleanup

* CR: change to featureTier and billingTier

* CR: Misc fixes

* Rename featureTier back to just tier

* CR: Explicitly do OrgUser and User updates in order

* CR: Combine rethink queries

* Actually we don't need to do those in a specific order

* Why are tests broken

* Revert "CR: Combine rethink queries"

This reverts commit 04ad78d.

* Revert "Why are tests broken"

This reverts commit eca6417.

* Manually bisecting changes that break tests (part 1)

* Revert "Manually bisecting changes that break tests (part 1)"

This reverts commit db90ead.

* Revert "Revert "CR: Combine rethink queries""

This reverts commit a8c21a7.

* Fix tests 🤦

* Update trial copy for OrgPlansAndBillingHeading
  • Loading branch information
jmtaber129 authored Nov 27, 2023
1 parent a26050e commit 7367b94
Show file tree
Hide file tree
Showing 72 changed files with 462 additions and 166 deletions.
6 changes: 4 additions & 2 deletions codegen.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
"ChangeEmailDomainSuccess": "./types/ChangeEmailDomainSuccess#ChangeEmailDomainSuccessSource",
"Company": "./queries/company#CompanySource",
"DraftEnterpriseInvoicePayload": "./types/DraftEnterpriseInvoicePayload#DraftEnterpriseInvoicePayloadSource",
"EndTrialSuccess": "./types/EndTrialSuccess#EndTrialSuccessSource",
"File": "../public/types/File#TFile",
"FlagConversionModalPayload": "./types/FlagConversionModalPayload#FlagConversionModalPayloadSource",
"FlagOverLimitPayload": "./types/FlagOverLimitPayload#FlagOverLimitPayloadSource",
Expand All @@ -27,6 +28,7 @@
"SAML": "./types/SAML#SAMLSource",
"SetIsFreeMeetingTemplateSuccess": "./types/SetIsFreeMeetingTemplateSuccess#SetIsFreeMeetingTemplateSuccessSource",
"SignupsPayload": "./types/SignupsPayload#SignupsPayloadSource",
"StartTrialSuccess": "./types/StartTrialSuccess#StartTrialSuccessSource",
"StripeFailPaymentPayload": "./mutations/stripeFailPayment#StripeFailPaymentPayloadSource",
"Team": "../../postgres/queries/getTeamsByIds#Team",
"UpdateOrgFeatureFlagSuccess": "./types/UpdateOrgFeatureFlagSuccess#UpdateOrgFeatureFlagSuccessSource",
Expand Down Expand Up @@ -93,8 +95,8 @@
"RequestToJoinDomainSuccess": "./types/RequestToJoinDomainSuccess#RequestToJoinDomainSuccessSource",
"ResetReflectionGroupsSuccess": "./types/ResetReflectionGroupsSuccess#ResetReflectionGroupsSuccessSource",
"RetrospectiveMeeting": "../../database/types/MeetingRetrospective#default",
"SAML": "./types/SAML#SAMLSource",
"RetrospectiveMeetingSettings": "../../database/types/MeetingSettingsRetrospective#default",
"SAML": "./types/SAML#SAMLSource",
"SetMeetingSettingsPayload": "../types/SetMeetingSettingsPayload#SetMeetingSettingsPayloadSource",
"SetNotificationStatusPayload": "./types/SetNotificationStatusPayload#SetNotificationStatusPayloadSource",
"SetOrgUserRoleSuccess": "./types/SetOrgUserRoleSuccess#SetOrgUserRoleSuccessSource",
Expand All @@ -114,8 +116,8 @@
"TemplateDimension": "../../database/types/TemplateDimension#default",
"TimelineEventTeamPromptComplete": "./types/TimelineEventTeamPromptComplete#TimelineEventTeamPromptCompleteSource",
"ToggleSummaryEmailSuccess": "./types/ToggleSummaryEmailSuccess#ToggleSummaryEmailSuccessSource",
"UpdateAutoJoinSuccess": "./types/UpdateAutoJoinSuccess#UpdateAutoJoinSuccessSource",
"TopRetroTemplate": "./types/TopRetroTemplate#TopRetroTemplateSource",
"UpdateAutoJoinSuccess": "./types/UpdateAutoJoinSuccess#UpdateAutoJoinSuccessSource",
"UpdateCreditCardSuccess": "./types/UpdateCreditCardSuccess#UpdateCreditCardSuccessSource",
"UpdateDimensionFieldSuccess": "./types/UpdateDimensionFieldSuccess#UpdateDimensionFieldSuccessSource",
"UpdateFeatureFlagPayload": "./types/UpdateFeatureFlagPayload#UpdateFeatureFlagPayloadSource",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ export const query = graphql`
viewer {
...ActivityDetailsSidebar_viewer
preferredTeamId
tier
activity(activityId: $activityId) {
...ActivityDetails_template @relay(mask: false)
}
Expand Down
6 changes: 3 additions & 3 deletions packages/client/components/BillingLeaderActionMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ const BillingLeaderActionMenu = (props: Props) => {
graphql`
fragment BillingLeaderActionMenu_organization on Organization {
id
tier
billingTier
}
`,
organizationRef
Expand All @@ -54,7 +54,7 @@ const BillingLeaderActionMenu = (props: Props) => {
organizationUserRef
)
const atmosphere = useAtmosphere()
const {id: orgId, tier} = organization
const {id: orgId, billingTier} = organization
const {viewerId} = atmosphere
const {newUserUntil, role, user} = organizationUser
const isBillingLeader = role === 'BILLING_LEADER'
Expand Down Expand Up @@ -84,7 +84,7 @@ const BillingLeaderActionMenu = (props: Props) => {
{viewerId !== userId && (
<MenuItem
label={
tier === 'team' && new Date(newUserUntil) > new Date()
billingTier === 'team' && new Date(newUserUntil) > new Date()
? 'Refund and Remove'
: 'Remove from Organization'
}
Expand Down
5 changes: 3 additions & 2 deletions packages/client/components/NewTeamOrgDropdown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ const NewTeamOrgDropdown = (props: Props) => {
id
name
tier
billingTier
}
`,
organizationsRef
Expand All @@ -36,14 +37,14 @@ const NewTeamOrgDropdown = (props: Props) => {
>
<DropdownMenuLabel>Select Organization:</DropdownMenuLabel>
{organizations.map((anOrg) => {
const {id, tier, name} = anOrg
const {id, tier, billingTier, name} = anOrg
return (
<MenuItem
key={id}
label={
<DropdownMenuItemLabel>
<span>{name}</span>
{tier !== 'starter' && <TierTag tier={tier} />}
{tier !== 'starter' && <TierTag tier={tier} billingTier={billingTier} />}
</DropdownMenuItemLabel>
}
onClick={() => {
Expand Down
10 changes: 6 additions & 4 deletions packages/client/components/StandardHub/StandardHub.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,8 @@ const DEFAULT_VIEWER = {
picture: '',
preferredName: '',
email: '',
tier: 'starter'
tier: 'starter',
billingTier: 'starter'
} as const

const StandardHub = (props: Props) => {
Expand All @@ -100,11 +101,12 @@ const StandardHub = (props: Props) => {
picture
preferredName
tier
billingTier
}
`,
viewerRef
)
const {email, picture, preferredName, tier} = viewer || DEFAULT_VIEWER
const {email, picture, preferredName, tier, billingTier} = viewer || DEFAULT_VIEWER
const userAvatar = picture || defaultUserAvatar
const {history} = useRouter()
const handleUpgradeClick = () => {
Expand All @@ -124,13 +126,13 @@ const StandardHub = (props: Props) => {
<Email>{email}</Email>
</NameAndEmail>
</User>
{tier === 'starter' ? (
{billingTier === 'starter' ? (
<Upgrade onClick={handleUpgradeClick}>
<VerifiedUserIcon />
<UpgradeCTA>{'Upgrade'}</UpgradeCTA>
</Upgrade>
) : (
<Tier tier={tier as TierEnum} />
<Tier tier={tier as TierEnum} billingTier={billingTier as TierEnum} />
)}
</StandardHubRoot>
)
Expand Down
4 changes: 2 additions & 2 deletions packages/client/components/StandardHubUserMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,15 +48,15 @@ const StandardHubUserMenu = (props: Props) => {
}
organizations {
id
tier
billingTier
}
}
`,
viewerRef
)
const {email, featureFlags, organizations} = viewer
const {insights} = featureFlags
const ownedFreeOrgs = organizations.filter((org) => org.tier === 'starter')
const ownedFreeOrgs = organizations.filter((org) => org.billingTier === 'starter')
const showUpgradeCTA = ownedFreeOrgs.length > 0
const routeSuffix = ownedFreeOrgs.length === 1 ? `/${ownedFreeOrgs[0]!.id}` : ''

Expand Down
4 changes: 3 additions & 1 deletion packages/client/components/Tag/TierTag.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import BaseTag from './BaseTag'
interface Props {
className?: string
tier: TierEnum | null
billingTier: TierEnum | null
}

const StarterTag = styled(BaseTag)({
Expand All @@ -26,7 +27,8 @@ const EnterpriseTag = styled(BaseTag)({
})

const TierTag = (props: Props) => {
const {className, tier} = props
const {className, tier, billingTier} = props
if (tier !== billingTier) return <StarterTag className={className}>{'Free Trial'}</StarterTag>
if (tier === 'starter') return <StarterTag className={className}>{TierLabel.STARTER}</StarterTag>
if (tier === 'team') return <TeamTag className={className}>{TierLabel.TEAM}</TeamTag>
if (tier === 'enterprise')
Expand Down
4 changes: 2 additions & 2 deletions packages/client/components/ThreadedCommentBase.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ const ThreadedCommentBase = (props: Props) => {
graphql`
fragment ThreadedCommentBase_viewer on User {
...ThreadedItemReply_viewer
tier
billingTier
}
`,
viewerRef
Expand Down Expand Up @@ -140,7 +140,7 @@ const ThreadedCommentBase = (props: Props) => {
if (createdByUserNullable?.id === PARABOL_AI_USER_ID) {
SendClientSideEvent(atmosphere, 'AI Summary Viewed', {
source: 'Discussion',
tier: viewer.tier,
tier: viewer.billingTier,
meetingId,
discussionTopicId
})
Expand Down
6 changes: 3 additions & 3 deletions packages/client/hooks/useUsageSnackNag.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@ const getIsNaggingPath = (history: RouterProps['history']) => {
return !(pathname.includes('/usage') || pathname.includes('/meet/'))
}

const shouldNag = (tier: TierEnum, suggestedTier: TierEnum | null) => {
const shouldNag = (billingTier: TierEnum, suggestedTier: TierEnum | null) => {
if (!suggestedTier) return false
const suggestPro = suggestedTier === 'team' && tier === 'starter'
const suggestEnterprise = suggestedTier === 'enterprise' && tier !== 'enterprise'
const suggestPro = suggestedTier === 'team' && billingTier === 'starter'
const suggestEnterprise = suggestedTier === 'enterprise' && billingTier !== 'enterprise'
return suggestPro || suggestEnterprise
}

Expand Down
2 changes: 2 additions & 0 deletions packages/client/modules/demo/initDB.ts
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,7 @@ const initDemoOrg = () => {
id: demoOrgId,
name: 'Demo Organization',
tier: 'team',
billingTier: 'team',
orgUserCount: {
activeUserCount: 5,
inactiveUserCount: 0
Expand Down Expand Up @@ -327,6 +328,7 @@ const initDemoTeam = (
teamName: demoTeamName,
orgId: demoOrgId,
tier: 'team',
billingTier: 'team',
teamId: demoTeamId,
organization,
meetingSettings: initMeetingSettings(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ const WholeMeetingSummaryResult = (props: Props) => {
summary
team {
tier
billingTier
}
}
`,
Expand All @@ -60,7 +61,7 @@ const WholeMeetingSummaryResult = (props: Props) => {
useEffect(() => {
SendClientSideEvent(atmosphere, 'AI Summary Viewed', {
source: 'Meeting Summary',
tier: meeting.team.tier,
tier: meeting.team.billingTier,
meetingId: meeting.id
})
}, [])
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ const InvoiceHeader = (props: Props) => {
</LogoPanel>
<Info>
<OrgName>{orgName}</OrgName>
{tier !== 'starter' && <StyledTierTag tier={tier} />}
{tier !== 'starter' && <StyledTierTag billingTier={tier} tier={tier} />}
{billingLeaderEmails.map((email) => (
<Email key={`email${email}`}>{email}</Email>
))}
Expand Down
5 changes: 4 additions & 1 deletion packages/client/modules/team/components/NewTeamOrgPicker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ const NewTeamOrgPicker = (props: Props) => {
id
name
tier
billingTier
}
`,
organizationsRef
Expand Down Expand Up @@ -85,7 +86,9 @@ const NewTeamOrgPicker = (props: Props) => {
defaultText={
<MenuToggleInner>
<MenuToggleLabel>{defaultText}</MenuToggleLabel>
{org && org.tier !== 'starter' && <TierTag tier={org.tier} />}
{org && org.tier !== 'starter' && (
<TierTag tier={org.tier} billingTier={org.billingTier} />
)}
</MenuToggleInner>
}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ const query = graphql`
id
name
tier
billingTier
orgId
teamMembers(sortBy: "preferredName") {
teamMemberId: id
Expand All @@ -67,7 +68,7 @@ const TeamSettings = (props: Props) => {
const {viewer} = data
const {history} = useRouter()
const {team} = viewer
const {name: teamName, orgId, teamMembers, tier} = team!
const {name: teamName, orgId, teamMembers, tier, billingTier} = team!
useDocumentTitle(`Team Settings | ${teamName}`, 'Team Settings')
const viewerTeamMember = teamMembers.find((m) => m.isSelf)
// if kicked out, the component might reload before the redirect occurs
Expand All @@ -78,10 +79,14 @@ const TeamSettings = (props: Props) => {
return (
<TeamSettingsLayout>
<PanelsLayout>
{tier === 'starter' && (
{billingTier === 'starter' && (
<Panel>
<StyledRow>
<div>{'This team is currently on a starter plan.'}</div>
<div>
{tier !== 'starter'
? `This team is currently on a free trial for the ${TierLabel.TEAM} plan.`
: 'This team is currently on a starter plan.'}
</div>
<PrimaryButton onClick={() => history.push(`/me/organizations/${orgId}`)}>
{`Upgrade Team to ${TierLabel.TEAM}`}
</PrimaryButton>
Expand All @@ -98,8 +103,8 @@ const TeamSettings = (props: Props) => {
<Panel className='mt-8'>
<StyledRow>
<div>
This team is currently on a <b className='capitalize'>{tier} plan</b>. Only Team
Leads can <b>Upgrade plans</b> and <b>Delete a team</b>.<br />
This team is currently on a <b className='capitalize'>{billingTier} plan</b>. Only
Team Leads can <b>Upgrade plans</b> and <b>Delete a team</b>.<br />
The <b>Team Lead</b> for {teamName} is{' '}
<a href={`mailto:${contact.email}`} className='text-sky-500 underline'>
{contact.preferredName}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,17 +40,17 @@ const OrgBilling = (props: Props) => {
...OrgBillingUpgrade_organization
...OrgBillingDangerZone_organization
id
tier
billingTier
}
`,
organizationRef
)
const {tier} = organization
const {billingTier} = organization

return (
<div>
<OrgBillingUpgrade organization={organization} invoiceListRefetch={refetch} />
{tier === 'team' && (
{billingTier === 'team' && (
<>
<OrgBillingCreditCardInfoOld organization={organization} />
<OrgBillingInvoices queryRef={queryData} />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,14 +59,14 @@ const OrgBillingDangerZone = (props: Props) => {
fragment OrgBillingDangerZone_organization on Organization {
...ArchiveOrganization_organization
isBillingLeader
tier
billingTier
}
`,
organizationRef
)
const {isBillingLeader, tier} = organization
const {isBillingLeader, billingTier} = organization
if (!isBillingLeader) return null
const isStarter = tier === 'starter'
const isStarter = billingTier === 'starter'
return (
<StyledPanel isWide={isWide} label='Danger Zone'>
<PanelRow>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,15 +47,15 @@ const OrgBillingUpgrade = (props: Props) => {
graphql`
fragment OrgBillingUpgrade_organization on Organization {
id
tier
billingTier
orgUserCount {
activeUserCount
}
}
`,
organizationRef
)
const {id: orgId, tier, orgUserCount} = organization
const {id: orgId, billingTier, orgUserCount} = organization
const {activeUserCount} = orgUserCount
const {togglePortal, closePortal, modalPortal} = useModal()
const onUpgrade = () => invoiceListRefetch?.({orgId, first: 3})
Expand All @@ -70,7 +70,7 @@ const OrgBillingUpgrade = (props: Props) => {
activeUserCount={activeUserCount}
/>
)}
{tier === 'starter' && (
{billingTier === 'starter' && (
<Panel>
<Inner>
<Title>Upgrade</Title>
Expand Down
Loading

0 comments on commit 7367b94

Please sign in to comment.