Simplify the dialog

This commit is contained in:
Eric Bailey
2024-11-20 11:34:35 -06:00
parent 4db49edca6
commit b63cb9bf5d
3 changed files with 201 additions and 213 deletions
+3
View File
@@ -654,10 +654,12 @@ export function ButtonIcon({
icon: Comp,
position,
size,
style,
}: {
icon: React.ComponentType<SVGIconProps>
position?: 'left' | 'right'
size?: SVGIconProps['size']
style?: SVGIconProps['style']
}) {
const {size: buttonSize, disabled} = useButtonContext()
const textStyles = useSharedButtonTextStyles()
@@ -742,6 +744,7 @@ export function ButtonIcon({
color: textStyles.color,
pointerEvents: 'none',
},
style,
]}
/>
</View>
+4 -3
View File
@@ -1,11 +1,12 @@
import {LinearGradient} from 'expo-linear-gradient'
import {atoms as a, tokens} from '#/alf'
import {atoms as a, tokens, ViewStyleProp} from '#/alf'
export function GradientFill({
gradient,
rotate,
}: {
style,
}: ViewStyleProp & {
gradient:
| typeof tokens.gradients.primary
| typeof tokens.gradients.sky
@@ -39,7 +40,7 @@ export function GradientFill({
locations={gradient.values.map(c => c[0])}
start={start}
end={end}
style={[a.absolute, a.inset_0]}
style={[a.absolute, a.inset_0, style]}
/>
)
}
+194 -210
View File
@@ -3,42 +3,48 @@ import {View} from 'react-native'
import {msg, Trans} from '@lingui/macro'
import {useLingui} from '@lingui/react'
import {
OfferingId,
SubscriptionGroupId,
} from '#/state/purchases/subscriptions/types'
import {
usePurchaseOffering,
useSubscriptionGroup,
} from '#/state/purchases/subscriptions/useSubscriptionGroup'
import {parseOfferingId} from '#/state/purchases/subscriptions/util'
import {useSession} from '#/state/session'
import * as Toast from '#/view/com/util/Toast'
import {atoms as a, tokens, useBreakpoints, useTheme, web} from '#/alf'
import {atoms as a, tokens, useBreakpoints, useTheme} from '#/alf'
import {Button, ButtonIcon, ButtonText} from '#/components/Button'
import * as Dialog from '#/components/Dialog'
import * as Toggle from '#/components/forms/Toggle'
import {GradientFill} from '#/components/GradientFill'
import {Full as BlueskyPlusLogo} from '#/components/icons/BlueskyPlus'
import {ChevronRight_Stroke2_Corner0_Rounded as ChevronRightIcon} from '#/components/icons/Chevron'
import {InlineLinkText} from '#/components/Link'
import {CheckThick_Stroke2_Corner0_Rounded as CheckThink} from '#/components/icons/Check'
import {PlusLarge_Stroke2_Corner0_Rounded as Plus} from '#/components/icons/Plus'
import {Loader} from '#/components/Loader'
import {Text} from '#/components/Typography'
import {useSubscriptionGroup, usePurchaseOffering} from '#/state/purchases/subscriptions/useSubscriptionGroup'
import {OfferingId, SubscriptionGroupId} from '#/state/purchases/subscriptions/types'
import {parseOfferingId} from '#/state/purchases/subscriptions/util'
export function BlueskyPlus({
control,
}: {
control: Dialog.DialogControlProps
}) {
export function BlueskyPlus({control}: {control: Dialog.DialogControlProps}) {
return (
<Dialog.Outer control={control}>
<Dialog.Handle />
<DialogInner />
</Dialog.Outer>
)
}
function DialogInner() {
const t = useTheme()
const {_} = useLingui()
const {gtMobile} = useBreakpoints()
const {currentAccount} = useSession()
const t = useTheme()
const copy = useCoreOfferingCopy()
const [offeringId, setOfferingId] = React.useState<OfferingId>(OfferingId.CoreMonthly)
const {data: coreOffering, error} = useSubscriptionGroup(SubscriptionGroupId.Core)
const [offeringId, setOfferingId] = React.useState<OfferingId>(
OfferingId.CoreAnnual,
)
const {data: coreOffering} = useSubscriptionGroup(SubscriptionGroupId.Core)
const {mutateAsync: purchaseOffering, isPending} = usePurchaseOffering()
const onPressSubscribe = async () => {
@@ -61,209 +67,187 @@ function DialogInner() {
}
return (
<Dialog.Inner label={_(msg`Bluesky Plus`)} style={[web({maxWidth: 1000})]}>
<View style={[a.gap_xl, gtMobile && a.flex_row]}>
<View
style={[
a.flex_1,
a.gap_md,
a.rounded_xs,
a.relative,
a.overflow_hidden,
]}>
<GradientFill gradient={tokens.gradients.nordic} rotate="270deg" />
<View style={[a.px_xl, a.py_4xl, a.gap_md]}>
<MarketingBlurb />
</View>
</View>
<View style={[a.justify_end, a.gap_md]}>
<Text style={[a.font_bold, a.text_3xl]}>
<Trans>Early bird discount!</Trans>
</Text>
<Text style={[a.text_lg, a.leading_snug]}>
<Trans>Support Bluesky now and get a 25% discount for a year</Trans>
</Text>
<Toggle.Group
type="radio"
label={_(msg`Choose plan`)}
values={[offeringId]}
onChange={values => setOfferingId(parseOfferingId(values[0]))}
style={[a.w_full, a.gap_md, a.my_xl]}>
<Toggle.Item name={OfferingId.CoreMonthly} label={_(msg`Monthly plan`)}>
{({selected}) => (
<View
style={[
a.w_full,
a.p_sm,
a.rounded_sm,
a.flex_row,
a.gap_md,
a.border,
selected
? {borderColor: t.palette.primary_500}
: t.atoms.border_contrast_medium,
]}>
<Toggle.Radio />
<View style={[a.flex_1, a.gap_xs]}>
<View
style={[
a.flex_row,
a.flex_wrap,
a.justify_between,
a.gap_sm,
]}>
<Text style={[a.text_lg, a.leading_normal, a.font_bold]}>
<Trans>Monthly plan</Trans>
</Text>
<Text style={[a.text_lg, a.leading_normal, a.font_bold]}>
<Trans>$8/month</Trans>
</Text>
</View>
<Text
style={[
a.text_sm,
a.leading_normal,
t.atoms.text_contrast_medium,
]}>
<Trans>
Billed monthly, cancel anytime. $8/month after 12 months
</Trans>
</Text>
</View>
</View>
)}
</Toggle.Item>
<Toggle.Item name={OfferingId.CoreAnnual} label={_(msg`Annual plan`)}>
{({selected}) => (
<View
style={[
a.w_full,
a.p_sm,
a.rounded_sm,
a.flex_row,
a.gap_md,
a.border,
selected
? {borderColor: t.palette.primary_500}
: t.atoms.border_contrast_medium,
]}>
<Toggle.Radio />
<View style={[a.flex_1, a.gap_xs]}>
<View
style={[
a.flex_row,
a.flex_wrap,
a.justify_between,
a.gap_sm,
]}>
<Text style={[a.text_lg, a.leading_normal, a.font_bold]}>
<Trans>Annual plan</Trans>
</Text>
<Text style={[a.text_lg, a.leading_normal, a.font_bold]}>
<Trans>$80/year</Trans>
</Text>
</View>
<Text
style={[
a.text_sm,
a.leading_normal,
t.atoms.text_contrast_medium,
]}>
<Trans>Billed annually, renews at $80/year</Trans>
</Text>
</View>
</View>
)}
</Toggle.Item>
</Toggle.Group>
<Button
label={_(msg`Subscribe`)}
variant="solid"
color="primary"
size="large"
onPress={onPressSubscribe}
disabled={isPending}>
<ButtonText>
<Trans>Subscribe</Trans>
</ButtonText>
<ButtonIcon icon={isPending ? Loader : ChevronRightIcon} />
</Button>
<Text>
<InlineLinkText to="#" label="TODO REPLACE">
Terms and Conditions
</InlineLinkText>{' '}
&middot;{' '}
<InlineLinkText to="#" label="TODO REPLACE">
Privacy Policy
</InlineLinkText>{' '}
&middot;{' '}
<InlineLinkText to="#" label="TODO REPLACE">
EULA
</InlineLinkText>
</Text>
</View>
</View>
<Dialog.Close />
</Dialog.Inner>
)
}
<Dialog.ScrollableInner
label={_(msg`Bluesky Plus`)}
style={[
a.overflow_hidden,
gtMobile ? {width: '100%', maxWidth: 400, minWidth: 200} : a.w_full,
]}>
<BlueskyPlusLogo width={100} fill="nordic" />
function MarketingBlurb() {
return (
<>
<BlueskyPlusLogo width={200} fill="white" style={[a.mt_5xl]} />
<Text style={[a.text_3xl, a.font_heavy, a.pt_lg]}>
<Trans>Let's build the social web.</Trans>
</Text>
<Text style={[a.text_lg, a.leading_normal, {color: 'white'}]}>
<Text
style={[
a.text_md,
a.leading_snug,
a.pt_xs,
t.atoms.text_contrast_medium,
]}>
<Trans>
Here's the thing: we don't have any premium features yet because all
our servers are on fire. Support us now so we can put the fires out
and get working on those features!
Support Bluesky and get access to exclusive features, custom app
icons, higher video quality, and more!
</Trans>
</Text>
<Text
style={[a.text_lg, a.leading_normal, a.font_bold, {color: 'white'}]}>
<Trans>What you'll get now:</Trans>
</Text>
<View role="list" style={[a.gap_xs]}>
<Text
role="listitem"
style={[a.text_lg, a.leading_normal, {color: 'white'}]}>
{' '}
&middot; <Trans>A supporter badge on your profile</Trans>
</Text>
<Text
role="listitem"
style={[a.text_lg, a.leading_normal, {color: 'white'}]}>
{' '}
&middot; <Trans>A warm fuzzy feeling knowing you helped us out</Trans>
</Text>
<Toggle.Group
type="radio"
label={_(msg`Choose a Bluesky Plus plan`)}
values={[offeringId]}
onChange={values => setOfferingId(parseOfferingId(values[0]))}
style={[a.w_full, a.gap_sm, a.pt_lg]}>
{[OfferingId.CoreMonthly, OfferingId.CoreAnnual].map(id => {
return (
<Toggle.Item key={id} name={id} label={_(msg`Monthly plan`)}>
{({selected, hovered}) => (
<View
style={[
a.w_full,
a.p_md,
a.rounded_sm,
a.border,
a.overflow_hidden,
t.atoms.bg,
selected
? t.atoms.border_contrast_high
: t.atoms.border_contrast_low,
]}>
{Boolean(selected || hovered) && (
<GradientFill
gradient={tokens.gradients.nordic}
style={{opacity: 0.1}}
/>
)}
<View
style={[
a.flex_row,
a.justify_between,
a.align_center,
a.gap_sm,
]}>
<View style={[a.gap_xs]}>
<Text style={[a.text_lg, a.leading_tight, a.font_heavy]}>
<Trans>{copy[id].title}</Trans>
</Text>
<Text
style={[
a.text_sm,
a.leading_tight,
t.atoms.text_contrast_medium,
]}>
<Trans>{copy[id].price}</Trans>
</Text>
</View>
<View
style={[
a.flex_row,
a.justify_end,
a.align_center,
a.gap_sm,
]}>
{copy[id].discount && (
<View
style={[
a.rounded_full,
{
backgroundColor: t.atoms.text.color,
paddingVertical: 3,
paddingHorizontal: 6,
},
]}>
<Text
style={[
a.text_xs,
a.font_bold,
{
color: t.atoms.bg.backgroundColor,
},
]}>
{copy[id].discount}
</Text>
</View>
)}
<View
style={[
a.rounded_full,
a.overflow_hidden,
a.align_center,
a.justify_center,
{height: 24, width: 24},
]}>
{selected ? (
<>
<GradientFill gradient={tokens.gradients.nordic} />
<CheckThink
fill="white"
size="xs"
style={[a.z_10]}
/>
</>
) : (
<View
style={[
a.absolute,
a.inset_0,
a.border,
a.rounded_full,
t.atoms.border_contrast_low,
]}
/>
)}
</View>
</View>
</View>
</View>
)}
</Toggle.Item>
)
})}
</Toggle.Group>
<View style={[a.pt_md]}>
<Button
label={_(msg`Subscribe`)}
variant="solid"
color="secondary"
size="large"
onPress={onPressSubscribe}
disabled={isPending}
style={[a.overflow_hidden]}>
<GradientFill gradient={tokens.gradients.nordic} />
<ButtonText style={[t.atoms.text]}>
<Trans>Subscribe</Trans>
</ButtonText>
<ButtonIcon
icon={isPending ? Loader : Plus}
position="right"
style={[t.atoms.text]}
/>
</Button>
</View>
<Text
style={[a.text_lg, a.leading_normal, a.font_bold, {color: 'white'}]}>
<Trans>What you'll get soon: </Trans>
</Text>
<View role="list" style={[a.gap_xs]}>
<Text
role="listitem"
style={[a.text_lg, a.leading_normal, {color: 'white'}]}>
{' '}
&middot; <Trans>Custom profile colors</Trans>
</Text>
<Text
role="listitem"
style={[a.text_lg, a.leading_normal, {color: 'white'}]}>
{' '}
&middot; <Trans>Longer and higher quality videos</Trans>
</Text>
<Text
role="listitem"
style={[a.text_lg, a.leading_normal, {color: 'white'}]}>
{' '}
&middot; <Trans>Custom app icons</Trans>
</Text>
</View>
</>
<Dialog.Close />
</Dialog.ScrollableInner>
)
}
function useCoreOfferingCopy() {
const {_} = useLingui()
return React.useMemo(() => {
return {
[OfferingId.CoreMonthly]: {
title: _(msg`1 month`),
price: _(msg`$8 / month`),
discount: undefined,
},
[OfferingId.CoreAnnual]: {
title: _(msg`12 months`),
price: _(msg`$72 / year`),
discount: _(msg`Save 25%`),
},
}
}, [_])
}