import { ContinueWith, RecoveryFlow, UpdateRecoveryFlowBody } from "@ory/client" import { useFocusEffect } from "@react-navigation/native" import { StackScreenProps } from "@react-navigation/stack" import React, { useCallback, useContext, useState } from "react" import AuthLayout from "../Layout/AuthLayout" import ProjectPicker from "../Layout/ProjectPicker" import { RootStackParamList } from "../Navigation" import { SelfServiceFlow } from "../Ory/Ui" import { ProjectContext } from "../ProjectProvider" import AuthSubTitle from "../Styled/AuthSubTitle" import StyledCard from "../Styled/StyledCard" import { AuthContext } from "../AuthProvider" import NavigationCard from "../Styled/NavigationCard" import { handleFormSubmitError } from "../../helpers/form" import { logSDKError } from "../../helpers/axios" import axios from "axios" type Props = StackScreenProps function collectRecoveryActions(items?: ContinueWith[]) { return items?.reduce( (acc, curr) => { switch (curr.action) { case "show_settings_ui": return { ...acc, settingsFlowId: curr.flow.id } case "set_ory_session_token": { return { ...acc, sessionToken: curr.ory_session_token } } case "show_recovery_ui": { return { ...acc, recoveryFlowId: curr.flow.id } } } return acc }, { settingsFlowId: "", sessionToken: "", recoveryFlowId: "" }, ) } export default function Recovery({ navigation }: Props) { const [flow, setFlow] = useState(undefined) const { setSession, syncSession } = useContext(AuthContext) const { sdk } = useContext(ProjectContext) async function initializeFlow(): Promise { await sdk .createNativeRecoveryFlow() .then(({ data: flow }) => flow) .then(setFlow) .catch(logSDKError) } useFocusEffect( useCallback(() => { initializeFlow() return () => { setFlow(undefined) } }, [sdk]), ) const handleContinueWith = async (c: ContinueWith[]): Promise => { const actions = collectRecoveryActions(c) if (actions?.recoveryFlowId) { const { data: flow } = await sdk.getRecoveryFlow({ id: actions.recoveryFlowId, }) setFlow(flow) } } const onSubmit = async (body: UpdateRecoveryFlowBody) => { if (!flow) { console.error("No flow!") return } try { const { data: updatedFlow } = await sdk.updateRecoveryFlow({ flow: flow?.id, updateRecoveryFlowBody: body, }) if (updatedFlow.state === "passed_challenge") { const actions = collectRecoveryActions(updatedFlow.continue_with) if (actions?.sessionToken) { const { data: session } = await sdk.toSession({ xSessionToken: actions.sessionToken, }) setSession({ session, session_token: actions.sessionToken }) await syncSession() navigation.navigate("Settings", { flowId: actions.settingsFlowId, }) } } else { setFlow(updatedFlow) } } catch (err: unknown) { if (axios.isAxiosError(err)) { handleFormSubmitError( flow, setFlow, initializeFlow, () => {}, async () => {}, () => {}, handleContinueWith, )(err) } } } return ( Recover access to your account navigation.navigate("Recovery")} /> ) }