import {useState} from 'react'
import {useWindowDimensions, View} from 'react-native'
import {msg, Trans} from '@lingui/macro'
import {useLingui} from '@lingui/react'
import * as EmailValidator from 'email-validator'
import {cleanError, isNetworkError} from '#/lib/strings/errors'
import {checkAndFormatResetCode} from '#/lib/strings/password'
import {logger} from '#/logger'
import {isNative} from '#/platform/detection'
import {useAgent, useSession} from '#/state/session'
import {ErrorMessage} from '#/view/com/util/error/ErrorMessage'
import {android, atoms as a, web} from '#/alf'
import {Button, ButtonIcon, ButtonText} from '#/components/Button'
import * as Dialog from '#/components/Dialog'
import * as TextField from '#/components/forms/TextField'
import {Loader} from '#/components/Loader'
import {Text} from '#/components/Typography'
enum Stages {
RequestCode = 'RequestCode',
ChangePassword = 'ChangePassword',
Done = 'Done',
}
export function ChangePasswordDialog({
control,
}: {
control: Dialog.DialogControlProps
}) {
const {height} = useWindowDimensions()
return (
)
}
function Inner() {
const {_} = useLingui()
const {currentAccount} = useSession()
const agent = useAgent()
const control = Dialog.useDialogContext()
const [stage, setStage] = useState(Stages.RequestCode)
const [isProcessing, setIsProcessing] = useState(false)
const [resetCode, setResetCode] = useState('')
const [newPassword, setNewPassword] = useState('')
const [error, setError] = useState('')
const uiStrings = {
RequestCode: {
title: _(msg`Change your password`),
message: _(
msg`If you want to change your password, we will send you a code to verify that this is your account.`,
),
},
ChangePassword: {
title: _(msg`Enter code`),
message: _(
msg`Please enter the code you received and the new password you would like to use.`,
),
},
Done: {
title: _(msg`Password changed`),
message: _(
msg`Your password has been changed successfully! Please use your new password when you sign in to Bluesky from now on.`,
),
},
}
const onRequestCode = async () => {
if (
!currentAccount?.email ||
!EmailValidator.validate(currentAccount.email)
) {
return setError(_(msg`Your email appears to be invalid.`))
}
setError('')
setIsProcessing(true)
try {
await agent.com.atproto.server.requestPasswordReset({
email: currentAccount.email,
})
setStage(Stages.ChangePassword)
} catch (e: any) {
if (isNetworkError(e)) {
setError(
_(
msg`Unable to contact your service. Please check your internet connection and try again.`,
),
)
} else {
logger.error('Failed to request password reset', {safeMessage: e})
setError(cleanError(e))
}
} finally {
setIsProcessing(false)
}
}
const onChangePassword = async () => {
const formattedCode = checkAndFormatResetCode(resetCode)
if (!formattedCode) {
setError(
_(
msg`You have entered an invalid code. It should look like XXXXX-XXXXX.`,
),
)
return
}
if (!newPassword) {
setError(
_(msg`Please enter a password. It must be at least 8 characters long.`),
)
return
}
if (newPassword.length < 8) {
setError(_(msg`Password must be at least 8 characters long.`))
return
}
setError('')
setIsProcessing(true)
try {
await agent.com.atproto.server.resetPassword({
token: formattedCode,
password: newPassword,
})
setStage(Stages.Done)
} catch (e: any) {
if (isNetworkError(e)) {
setError(
_(
msg`Unable to contact your service. Please check your internet connection and try again.`,
),
)
} else if (e?.toString().includes('Token is invalid')) {
setError(_(msg`This confirmation code is not valid. Please try again.`))
} else {
logger.error('Failed to set new password', {safeMessage: e})
setError(cleanError(e))
}
} finally {
setIsProcessing(false)
}
}
const onBlur = () => {
const formattedCode = checkAndFormatResetCode(resetCode)
if (!formattedCode) {
return
}
setResetCode(formattedCode)
}
return (
{uiStrings[stage].title}
{error ? (
) : null}
{uiStrings[stage].message}
{stage === Stages.ChangePassword && (
Confirmation code
New password
)}
{stage === Stages.RequestCode ? (
<>
{isNative && (
)}
>
) : stage === Stages.ChangePassword ? (
<>
>
) : stage === Stages.Done ? (
) : null}
)
}