improvements, metrics
This commit is contained in:
@@ -70,6 +70,7 @@ export type MetricEvents = {
|
|||||||
'signup:handleTaken': {typeahead?: boolean}
|
'signup:handleTaken': {typeahead?: boolean}
|
||||||
'signup:handleReserved': {typeahead?: boolean}
|
'signup:handleReserved': {typeahead?: boolean}
|
||||||
'signup:handleAvailable': {typeahead?: boolean}
|
'signup:handleAvailable': {typeahead?: boolean}
|
||||||
|
'signup:handleSuggestionSelected': {method: string}
|
||||||
'signin:hostingProviderPressed': {
|
'signin:hostingProviderPressed': {
|
||||||
hostingProviderDidChange: boolean
|
hostingProviderDidChange: boolean
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
import {useState} from 'react'
|
import {useState} from 'react'
|
||||||
import {View} from 'react-native'
|
import {View} from 'react-native'
|
||||||
import Animated, {
|
import Animated, {
|
||||||
|
Easing,
|
||||||
FadeIn,
|
FadeIn,
|
||||||
FadeInDown,
|
FadeInDown,
|
||||||
FadeOut,
|
FadeOut,
|
||||||
FadeOutDown,
|
|
||||||
LayoutAnimationConfig,
|
LayoutAnimationConfig,
|
||||||
LinearTransition,
|
LinearTransition,
|
||||||
} from 'react-native-reanimated'
|
} from 'react-native-reanimated'
|
||||||
@@ -42,7 +42,10 @@ export function StepHandle() {
|
|||||||
|
|
||||||
const validCheck = validateServiceHandle(draftValue, state.userDomain)
|
const validCheck = validateServiceHandle(draftValue, state.userDomain)
|
||||||
|
|
||||||
const {data: isHandleAvailable, isLoading} = useHandleAvailabilityQuery({
|
const {
|
||||||
|
enabled: queryEnabled,
|
||||||
|
query: {data: isHandleAvailable, isPending},
|
||||||
|
} = useHandleAvailabilityQuery({
|
||||||
username: draftValue,
|
username: draftValue,
|
||||||
serviceDid: state.serviceDescription?.did ?? 'UNKNOWN',
|
serviceDid: state.serviceDescription?.did ?? 'UNKNOWN',
|
||||||
serviceDomain: state.userDomain,
|
serviceDomain: state.userDomain,
|
||||||
@@ -121,7 +124,10 @@ export function StepHandle() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const textFieldInvalid =
|
const textFieldInvalid =
|
||||||
(!isLoading && isHandleAvailable && !isHandleAvailable.available) ||
|
(!isPending &&
|
||||||
|
queryEnabled &&
|
||||||
|
isHandleAvailable &&
|
||||||
|
!isHandleAvailable.available) ||
|
||||||
!validCheck.frontLengthNotTooLong ||
|
!validCheck.frontLengthNotTooLong ||
|
||||||
!validCheck.handleChars ||
|
!validCheck.handleChars ||
|
||||||
!validCheck.hyphenStartOrEnd ||
|
!validCheck.hyphenStartOrEnd ||
|
||||||
@@ -129,7 +135,7 @@ export function StepHandle() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<ScreenTransition>
|
<ScreenTransition>
|
||||||
<View style={[a.gap_sm, a.pt_lg]}>
|
<View style={[a.gap_sm, a.pt_lg, a.z_10]}>
|
||||||
<View>
|
<View>
|
||||||
<TextField.Root isInvalid={textFieldInvalid}>
|
<TextField.Root isInvalid={textFieldInvalid}>
|
||||||
<TextField.Icon icon={AtIcon} />
|
<TextField.Icon icon={AtIcon} />
|
||||||
@@ -142,7 +148,7 @@ export function StepHandle() {
|
|||||||
setDraftValue(val)
|
setDraftValue(val)
|
||||||
}}
|
}}
|
||||||
label={state.userDomain}
|
label={state.userDomain}
|
||||||
defaultValue={draftValue}
|
value={draftValue}
|
||||||
keyboardType="ascii-capable" // fix for iOS replacing -- with —
|
keyboardType="ascii-capable" // fix for iOS replacing -- with —
|
||||||
autoCapitalize="none"
|
autoCapitalize="none"
|
||||||
autoCorrect={false}
|
autoCorrect={false}
|
||||||
@@ -166,7 +172,8 @@ export function StepHandle() {
|
|||||||
<RequirementText>{state.error}</RequirementText>
|
<RequirementText>{state.error}</RequirementText>
|
||||||
</Requirement>
|
</Requirement>
|
||||||
)}
|
)}
|
||||||
{isHandleAvailable &&
|
{queryEnabled &&
|
||||||
|
isHandleAvailable &&
|
||||||
!isHandleAvailable.available &&
|
!isHandleAvailable.available &&
|
||||||
validCheck.overall && (
|
validCheck.overall && (
|
||||||
<>
|
<>
|
||||||
@@ -189,7 +196,9 @@ export function StepHandle() {
|
|||||||
state.userDomain.length * -1,
|
state.userDomain.length * -1,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
// TODO: add logging
|
logger.metric('signup:handleSuggestionSelected', {
|
||||||
|
method: suggestion.method,
|
||||||
|
})
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
@@ -225,12 +234,14 @@ export function StepHandle() {
|
|||||||
</View>
|
</View>
|
||||||
</LayoutAnimationConfig>
|
</LayoutAnimationConfig>
|
||||||
</View>
|
</View>
|
||||||
<BackNextButtons
|
<Animated.View layout={native(LinearTransition)}>
|
||||||
isLoading={isNextLoading}
|
<BackNextButtons
|
||||||
isNextDisabled={!validCheck.overall || !!state.error}
|
isLoading={isNextLoading}
|
||||||
onBackPress={onBackPress}
|
isNextDisabled={!validCheck.overall || !!state.error}
|
||||||
onNextPress={onNextPress}
|
onBackPress={onBackPress}
|
||||||
/>
|
onNextPress={onNextPress}
|
||||||
|
/>
|
||||||
|
</Animated.View>
|
||||||
</ScreenTransition>
|
</ScreenTransition>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -270,33 +281,43 @@ function HandleSuggestions({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Animated.View
|
<Animated.View
|
||||||
entering={FadeInDown}
|
entering={native(FadeInDown.easing(Easing.out(Easing.exp)))}
|
||||||
exiting={FadeOutDown}
|
exiting={native(FadeOut)}
|
||||||
style={[
|
style={[
|
||||||
a.flex_1,
|
a.flex_1,
|
||||||
a.border,
|
a.border,
|
||||||
a.rounded_sm,
|
a.rounded_sm,
|
||||||
a.shadow_md,
|
t.atoms.shadow_sm,
|
||||||
t.atoms.bg,
|
t.atoms.bg,
|
||||||
t.atoms.border_contrast_low,
|
t.atoms.border_contrast_low,
|
||||||
|
a.mt_xs,
|
||||||
|
a.z_50,
|
||||||
|
a.w_full,
|
||||||
|
a.zoom_fade_in,
|
||||||
]}>
|
]}>
|
||||||
{suggestions.map((suggestion, index) => (
|
{suggestions.map((suggestion, index) => (
|
||||||
<Button
|
<Button
|
||||||
label={_(msg`Select ${suggestion.handle}`)}
|
label={_(msg`Select ${suggestion.handle}`)}
|
||||||
key={index}
|
key={index}
|
||||||
onPress={() => onSelect(suggestion)}
|
onPress={() => onSelect(suggestion)}
|
||||||
|
hoverStyle={[t.atoms.bg_contrast_25]}
|
||||||
style={[
|
style={[
|
||||||
a.w_full,
|
a.w_full,
|
||||||
a.flex_row,
|
a.flex_row,
|
||||||
a.align_center,
|
a.align_center,
|
||||||
a.justify_between,
|
a.justify_between,
|
||||||
a.px_md,
|
a.p_md,
|
||||||
a.py_lg,
|
|
||||||
a.border_b,
|
a.border_b,
|
||||||
t.atoms.border_contrast_low,
|
t.atoms.border_contrast_low,
|
||||||
index === 0 && {borderTopEndRadius: borderRadius.sm},
|
index === 0 && {
|
||||||
|
borderTopStartRadius: borderRadius.sm,
|
||||||
|
borderTopEndRadius: borderRadius.sm,
|
||||||
|
},
|
||||||
index === suggestions.length - 1 && [
|
index === suggestions.length - 1 && [
|
||||||
{borderBottomEndRadius: borderRadius.sm},
|
{
|
||||||
|
borderBottomStartRadius: borderRadius.sm,
|
||||||
|
borderBottomEndRadius: borderRadius.sm,
|
||||||
|
},
|
||||||
a.border_b_0,
|
a.border_b_0,
|
||||||
],
|
],
|
||||||
]}>
|
]}>
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ export const RQKEY_handleAvailability = (
|
|||||||
handle: string,
|
handle: string,
|
||||||
domain: string,
|
domain: string,
|
||||||
serviceDid: string,
|
serviceDid: string,
|
||||||
) => ['handle-availability', handle, domain, serviceDid]
|
) => ['handle-availability', {handle, domain, serviceDid}]
|
||||||
|
|
||||||
export function useHandleAvailabilityQuery(
|
export function useHandleAvailabilityQuery(
|
||||||
{
|
{
|
||||||
@@ -46,68 +46,71 @@ export function useHandleAvailabilityQuery(
|
|||||||
}
|
}
|
||||||
}, [serviceDid])
|
}, [serviceDid])
|
||||||
|
|
||||||
return useQuery({
|
return {
|
||||||
enabled: enabled && name === debouncedHandle,
|
enabled: enabled && name === debouncedHandle,
|
||||||
queryKey: RQKEY_handleAvailability(
|
query: useQuery({
|
||||||
debouncedHandle,
|
enabled: enabled && name === debouncedHandle,
|
||||||
serviceDomain,
|
queryKey: RQKEY_handleAvailability(
|
||||||
serviceDid,
|
debouncedHandle,
|
||||||
),
|
serviceDomain,
|
||||||
queryFn: async () => {
|
serviceDid,
|
||||||
const handle = createFullHandle(name, serviceDomain)
|
),
|
||||||
if (serviceDid === BSKY_SERVICE_DID) {
|
queryFn: async () => {
|
||||||
// entryway has a special API for handle availability
|
const handle = createFullHandle(name, serviceDomain)
|
||||||
const {data} = await agent.com.atproto.temp.checkHandleAvailability({
|
if (serviceDid === BSKY_SERVICE_DID) {
|
||||||
handle,
|
// entryway has a special API for handle availability
|
||||||
birthDate,
|
const {data} = await agent.com.atproto.temp.checkHandleAvailability({
|
||||||
email,
|
|
||||||
})
|
|
||||||
|
|
||||||
if (
|
|
||||||
bsky.dangerousIsType<ComAtprotoTempCheckHandleAvailability.ResultAvailable>(
|
|
||||||
data.result,
|
|
||||||
ComAtprotoTempCheckHandleAvailability.isResultAvailable,
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
return {available: true} as const
|
|
||||||
} else if (
|
|
||||||
bsky.dangerousIsType<ComAtprotoTempCheckHandleAvailability.ResultUnavailable>(
|
|
||||||
data.result,
|
|
||||||
ComAtprotoTempCheckHandleAvailability.isResultUnavailable,
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
return {
|
|
||||||
available: false,
|
|
||||||
suggestions: data.result.suggestions,
|
|
||||||
} as const
|
|
||||||
} else {
|
|
||||||
throw new Error(
|
|
||||||
`Unexpected result of \`checkHandleAvailability\`: ${JSON.stringify(data.result)}`,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// 3rd party services won't have this API so just try and resolve the handle
|
|
||||||
try {
|
|
||||||
const res = await agent.resolveHandle({
|
|
||||||
handle,
|
handle,
|
||||||
|
birthDate,
|
||||||
|
email,
|
||||||
})
|
})
|
||||||
|
|
||||||
if (res.data.did) {
|
if (
|
||||||
logger.metric(
|
bsky.dangerousIsType<ComAtprotoTempCheckHandleAvailability.ResultAvailable>(
|
||||||
'signup:handleReserved',
|
data.result,
|
||||||
{typeahead: true},
|
ComAtprotoTempCheckHandleAvailability.isResultAvailable,
|
||||||
{statsig: true},
|
)
|
||||||
|
) {
|
||||||
|
return {available: true} as const
|
||||||
|
} else if (
|
||||||
|
bsky.dangerousIsType<ComAtprotoTempCheckHandleAvailability.ResultUnavailable>(
|
||||||
|
data.result,
|
||||||
|
ComAtprotoTempCheckHandleAvailability.isResultUnavailable,
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
return {
|
||||||
|
available: false,
|
||||||
|
suggestions: data.result.suggestions,
|
||||||
|
} as const
|
||||||
|
} else {
|
||||||
|
throw new Error(
|
||||||
|
`Unexpected result of \`checkHandleAvailability\`: ${JSON.stringify(data.result)}`,
|
||||||
)
|
)
|
||||||
return {available: false} as const
|
|
||||||
}
|
}
|
||||||
} catch {}
|
} else {
|
||||||
logger.metric(
|
// 3rd party services won't have this API so just try and resolve the handle
|
||||||
'signup:handleAvailable',
|
try {
|
||||||
{typeahead: true},
|
const res = await agent.resolveHandle({
|
||||||
{statsig: true},
|
handle,
|
||||||
)
|
})
|
||||||
return {available: true} as const
|
|
||||||
}
|
if (res.data.did) {
|
||||||
},
|
logger.metric(
|
||||||
})
|
'signup:handleReserved',
|
||||||
|
{typeahead: true},
|
||||||
|
{statsig: true},
|
||||||
|
)
|
||||||
|
return {available: false} as const
|
||||||
|
}
|
||||||
|
} catch {}
|
||||||
|
logger.metric(
|
||||||
|
'signup:handleAvailable',
|
||||||
|
{typeahead: true},
|
||||||
|
{statsig: true},
|
||||||
|
)
|
||||||
|
return {available: true} as const
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user