Skip to content

Commit

Permalink
feat: add inline errors for pin countdown in pin enter screen (#1326)
Browse files Browse the repository at this point in the history
Signed-off-by: FarjadGov14 <[email protected]>
  • Loading branch information
FarjadGov14 authored Dec 2, 2024
1 parent d488f21 commit 08998a8
Show file tree
Hide file tree
Showing 6 changed files with 86 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ const InlineErrorText: React.FC<InlineMessageProps> = ({ message, inlineType, co
? InputInlineMessage.inlineWarningText.color
: InputInlineMessage.inlineErrorText.color

const props: SvgProps = { height: 16, width: 16, color: color, style: style.icon }
const props: SvgProps = { height: 24, width: 24, color: color, style: style.icon }

return (
<View style={[style.container, config.style]}>
Expand Down
23 changes: 17 additions & 6 deletions packages/legacy/core/App/components/inputs/PINInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,9 @@ const PINInputComponent = (
hideIcon: {
paddingHorizontal: 10,
},
inlineMessageContainer: {
minHeight: 36,
},
})
const content = () => (
<View style={PINInputTheme.labelAndFieldContainer}>
Expand Down Expand Up @@ -110,14 +113,22 @@ const PINInputComponent = (
const inlineMessageView = ({ message, inlineType, config }: InlineMessageProps) => (
<InlineErrorText message={message} inlineType={inlineType} config={config} />
)
const inlineMessagePlaceholder = (placment: InlineErrorPosition) => {
if (inlineMessage && inlineMessage.config.position === placment) {
return inlineMessageView(inlineMessage)
const inlineMessagePlaceholder = (placement: InlineErrorPosition) => {
// Check if inlineMessage exists and if its position matches the placement or falls back to Above
if (!inlineMessage) {
return <View style={style.inlineMessageContainer} />
}
//This is a fallback in case no position provided
if (inlineMessage && placment === InlineErrorPosition.Above && !inlineMessage.config.position) {
return inlineMessageView(inlineMessage)

const messagePosition = inlineMessage.config.position || InlineErrorPosition.Above // Default to Above
if (messagePosition !== placement) {
return <View style={style.inlineMessageContainer} />
}

return (
<View style={style.inlineMessageContainer}>
{inlineMessageView(inlineMessage)}
</View>
)
}
return (
<View style={style.container}>
Expand Down
2 changes: 2 additions & 0 deletions packages/legacy/core/App/localization/en/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,8 @@ const translation = {
"BiometricsUnlock": "Unlock with biometrics",
"IncorrectPIN": "Incorrect PIN",
"RepeatPIN": "Please try your PIN again.",
"IncorrectPINTries": "Incorrect PIN: {{tries}} tries before timeout",
"LastTryBeforeTimeout": "Incorrect PIN: Last try before timeout",
"EnableBiometrics": "You have to enable biometrics to be able to load the wallet.",
"BiometricsNotProvided": "Biometrics not provided, you may use PIN to load the wallet.",
"BiometricsError": "Biometrics were not successful.",
Expand Down
2 changes: 2 additions & 0 deletions packages/legacy/core/App/localization/fr/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,8 @@ const translation = {
"BiometricsUnlock": "Déverrouiller avec la biométrie",
"IncorrectPIN": "NIP erroné",
"RepeatPIN": "Essayez votre NIP à nouveau",
"IncorrectPINTries": "PIN incorrect : {{tries}} essaie avant l'expiration du délai",
"LastTryBeforeTimeout": "PIN incorrect : dernier essai avant expiration du délai",
"EnableBiometrics": "Vous devez activer la biométrie pour pouvoir charger le portefeuille.",
"BiometricsNotProvided": "Biométrie non fournie, vous pouvez utiliser le NIP pour vous connecter au portefeuille.",
"BiometricsError": "La biométrie n'a pas réussi.",
Expand Down
37 changes: 34 additions & 3 deletions packages/legacy/core/App/screens/PINEnter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ const PINEnter: React.FC<PINEnterProps> = ({ setAuthenticated, usage = PINEntryU
const [logger] = useServices([TOKENS.UTIL_LOGGER])
const [inlineMessageField, setInlineMessageField] = useState<InlineMessageProps>()
const [inlineMessages] = useServices([TOKENS.INLINE_ERRORS])
const [alertModalMessage, setAlertModalMessage] = useState('')

const style = StyleSheet.create({
screenContainer: {
Expand Down Expand Up @@ -99,7 +100,7 @@ const PINEnter: React.FC<PINEnterProps> = ({ setAuthenticated, usage = PINEntryU
},
subText: {
...TextTheme.bold,
marginBottom: 20,
marginBottom: 4,
},
})

Expand Down Expand Up @@ -256,10 +257,38 @@ const PINEnter: React.FC<PINEnterProps> = ({ setAuthenticated, usage = PINEntryU

if (!result) {
const newAttempt = store.loginAttempt.loginAttempts + 1
if (!getLockoutPenalty(newAttempt)) {
const attemptsLeft = attemptLockoutThresholdRules.attemptIncrement - newAttempt
if (!inlineMessages.enabled && !getLockoutPenalty(newAttempt)) {
// skip displaying modals if we are going to lockout
setAlertModalVisible(true)
}
if (attemptsLeft > 1) {
if (inlineMessages.enabled) {
setInlineMessageField({
message: t('PINEnter.IncorrectPINTries', { tries: attemptsLeft }), // Example: 'Incorrect PIN: 4 tries before timeout'
inlineType: InlineErrorType.error,
config: inlineMessages,
})
} else {
setAlertModalMessage(t('PINEnter.IncorrectPINTries', { tries: attemptsLeft }))
}
} else if (attemptsLeft === 1) {
if (inlineMessages.enabled) {
setInlineMessageField({
message: t('PINEnter.LastTryBeforeTimeout'), // Show last try warning
inlineType: InlineErrorType.error,
config: inlineMessages,
})
} else {
setAlertModalMessage(t('PINEnter.LastTryBeforeTimeout'))
}
} else {
const penalty = getLockoutPenalty(newAttempt)
if (penalty !== undefined) {
attemptLockout(penalty) // Only call attemptLockout if penalty is defined
}
return
}

setContinueEnabled(true)

Expand Down Expand Up @@ -305,6 +334,8 @@ const PINEnter: React.FC<PINEnterProps> = ({ setAuthenticated, usage = PINEntryU
setAuthenticated,
gotoPostAuthScreens,
t,
attemptLockout,
inlineMessages,
]
)

Expand Down Expand Up @@ -485,7 +516,7 @@ const PINEnter: React.FC<PINEnterProps> = ({ setAuthenticated, usage = PINEntryU
title={t('PINEnter.IncorrectPIN')}
bodyContent={
<View>
<Text style={style.modalText}>{t('PINEnter.RepeatPIN')}</Text>
<Text style={style.modalText}>{alertModalMessage}</Text>
{displayLockoutWarning ? (
<Text style={style.modalText}>{t('PINEnter.AttemptLockoutWarning')}</Text>
) : null}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ exports[`PINEnter Screen PIN Enter renders correctly 1`] = `
"color": "#FFFFFF",
"fontSize": 18,
"fontWeight": "bold",
"marginBottom": 20,
"marginBottom": 4,
}
}
>
Expand All @@ -94,6 +94,13 @@ exports[`PINEnter Screen PIN Enter renders correctly 1`] = `
}
}
>
<View
style={
Object {
"minHeight": 36,
}
}
/>
<View
style={
Object {
Expand Down Expand Up @@ -372,6 +379,13 @@ exports[`PINEnter Screen PIN Enter renders correctly 1`] = `
</Text>
</View>
</View>
<View
style={
Object {
"minHeight": 36,
}
}
/>
</View>
</View>
<View
Expand Down Expand Up @@ -545,7 +559,7 @@ exports[`PINEnter Screen PIN Enter renders correctly when logged out message is
"color": "#FFFFFF",
"fontSize": 18,
"fontWeight": "bold",
"marginBottom": 20,
"marginBottom": 4,
}
}
>
Expand All @@ -559,6 +573,13 @@ exports[`PINEnter Screen PIN Enter renders correctly when logged out message is
}
}
>
<View
style={
Object {
"minHeight": 36,
}
}
/>
<View
style={
Object {
Expand Down Expand Up @@ -837,6 +858,13 @@ exports[`PINEnter Screen PIN Enter renders correctly when logged out message is
</Text>
</View>
</View>
<View
style={
Object {
"minHeight": 36,
}
}
/>
</View>
</View>
<View
Expand Down

0 comments on commit 08998a8

Please sign in to comment.