Submit fix (#4978)

* Fix submit logic

* Fix type

* Align submit task creation 1:1 with callsites

* blegh. `useThrottledValue`

* make `useThrottledValue`'s time required

---------

Co-authored-by: Hailey <me@haileyok.com>
zio/stable
dan 2024-08-22 22:43:23 +01:00 committed by GitHub
parent df5bf28e61
commit 27bb383268
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 46 additions and 32 deletions

View File

@ -2,7 +2,7 @@ import {useEffect, useRef, useState} from 'react'
import {useNonReactiveCallback} from '#/lib/hooks/useNonReactiveCallback'
export function useThrottledValue<T>(value: T, time?: number) {
export function useThrottledValue<T>(value: T, time: number) {
const pendingValueRef = useRef(value)
const [throttledValue, setThrottledValue] = useState(value)

View File

@ -8,7 +8,7 @@ import {createFullHandle} from '#/lib/strings/handles'
import {logger} from '#/logger'
import {logEvent} from 'lib/statsig/statsig'
import {ScreenTransition} from '#/screens/Login/ScreenTransition'
import {useSignupContext, useSubmitSignup} from '#/screens/Signup/state'
import {useSignupContext} from '#/screens/Signup/state'
import {CaptchaWebView} from '#/screens/Signup/StepCaptcha/CaptchaWebView'
import {atoms as a, useTheme} from '#/alf'
import {FormError} from '#/components/forms/FormError'
@ -20,7 +20,6 @@ export function StepCaptcha() {
const {_} = useLingui()
const theme = useTheme()
const {state, dispatch} = useSignupContext()
const submit = useSubmitSignup({state, dispatch})
const [completed, setCompleted] = React.useState(false)
@ -42,9 +41,13 @@ export function StepCaptcha() {
(code: string) => {
setCompleted(true)
logEvent('signup:captchaSuccess', {})
submit(code)
const submitTask = {code, mutableProcessed: false}
dispatch({
type: 'submit',
task: submitTask,
})
},
[submit],
[dispatch],
)
const onError = React.useCallback(

View File

@ -7,9 +7,10 @@ import {logEvent} from '#/lib/statsig/statsig'
import {createFullHandle, validateHandle} from '#/lib/strings/handles'
import {useAgent} from '#/state/session'
import {ScreenTransition} from '#/screens/Login/ScreenTransition'
import {useSignupContext, useSubmitSignup} from '#/screens/Signup/state'
import {useSignupContext} from '#/screens/Signup/state'
import {atoms as a, useTheme} from '#/alf'
import * as TextField from '#/components/forms/TextField'
import {useThrottledValue} from '#/components/hooks/useThrottledValue'
import {At_Stroke2_Corner0_Rounded as At} from '#/components/icons/At'
import {Check_Stroke2_Corner0_Rounded as Check} from '#/components/icons/Check'
import {TimesLarge_Stroke2_Corner0_Rounded as Times} from '#/components/icons/Times'
@ -20,10 +21,10 @@ export function StepHandle() {
const {_} = useLingui()
const t = useTheme()
const {state, dispatch} = useSignupContext()
const submit = useSubmitSignup({state, dispatch})
const agent = useAgent()
const handleValueRef = useRef<string>(state.handle)
const [draftValue, setDraftValue] = React.useState(state.handle)
const isLoading = useThrottledValue(state.isLoading, 500)
const onNextPress = React.useCallback(async () => {
const handle = handleValueRef.current.trim()
@ -64,7 +65,8 @@ export function StepHandle() {
})
// phoneVerificationRequired is actually whether a captcha is required
if (!state.serviceDescription?.phoneVerificationRequired) {
submit()
const submitTask = {code: undefined, mutableProcessed: false}
dispatch({type: 'submit', task: submitTask})
return
}
dispatch({type: 'next'})
@ -74,7 +76,6 @@ export function StepHandle() {
state.activeStep,
state.serviceDescription?.phoneVerificationRequired,
state.userDomain,
submit,
agent,
])
@ -175,7 +176,7 @@ export function StepHandle() {
)}
</View>
<BackNextButtons
isLoading={state.isLoading}
isLoading={isLoading}
isNextDisabled={!validCheck.overall}
onBackPress={onBackPress}
onNextPress={onNextPress}

View File

@ -16,6 +16,7 @@ import {
reducer,
SignupContext,
SignupStep,
useSubmitSignup,
} from '#/screens/Signup/state'
import {StepCaptcha} from '#/screens/Signup/StepCaptcha'
import {StepHandle} from '#/screens/Signup/StepHandle'
@ -33,6 +34,7 @@ export function Signup({onPressBack}: {onPressBack: () => void}) {
const {screen} = useAnalytics()
const [state, dispatch] = React.useReducer(reducer, initialState)
const {gtMobile} = useBreakpoints()
const submit = useSubmitSignup()
const activeStarterPack = useActiveStarterPack()
const {
@ -81,6 +83,15 @@ export function Signup({onPressBack}: {onPressBack: () => void}) {
}
}, [_, serviceInfo, isError])
React.useEffect(() => {
if (state.pendingSubmit) {
if (!state.pendingSubmit.mutableProcessed) {
state.pendingSubmit.mutableProcessed = true
submit(state, dispatch)
}
}
}, [state, dispatch, submit])
return (
<SignupContext.Provider value={{state, dispatch}}>
<LoggedOutLayout

View File

@ -26,6 +26,11 @@ export enum SignupStep {
CAPTCHA,
}
type SubmitTask = {
code: string | undefined
mutableProcessed: boolean // OK to mutate assuming it's never read in render.
}
export type SignupState = {
hasPrev: boolean
activeStep: SignupStep
@ -41,6 +46,8 @@ export type SignupState = {
error: string
isLoading: boolean
pendingSubmit: null | SubmitTask
}
export type SignupAction =
@ -58,6 +65,7 @@ export type SignupAction =
| {type: 'setVerificationCode'; value: string}
| {type: 'setError'; value: string}
| {type: 'setIsLoading'; value: boolean}
| {type: 'submit'; task: SubmitTask}
export const initialState: SignupState = {
hasPrev: false,
@ -74,6 +82,8 @@ export const initialState: SignupState = {
error: '',
isLoading: false,
pendingSubmit: null,
}
export function is13(date: Date) {
@ -149,6 +159,10 @@ export function reducer(s: SignupState, a: SignupAction): SignupState {
next.error = a.value
break
}
case 'submit': {
next.pendingSubmit = a.task
break
}
}
next.hasPrev = next.activeStep !== SignupStep.INFO
@ -169,19 +183,17 @@ interface IContext {
export const SignupContext = React.createContext<IContext>({} as IContext)
export const useSignupContext = () => React.useContext(SignupContext)
export function useSubmitSignup({
state,
dispatch,
}: {
state: SignupState
dispatch: (action: SignupAction) => void
}) {
export function useSubmitSignup() {
const {_} = useLingui()
const {createAccount} = useSessionApi()
const onboardingDispatch = useOnboardingDispatch()
return useCallback(
async (verificationCode?: string) => {
async (
state: SignupState,
dispatch: (action: SignupAction) => void,
verificationCode?: string,
) => {
if (!state.email) {
dispatch({type: 'setStep', value: SignupStep.INFO})
return dispatch({
@ -270,19 +282,6 @@ export function useSubmitSignup({
dispatch({type: 'setIsLoading', value: false})
}
},
[
state.email,
state.password,
state.handle,
state.serviceDescription?.phoneVerificationRequired,
state.serviceUrl,
state.userDomain,
state.inviteCode,
state.dateOfBirth,
dispatch,
_,
onboardingDispatch,
createAccount,
],
[_, onboardingDispatch, createAccount],
)
}