import { Action } from "../../../../types"; import { Context, State } from "../../../overmind"; import { UserCreateRequest } from "@newstackdev/iosdk-newgraph-client-js"; import { WizardInput } from "./wizardStateMachine"; import { debounce, filter, pipe, throttle } from "overmind"; import { get, isEmpty, isNil } from "lodash"; // import { IReaction } from "overmind"; const reduceState: (st: State) => WizardInput = ({ api: { auth }, auth: { authenticated }, config: { featureFlags }, flows: { user: { create: { legacyToken, form: { username, couponCode, inviteHash, phone }, formUsernameIsAvailable, inviteHashVerified, isLegacyUpdateOngoing, metamaskFlow, }, }, }, }: State) => { return { ...auth, ...{ authenticated }, formUsername: username || "", inviteHash: inviteHash || "", subscribed: !!auth.user?.subscriptionStatus?.startsWith("io-domain-sale"), formUsernameIsAvailable, user: auth.user, formPhone: phone, inviteHashVerified, metamaskFlow, legacyToken, isLegacyUpdateOngoing, featureFlags: featureFlags, couponCode: couponCode || "", }; }; export const onInitializeOnboardingWizard: Action = async ({ actions, effects, state, reaction }) => { const legacy: { form: UserCreateRequest; legacyToken: string; updated: number; } = JSON.parse(window.localStorage.getItem("legacyAuthToken") || "{}"); if (legacy.updated && Date.now() - (legacy.updated || 0) < 30 * 60000) { // const cf = state.flows.user.create; // cf.form = legacy.form; // cf.legacyToken = legacy.legacyToken; //actions.auth.firebaseRequestToken effects.api.updateToken(legacy.legacyToken); state.firebase.token = legacy.legacyToken; await actions.api.auth.authorize(); // await actions.flows.user.create.startLegacyImport(); } if (!state.auth.authenticated && !state.api.auth.authorized && !isEmpty(state.firebase?.token)) { actions.routing.historyPush({ location: "/" }); } reaction(reduceState, actions.flows.user.create._wizardReact); reaction( (s) => ({ auth: s.api.auth, username: s.flows.user.create.form.username, legacyImportOngoing: s.flows.user.create.isLegacyUpdateOngoing, }), ({ username, auth, legacyImportOngoing }) => { if (!auth.authorized || legacyImportOngoing) actions.flows.user.create.checkAvailability({ username }); }, ); }; export const updateForm: Action> = //({ state }, val) => pipe( // debounce(200), ({ state }, val) => { state.flows.user.create.form = { ...state.flows.user.create.form, ...val, }; }, ); const usernameToAccount = (username: string) => { // adjust any string to newlife account name username = username.replace(/\.io/, "").replace(/[^a-z1-5]/g, ""); if (/^[0-9]+/.test(username)) username = "z" + username; return username.replace(/^(.{0,9})(.*)$/, (...m) => `${m[1]}.io`); }; export const startLegacyImport: Action = //({ state }, val) => async ({ state, actions }) => { const user = { ...state.api.auth.user }; // wont be available after logout const legacyToken = state.firebase.token; const username = usernameToAccount(user.username || user.displayName || ""); actions.flows.user.create.updateForm({ ...user, username, }); state.flows.user.create = { ...state.flows.user.create, legacyToken: legacyToken, legacyUsername: user.username || "", isLegacyUpdateOngoing: true, }; await actions.auth.logout({ noRouting: true }); actions.routing.historyPush({ location: "/signup/domain" }); if (window.sessionStorage.getItem("e2eTestMode") === "true") await actions.api.auth.authorize({ token: legacyToken }); window.localStorage.setItem("legacyAuthToken", JSON.stringify({ legacyToken, updated: Date.now() })); }; export const stopLegacyImport: Action<{ noRedirect?: boolean } | undefined> = (_, params = {}) => { window.localStorage.setItem("legacyAuthToken", ""); if (!params.noRedirect) window.location.pathname = "/"; }; export const wizardStepPrev: Action = ({ state }) => { state.flows.user.create.wizard.send("PREV", reduceState(state)); }; const autoRedirectFrom = ["", "/", "/auth", "/signup/auth", "/signup/domain", "/signup/create", "/signup/subscibe"]; export const _wizardReact: Action = // ({ state, actions }, i: WizardInput) => pipe(debounce(300), ({ state, actions }: Context, i: WizardInput) => { if ( state.api.auth.authorized && ["registered", "admitted"].includes(state.api.auth.user?.status || "") && !state.flows.user.create.isLegacyUpdateOngoing && state.api.auth.user?.username !== state.flows.user.create.form.username && autoRedirectFrom.includes(state.routing.location) // && // state.newcoin.pools["CGY"] ) { actions.routing.historyPush({ location: "/explore" }); } state.flows.user.create.wizard.send("UPDATE", i); const subscription = (state.api.auth.user?.subscriptionStatus || "").split(/_/); if ( subscription[0] === "io-domain-sale" && state.flows.user.create.form.username != subscription[1] && isEmpty(state.api.auth.user.username) ) { actions.flows.user.create.updateForm({ username: subscription[1] }); if (!state.flows.user.create.isLegacyUpdateOngoing && !state.api.auth.authorized) { actions.routing.historyPush({ location: "/signup/create" }); } } }); export const wizardStepNext: Action = ({ state, actions }) => { if (state.config.settings.app.name != "newlife") return; const { nextLink, hasNext, current, hasPrev } = state.flows.user.create.wizard; if (!isEmpty(state.flows.user.create.wizard.nextLink)) { actions.routing.historyPush({ location: state.flows.user.create.wizard.nextLink as string }); } state.flows.user.create.progressedSteps = state.flows.user.create.progressedSteps.filter((step) => step.current !== current); state.flows.user.create.progressedSteps.push({ nextLink, hasNext, current, hasPrev }); state.flows.user.create.wizard.send("NEXT", reduceState(state)); state.flows.user.create.wizard.send("UPDATE", reduceState(state)); }; export const preregisterCreate: Action<{ noRouting?: boolean; user?: UserCreateRequest; }> = async ({ actions }, params) => { const u = params.user || ({} as UserCreateRequest); return actions.api.user.create({ ...params, user: u, preregisterCreate: true, }); }; export const create: Action<{ noRouting?: boolean; user: UserCreateRequest; }> = async ({ actions }, params) => { const u = await actions.api.user.create({ ...params }); actions.flows.user.create.stopLegacyImport({ noRedirect: true }); }; export const checkAvailability: Action<{ username?: string }> = pipe( // filter((_, { username }) => username.length > 6), debounce(300), async ({ actions, state }: Context, { username }) => { if (!username) { state.flows.user.create.formUsernameIsAvailable = ""; return; } state.flows.user.create.formUsernameIsAvailable = "checking"; // const promises = [ // state.api.client.user.availabilityList({ username }), // actions.newcoin.getAccountHitory({ user: { username } }) // ]; // const [r, nc] = await Promise.all(promises); //actions.flows.user.create._userCreate({ ...params }); const r = await state.api.client.user.availabilityList({ username }); const currUser = state.api.auth.user; const isOpenSeaOffer = !isEmpty(r.data?.offer); const availableOnNewlife = r.data?.available || (currUser?.username === username && currUser.status === "imported") || state.api.auth.user.newcoinAccTx; // const availableOnNewcoin = nc?.statusCode === 500; state.flows.user.create.formUsernameIsAvailable = availableOnNewlife ? isOpenSeaOffer ? "availableOnOpenSea" : state.flows.user.create.metamaskFlow ? "unavailable" : "available" : "unavailable"; // && availableOnNewcoin }, ); export const verifyHash: Action<{ inviteHash: string }> = pipe(async ({ state, actions, effects }: Context, { inviteHash }) => { try { const res = (await state.api.client.user.inviteHashList({ hash: inviteHash })).data; if (res) { if (!/^\+/.test((res as any).phone)) (res as any).phone = "+" + (res as any).phone; state.flows.user.create.inviteHashVerified = true; //@ts-ignore actions.flows.user.create.updateForm({ ...res }); actions.flows.user.create.wizardStepNext(); } } catch (e) { effects.ux.notification.error({ message: "Something went wrong, please try again", }); actions.routing.historyPush({ location: "/signup/notInvited" }); } }); export const startMetamaskFlow: Action<{}> = pipe(async ({ state, actions }: Context) => { state.flows.user.create.metamaskFlow = true; actions.routing.historyPush({ location: "/signup/auth" }); }); export const stopMetamaskFlow: Action = pipe(async ({ state }: Context) => { state.flows.user.create.metamaskFlow = false; }); export const bypassInviteFlow: Action<{ couponCode: string }> = pipe(async ({ state, actions }, { couponCode }) => { actions.flows.user.create.updateForm({ couponCode }); state.flows.user.create.inviteHashVerified = true; actions.flows.user.create.wizardStepNext(); });