Contact support
}
/>
)
return (
{seenBefore ? `Welcome back ${seenUser}` : 'Welcome'}
Sign in to FreeSewing
{!seenBefore && (
val.length > 1}
/>
)}
{magicLink ? (
) : (
<>
val.length > 0}
onKeyDown={triggerSubmit}
/>
>
)}
{['Google', 'Github'].map((provider) => (
))}
{seenBefore ? (
) : (
Sign up here
)}
)
}
const WrapForm = ({ children }) => {children}
const MfaForm = ({ mfaCode, setMfaCode, onSubmit, post = [] }) => (
MFA Code
Please provide a one-time MFA code, or a backup scratch code
{post}
)
export const SignInConfirmation = ({ onSuccess = false }) => {
// State
const [error, setError] = useState(false)
const [id, setId] = useState()
const [check, setCheck] = useState()
const [mfa, setMfa] = useState()
const [mfaCode, setMfaCode] = useState()
// Hooks
const { setAccount, setToken } = useAccount()
const backend = useBackend()
// Context
const { setLoadingStatus } = useContext(LoadingStatusContext)
// Effects
useEffect(() => {
const newId = getSearchParam('id')
const newCheck = getSearchParam('check')
if (newId !== id) setId(newId)
if (newCheck !== check) setCheck(newCheck)
}, [id, check])
useEffect(() => {
// Call async method
if (id) getConfirmation()
}, [id])
// Gets the confirmation
const getConfirmation = async () => {
setLoadingStatus([true, 'Contacting the backend', true, true])
// Reach out to backend
const [status, body] = await backend.signInFromLink({ id, check, token: mfaCode })
// If it works, store account, which runs the onSuccess handler
if (body.token) return storeAccount(body)
// If it did not work, perhaps we need to handle MFA?
if (status === 403 && body.error === 'mfaTokenRequired') {
setMfa(true)
setLoadingStatus([
true,
'Please provide a one-time MFA code, or a backup scratch code',
true,
true,
])
return
}
// If we get here, we're not sure what's wrong
if (body.error) return setError(body.error)
return setError(true)
}
// Updates the (local) account data
const storeAccount = async (data) => {
if (data?.token && data?.account) {
setToken(data.token)
setAccount(data.account)
if (typeof onSuccess === 'function') onSuccess(data)
else navigate('/account', true)
} else {
setError(data)
}
}
// Short-circuit errors
if (error && mfa)
return error === 'signInFailed' ? (
<>
Your one-time token is either invalid of expired.
>
) : (
<>
This error is unexpected. Please report this.
>
)
// Show MFA input if required
if (mfa) return
// If we do not (yet) have the data, show a loader
if (!id || !check)
return (
<>
One moment please
>
)
return fixme
}
/*
* This is the generic component that will handle the Oauth callback
*/
export const OauthCallback = ({ provider = false }) => {
const [error, setError] = useState(false)
const backend = useBackend()
const { setAccount, setToken, setSeenUser } = useAccount()
// Handle callback
useEffect(() => {
const oauthFlow = async () => {
const state = getSearchParam('state')
const code = getSearchParam('state')
const [status, body] = await backend.oauthSignIn({ state, code, provider })
if (status === 200 && body.account && body.token) {
setAccount(body.account)
setToken(body.token)
setSeenUser(body.data.account.username)
navigate('/welcome', true)
} else setError(true)
}
oauthFlow()
}, [])
if (!provider) return You must provide a provider prop to this component
return error ? (
<>
Oh no, something went wrong
Please{' '}
escalate this to support
>
) : (
<>
One moment please
>
)
}