From 34453630315cad30f7b783ad5deea682d9d132fd Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Thu, 21 Nov 2024 12:55:05 -0600 Subject: [PATCH] NUX right nav, fix SVGs --- src/components/dialogs/BlueskyPlus/index.tsx | 4 +- src/components/dialogs/nuxs/index.tsx | 17 ++-- src/components/icons/BlueskyPlus.tsx | 59 +++----------- src/screens/Subscriptions/index.tsx | 21 +---- src/state/queries/nuxs/definitions.ts | 6 +- src/state/queries/nuxs/index.ts | 55 ++++++++++--- src/view/shell/desktop/RightNav.tsx | 85 ++++++++++++++++---- 7 files changed, 140 insertions(+), 107 deletions(-) diff --git a/src/components/dialogs/BlueskyPlus/index.tsx b/src/components/dialogs/BlueskyPlus/index.tsx index 3686733676..27c83d55dc 100644 --- a/src/components/dialogs/BlueskyPlus/index.tsx +++ b/src/components/dialogs/BlueskyPlus/index.tsx @@ -91,9 +91,9 @@ function DialogInner({control}: {control: Dialog.DialogControlProps}) { a.overflow_hidden, gtMobile ? {width: '100%', maxWidth: 400, minWidth: 200} : a.w_full, ]}> - + - + Let's build the social web. diff --git a/src/components/dialogs/nuxs/index.tsx b/src/components/dialogs/nuxs/index.tsx index 701ae84e69..11d622a4dc 100644 --- a/src/components/dialogs/nuxs/index.tsx +++ b/src/components/dialogs/nuxs/index.tsx @@ -3,12 +3,7 @@ import {AppBskyActorDefs} from '@atproto/api' import {useGate} from '#/lib/statsig/statsig' import {logger} from '#/logger' -import { - Nux, - useNuxs, - useRemoveNuxsMutation, - useUpsertNuxMutation, -} from '#/state/queries/nuxs' +import {Nux, useNuxs, useResetNuxs, useSaveNux} from '#/state/queries/nuxs' import { usePreferencesQuery, UsePreferencesQueryResponse, @@ -85,8 +80,8 @@ function Inner({ return isSnoozed() }) const [activeNux, setActiveNux] = React.useState() - const {mutateAsync: upsertNux} = useUpsertNuxMutation() - const {mutate: removeNuxs} = useRemoveNuxsMutation() + const {mutateAsync: saveNux} = useSaveNux() + const {mutate: resetNuxs} = useResetNuxs() const snoozeNuxDialog = React.useCallback(() => { snooze() @@ -102,7 +97,7 @@ function Inner({ // @ts-ignore window.clearNuxDialog = (id: Nux) => { if (!IS_DEV || !id) return - removeNuxs([id]) + resetNuxs([id]) unsnooze() } } @@ -136,7 +131,7 @@ function Inner({ snoozeNuxDialog() // immediately update remote data (affects next reload) - upsertNux({ + saveNux({ id, completed: true, data: undefined, @@ -152,7 +147,7 @@ function Inner({ nuxs, snoozed, snoozeNuxDialog, - upsertNux, + saveNux, gate, currentAccount, currentProfile, diff --git a/src/components/icons/BlueskyPlus.tsx b/src/components/icons/BlueskyPlus.tsx index f5da7ff0b1..3261aa5e2e 100644 --- a/src/components/icons/BlueskyPlus.tsx +++ b/src/components/icons/BlueskyPlus.tsx @@ -1,34 +1,15 @@ -import React from 'react' -import {StyleSheet, TextProps} from 'react-native' -import Svg, { - Defs, - LinearGradient, - Path, - PathProps, - Stop, - SvgProps, -} from 'react-native-svg' +import Svg, {Path} from 'react-native-svg' import {msg} from '@lingui/macro' import {useLingui} from '@lingui/react' -import {useTheme} from '#/alf' - -type Props = { - fill?: PathProps['fill'] - style?: TextProps['style'] -} & Omit +import {Props, useCommonSVGProps} from '#/components/icons/common' /** * Full Bluesky+ logo with butterfly */ export function Full(props: Props) { - const t = useTheme() - const {fill, ...rest} = props - const gradient = fill === 'nordic' - const styles = StyleSheet.flatten(props.style) - const _fill = gradient - ? 'url(#nordic)' - : fill || styles?.color || t.palette.primary_500 + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const {fill, size: _size, style, gradient, ...rest} = useCommonSVGProps(props) // @ts-ignore it's fiiiiine const size = parseInt(rest.width || 100) const ratio = 90 / 448 @@ -41,10 +22,10 @@ export function Full(props: Props) { accessibilityLabel={_(msg`Bluesky Plus`)} accessibilityHint="" {...rest} - style={[styles, {width: size, height: size * ratio}]}> - {gradient && } + style={[style, {width: size, height: size * ratio}]}> + {gradient} - {gradient && } + style={[style, {width: size, height: size * ratio}]}> + {gradient} ) } - -function Gradients() { - return ( - - - - - - - ) -} diff --git a/src/screens/Subscriptions/index.tsx b/src/screens/Subscriptions/index.tsx index 2e2d92d627..e2c2ba8e28 100644 --- a/src/screens/Subscriptions/index.tsx +++ b/src/screens/Subscriptions/index.tsx @@ -1,16 +1,15 @@ -import React from 'react' import {View} from 'react-native' import {msg, Trans} from '@lingui/macro' import {useLingui} from '@lingui/react' import {NativeStackScreenProps} from '@react-navigation/native-stack' import {CommonNavigatorParams} from '#/lib/routes/types' -import {PurchasesState,usePurchases} from '#/state/purchases' +import {PurchasesState, usePurchases} from '#/state/purchases' import {useManageSubscription} from '#/state/purchases/hooks/useManageSubscription' import {SubscriptionGroupId} from '#/state/purchases/types' import {APISubscription} from '#/state/purchases/types' import {CenteredView} from '#/view/com/util/Views' -import {atoms as a, tokens,useTheme} from '#/alf' +import {atoms as a, tokens, useTheme} from '#/alf' import {Admonition} from '#/components/Admonition' import {Button, ButtonIcon, ButtonText} from '#/components/Button' import {useDialogControl} from '#/components/Dialog' @@ -23,7 +22,7 @@ import {Clock_Stroke2_Corner0_Rounded as Clock} from '#/components/icons/Clock' import {PlusLarge_Stroke2_Corner0_Rounded as Plus} from '#/components/icons/Plus' import {SettingsGear2_Stroke2_Corner0_Rounded as Gear} from '#/components/icons/SettingsGear2' import * as Layout from '#/components/Layout' -import {createStaticClick,InlineLinkText, Link} from '#/components/Link' +import {createStaticClick, InlineLinkText, Link} from '#/components/Link' import {Loader} from '#/components/Loader' import {Text} from '#/components/Typography' @@ -69,7 +68,6 @@ function Core({ s => s.group === SubscriptionGroupId.Core, ) const isSubscribedToCore = !!coreSubscriptions.length - console.log(state) const features = [ { @@ -116,7 +114,7 @@ function Core({ return ( - + {isSubscribedToCore ? ( @@ -246,17 +244,6 @@ function Core({ EULA - - - - Learn more about Bluesky+ and our roadmap{' '} - - here - - - ) diff --git a/src/state/queries/nuxs/definitions.ts b/src/state/queries/nuxs/definitions.ts index 8166602c8a..0558fbf155 100644 --- a/src/state/queries/nuxs/definitions.ts +++ b/src/state/queries/nuxs/definitions.ts @@ -3,16 +3,16 @@ import zod from 'zod' import {BaseNux} from '#/state/queries/nuxs/types' export enum Nux { - NeueTypography = 'NeueTypography', + BlueskyPlus_Core_RightNav = 'BlueskyPlus_Core_RightNav', } export const nuxNames = new Set(Object.values(Nux)) export type AppNux = BaseNux<{ - id: Nux.NeueTypography + id: Nux.BlueskyPlus_Core_RightNav data: undefined }> export const NuxSchemas: Record | undefined> = { - [Nux.NeueTypography]: undefined, + [Nux.BlueskyPlus_Core_RightNav]: undefined, } diff --git a/src/state/queries/nuxs/index.ts b/src/state/queries/nuxs/index.ts index 94c1242301..6ad59c7a46 100644 --- a/src/state/queries/nuxs/index.ts +++ b/src/state/queries/nuxs/index.ts @@ -10,49 +10,78 @@ import {useAgent} from '#/state/session' export {Nux} from '#/state/queries/nuxs/definitions' -export function useNuxs() { - const {data, isSuccess} = usePreferencesQuery() +export function useNuxs(): + | { + nuxs: AppNux[] + status: 'ready' + } + | { + nuxs: undefined + status: 'loading' | 'error' + } { + const {data, isSuccess, isError} = usePreferencesQuery() + const status = isSuccess ? 'ready' : isError ? 'error' : 'loading' - if (data && isSuccess) { - const nuxs = data.bskyAppState.nuxs + if (status === 'ready') { + const nuxs = data?.bskyAppState?.nuxs ?.map(parseAppNux) ?.filter(Boolean) as AppNux[] if (nuxs) { return { nuxs, - isSuccess, + status, + } + } else { + return { + nuxs: [], + status, } } } return { nuxs: undefined, - isSuccess, + status, } } -export function useNux(id: T) { - const {nuxs, isSuccess} = useNuxs() +export function useNux( + id: T, +): + | { + nux: Extract | undefined + status: 'ready' + } + | { + nux: undefined + status: 'loading' | 'error' + } { + const {nuxs, status} = useNuxs() - if (nuxs && isSuccess) { + if (status === 'ready') { const nux = nuxs.find(nux => nux.id === id) if (nux) { return { nux: nux as Extract, - isSuccess, + status, + } + } else { + return { + nux: undefined, + status, } } } return { nux: undefined, - isSuccess, + status, } } -export function useUpsertNuxMutation() { +export function useSaveNux() { const queryClient = useQueryClient() const agent = useAgent() @@ -68,7 +97,7 @@ export function useUpsertNuxMutation() { }) } -export function useRemoveNuxsMutation() { +export function useResetNuxs() { const queryClient = useQueryClient() const agent = useAgent() diff --git a/src/view/shell/desktop/RightNav.tsx b/src/view/shell/desktop/RightNav.tsx index 354f549db2..6c7a8157b7 100644 --- a/src/view/shell/desktop/RightNav.tsx +++ b/src/view/shell/desktop/RightNav.tsx @@ -8,6 +8,7 @@ import {useWebMediaQueries} from '#/lib/hooks/useWebMediaQueries' import {useKawaiiMode} from '#/state/preferences/kawaii' import {usePurchases} from '#/state/purchases' import {EntitlementId} from '#/state/purchases/types' +import {Nux, useNux, useResetNuxs,useSaveNux} from '#/state/queries/nuxs' import {useSession} from '#/state/session' import {DesktopFeeds} from '#/view/shell/desktop/Feeds' import {DesktopSearch} from '#/view/shell/desktop/Search' @@ -19,21 +20,53 @@ import {Divider} from '#/components/Divider' import {GradientFill} from '#/components/GradientFill' import {Full as BlueskyPlusLogo} from '#/components/icons/BlueskyPlus' import {SquareArrowTopRight_Stroke2_Corner0_Rounded as SquareArrowTopRight} from '#/components/icons/SquareArrowTopRight' -import {InlineLinkText} from '#/components/Link' +import {createStaticClick,InlineLinkText} from '#/components/Link' import {ProgressGuideList} from '#/components/ProgressGuide/List' import {Text} from '#/components/Typography' +import {IS_DEV} from '#/env' export function DesktopRightNav({routeName}: {routeName: string}) { const t = useTheme() const {_} = useLingui() const {hasSession, currentAccount} = useSession() - const subscriptionsDialogControl = useDialogControl() - const purchases = usePurchases() - const isSubscribed = - purchases.status === 'ready' && - purchases.entitlements?.some(e => e.id === EntitlementId.Core) - const kawaii = useKawaiiMode() + const bskyPlusDialogControl = useDialogControl() + + const {mutateAsync: resetNuxs} = useResetNuxs() + const nux = useNux(Nux.BlueskyPlus_Core_RightNav) + const {mutateAsync: saveNux} = useSaveNux() + const purchases = usePurchases() + const [hideNux, setHideNux] = React.useState(false) + const bskyPlusNux = React.useMemo(() => { + const purchasesReady = purchases.status === 'ready' + const nuxReady = nux.status === 'ready' + const ready = purchasesReady && nuxReady + const subscribed = + purchasesReady && + purchases.entitlements.some(e => e.id === EntitlementId.Core) + const nuxSeen = Boolean(nuxReady && nux.nux) + const active = !ready + ? false + : subscribed || nuxSeen + ? false + : hideNux + ? false + : true + return { + active, + nuxSeen, + } + }, [hideNux, nux, purchases]) + + const onPressBlueskyPlusNux = () => { + setHideNux(true) + bskyPlusDialogControl.open() + saveNux({ + id: Nux.BlueskyPlus_Core_RightNav, + completed: true, + data: undefined, + }).catch(_e => {}) + } const {isTablet} = useWebMediaQueries() if (isTablet) { @@ -72,11 +105,10 @@ export function DesktopRightNav({routeName}: {routeName: string}) { )} - {/* TODO NUX this */} - {!isSubscribed && ( + {bskyPlusNux.active ? ( - + ) : ( + <> + {bskyPlusNux.nuxSeen && IS_DEV && ( + + + Dev only:{' '} + { + setHideNux(false) + resetNuxs([Nux.BlueskyPlus_Core_RightNav]) + })}> + reset Bluesky+ NUX + + + + )} + )} + + {hasSession && ( <>