import React from 'react' import {TouchableOpacity, View} from 'react-native' import { KeyboardAwareScrollView, useKeyboardController, } from 'react-native-keyboard-controller' import {AppBskyGraphDefs, AtUri} from '@atproto/api' import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' import {msg, Trans} from '@lingui/macro' import {useLingui} from '@lingui/react' import {useFocusEffect, useNavigation} from '@react-navigation/native' import {NativeStackScreenProps} from '@react-navigation/native-stack' import {HITSLOP_10} from '#/lib/constants' import {CommonNavigatorParams, NavigationProp} from '#/lib/routes/types' import {parseStarterPackUri} from '#/lib/strings/starter-pack' import {logger} from '#/logger' import {isAndroid, isWeb} from '#/platform/detection' import {useModerationOpts} from '#/state/preferences/moderation-opts' import {useCreateFeedMutation} from '#/state/queries/feed' import {useAllListMembersQuery} from '#/state/queries/list-members' import {useProfileQuery} from '#/state/queries/profile' import { useEditStarterPackMutation, useStarterPackQuery, } from '#/state/queries/starter-packs' import {useSession} from '#/state/session' import {useSetMinimalShellMode} from '#/state/shell' import * as Toast from '#/view/com/util/Toast' import {CenteredView} from '#/view/com/util/Views' import {atoms as a, useTheme} from '#/alf' import {Button, ButtonText} from '#/components/Button' import * as Layout from '#/components/Layout' import {ListMaybePlaceholder} from '#/components/Lists' import {Text} from '#/components/Typography' import {useWizardState, WizardStep} from './State' import {Provider} from './State' import {StepDetails} from './StepDetails' export function Wizard({ route, }: NativeStackScreenProps) { const {rkey} = route.params ?? {} const {currentAccount} = useSession() const moderationOpts = useModerationOpts() const {_} = useLingui() const { data: starterPack, isLoading: isLoadingStarterPack, isError: isErrorStarterPack, } = useStarterPackQuery({did: currentAccount!.did, rkey}) const listUri = starterPack?.list?.uri const { data: listItems, isLoading: isLoadingProfiles, isError: isErrorProfiles, } = useAllListMembersQuery(listUri) const { data: profile, isLoading: isLoadingProfile, isError: isErrorProfile, } = useProfileQuery({did: currentAccount?.did}) const isEdit = Boolean(rkey) const isReady = (!isEdit || (isEdit && starterPack && listItems)) && profile && moderationOpts if (!isReady) { return ( ) } else if (isEdit && starterPack?.creator.did !== currentAccount?.did) { return ( ) } return ( ) } function WizardInner({ currentStarterPack, currentListItems, }: { currentStarterPack?: AppBskyGraphDefs.StarterPackView currentListItems?: AppBskyGraphDefs.ListItemView[] }) { const navigation = useNavigation() const {_} = useLingui() const t = useTheme() const setMinimalShellMode = useSetMinimalShellMode() const {setEnabled} = useKeyboardController() const [state, dispatch] = useWizardState() const {currentAccount} = useSession() const parsed = parseStarterPackUri(currentStarterPack?.uri) React.useEffect(() => { navigation.setOptions({ gestureEnabled: false, }) }, [navigation]) useFocusEffect( React.useCallback(() => { setEnabled(true) setMinimalShellMode(true) return () => { setMinimalShellMode(false) setEnabled(false) } }, [setMinimalShellMode, setEnabled]), ) const getDefaultName = () => { return _(msg`Your feed name`) } const wizardUiStrings: Record< WizardStep, {header: string; nextBtn: string; subtitle?: string} > = { Details: { header: _(msg`Create a Feed`), nextBtn: _(msg`Finish`), }, } const currUiStrings = wizardUiStrings[state.currentStep] const onSuccessCreate = (data: {uri: string; cid: string}) => { const rkey = new AtUri(data.uri).rkey dispatch({type: 'SetProcessing', processing: false}) navigation.replace('ProfileFeed', { name: currentAccount!.handle, rkey, }) } const onSuccessEdit = () => { if (navigation.canGoBack()) { navigation.goBack() } else { navigation.replace('ProfileFeed', { name: currentAccount!.handle, rkey: parsed!.rkey, }) } } const {mutate: createFeed} = useCreateFeedMutation({ onSuccess: onSuccessCreate, onError: e => { logger.error('Failed to create starter pack', {safeMessage: e}) dispatch({type: 'SetProcessing', processing: false}) Toast.show(_(msg`Failed to create starter pack`), 'xmark') }, }) // TODO const {mutate: editStarterPack} = useEditStarterPackMutation({ onSuccess: onSuccessEdit, onError: e => { logger.error('Failed to edit starter pack', {safeMessage: e}) dispatch({type: 'SetProcessing', processing: false}) Toast.show(_(msg`Failed to create starter pack`), 'xmark') }, }) const submit = async () => { dispatch({type: 'SetProcessing', processing: true}) if (currentStarterPack && currentListItems) { editStarterPack({ name: state.name?.trim() || getDefaultName(), description: state.description?.trim(), profiles: state.profiles, feeds: state.feeds, currentStarterPack: currentStarterPack, currentListItems: currentListItems, }) } else { createFeed({ name: state.name?.trim() || getDefaultName(), description: state.description?.trim(), }) } } return ( { if (state.currentStep === 'Details') { navigation.pop() } else { dispatch({type: 'Back'}) } }}> {currUiStrings.header} {state.currentStep === 'Details' ? : null} ) } function Container({ children, onFinish, }: { children: React.ReactNode onFinish: () => void }) { const {_} = useLingui() const [state] = useWizardState() return ( {children} {state.currentStep === 'Details' && ( <> )} ) }