Skip to content

Commit

Permalink
chore: recovery code component (juspay#715)
Browse files Browse the repository at this point in the history
  • Loading branch information
Riddhiagrawal001 authored May 27, 2024
1 parent 2e471cc commit a3093b0
Show file tree
Hide file tree
Showing 4 changed files with 172 additions and 196 deletions.
85 changes: 85 additions & 0 deletions src/entryPoints/AuthModule/TotpAuth/TotpRecoveryCodes.res
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
let h2TextStyle = HSwitchUtils.getTextClass((H2, Optional))

@react.component
let make = (~setTotpStatus, ~onClickDownload) => {
let showToast = ToastState.useShowToast()
let getURL = APIUtils.useGetURL()
let fetchDetails = APIUtils.useGetMethod()
let (recoveryCodes, setRecoveryCodes) = React.useState(_ => [])
let (screenState, setScreenState) = React.useState(_ => PageLoaderWrapper.Success)

let generateRecoveryCodes = async () => {
open TotpTypes
try {
open LogicUtils
setScreenState(_ => PageLoaderWrapper.Loading)
let url = getURL(~entityName=USERS, ~userType=#GENERATE_RECOVERY_CODES, ~methodType=Get, ())
let response = await fetchDetails(url)
let recoveryCodesValue = response->getDictFromJsonObject->getStrArray("recovery_codes")
setRecoveryCodes(_ => recoveryCodesValue)
setScreenState(_ => PageLoaderWrapper.Success)
} catch {
| _ => setTotpStatus(_ => TOTP_SHOW_QR)
}
}

let downloadRecoveryCodes = () => {
open LogicUtils
DownloadUtils.downloadOld(
~fileName="recoveryCodes.txt",
~content=JSON.stringifyWithIndent(recoveryCodes->getJsonFromArrayOfString, 3),
)
}

let copyRecoveryCodes = ev => {
open LogicUtils
ev->ReactEvent.Mouse.stopPropagation
Clipboard.writeText(JSON.stringifyWithIndent(recoveryCodes->getJsonFromArrayOfString, 3))
showToast(~message="Copied to Clipboard!", ~toastType=ToastSuccess, ())
}

React.useEffect0(() => {
generateRecoveryCodes()->ignore
None
})

<PageLoaderWrapper screenState>
<div className={`bg-white h-40-rem w-133 rounded-2xl flex flex-col`}>
<div className="p-6 border-b-2 flex justify-between items-center">
<p className={`${h2TextStyle} text-grey-900`}>
{"Two factor recovery codes"->React.string}
</p>
</div>
<div className="px-8 py-8 flex flex-col flex-1 justify-between">
<div className="flex flex-col gap-6">
<p className="text-jp-gray-700">
{"Recovery codes provide a way to access your account if you lose your device and can't receive two-factor authentication codes."->React.string}
</p>
<HSwitchUtils.WarningArea
warningText="These codes are the last resort for accessing your account in case you lose your password and second factors. If you cannot find these codes, you will lose access to your account."
/>
<TwoFaElements.ShowRecoveryCodes recoveryCodes />
</div>
<div className="flex gap-4 justify-end">
<Button
leftIcon={CustomIcon(<img src={`/assets/CopyToClipboard.svg`} />)}
text={"Copy"}
buttonType={Secondary}
buttonSize={Small}
onClick={copyRecoveryCodes}
/>
<Button
leftIcon={FontAwesome("download-api-key")}
text={"Download"}
buttonType={Primary}
buttonSize={Small}
onClick={_ => {
downloadRecoveryCodes()
onClickDownload(false)->ignore
}}
/>
</div>
</div>
</div>
</PageLoaderWrapper>
}
34 changes: 3 additions & 31 deletions src/entryPoints/AuthModule/TotpAuth/TotpSetup.res
Original file line number Diff line number Diff line change
Expand Up @@ -130,36 +130,8 @@ module ConfigureTotpScreen = {
}
}

// let downloadRecoveryCodes = () => {
// open LogicUtils
// try {
// DownloadUtils.downloadOld(
// ~fileName="recoveryCodes.txt",
// ~content=JSON.stringifyWithIndent(recoveryCodes->getJsonFromArrayOfString, 3),
// )
// } catch {
// | _ => showToast(~message="Failed to fetch recovery codes!", ~toastType=ToastError, ())
// }
// }

// let confirmRecoveryCodesPopUp = () => {
// showPopUp({
// popUpType: (Warning, WithIcon),
// heading: "Confirm action",
// description: <ConfirmPopUpElement recoveryCodes downloadRecoveryCodes />,
// handleConfirm: {
// text: "Continue",
// onClick: _ => verifyTOTP()->ignore,
// },
// })
// }

let handleTotpSubmitClick = () => {
// if recoveryCodes->Array.length > 0 {
// confirmRecoveryCodesPopUp()
// } else {
verifyTOTP()->ignore
// }
}

let buttonText = showQR ? "Enable 2FA" : "Verify OTP"
Expand All @@ -171,9 +143,9 @@ module ConfigureTotpScreen = {
</div>
<div className="px-12 py-8 flex flex-col gap-12 justify-between flex-1">
<UIUtils.RenderIf condition={showQR}>
<TotpSetupElements.TotpScanQR totpUrl isQrVisible />
<TwoFaElements.TotpScanQR totpUrl isQrVisible />
</UIUtils.RenderIf>
<TotpSetupElements.TotpInput otp setOtp />
<TwoFaElements.TotpInput otp setOtp />
<div className="flex justify-end gap-4">
<Button
text="Skip now"
Expand Down Expand Up @@ -266,7 +238,7 @@ let make = () => {
<div className="h-full w-full flex flex-col gap-4 items-center justify-center p-6">
{switch totpStatus {
| TOTP_SHOW_QR => <ConfigureTotpScreen isQrVisible totpUrl showQR setTotpStatus />
| TOTP_SHOW_RC => <TotpSetupElements.TotpRecoveryCodes setTotpStatus />
| TOTP_SHOW_RC => <TotpRecoveryCodes setTotpStatus onClickDownload={_ => ()} />
}}
<div className="text-grey-200 flex gap-2">
{"Log in with a different account?"->React.string}
Expand Down
165 changes: 0 additions & 165 deletions src/entryPoints/AuthModule/TotpAuth/TotpSetupElements.res

This file was deleted.

84 changes: 84 additions & 0 deletions src/entryPoints/AuthModule/TotpAuth/TwoFaElements.res
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
let h2TextStyle = HSwitchUtils.getTextClass((H2, Optional))
let h3TextStyle = HSwitchUtils.getTextClass((H3, Leading_1))
let p2Regular = HSwitchUtils.getTextClass((P2, Regular))
let p3Regular = HSwitchUtils.getTextClass((P3, Regular))

module TotpScanQR = {
@react.component
let make = (~totpUrl, ~isQrVisible) => {
<>
<div className="grid grid-cols-4 gap-4 w-full">
<div className="flex flex-col gap-10 col-span-3">
<p> {"Use any authenticator app to complete the setup"->React.string} </p>
<div className="flex flex-col gap-4">
<p className=p2Regular>
{"Follow these steps to configure two factor authentication:"->React.string}
</p>
<div className="flex flex-col gap-4 ml-2">
<p className={`${p2Regular} opacity-60 flex gap-2 items-center`}>
<div className="text-white rounded-full bg-grey-900 opacity-50 px-2 py-0.5">
{"1"->React.string}
</div>
{"Scan the QR code shown on the screen with your authenticator application"->React.string}
</p>
<p className={`${p2Regular} opacity-60 flex gap-2 items-center`}>
<div className="text-white rounded-full bg-grey-900 opacity-50 px-2 py-0.5">
{"2"->React.string}
</div>
{"Enter the OTP code displayed on the authenticator app in below text field or textbox"->React.string}
</p>
</div>
</div>
</div>
<div
className={`flex flex-col gap-2 col-span-1 items-center justify-center ${totpUrl->String.length > 0
? "blur-none"
: "blur-sm"}`}>
<p className=p3Regular> {"Scan the QR Code into your app"->React.string} </p>
{if isQrVisible {
<ReactQRCode value=totpUrl size=150 />
} else {
<Icon
name="spinner"
size=20
className="animate-spin"
parentClass="w-full h-full flex justify-center items-center"
/>
}}
</div>
</div>
<div className="h-px w-11/12 bg-grey-200 opacity-50" />
</>
}
}

module TotpInput = {
@react.component
let make = (~otp, ~setOtp) => {
<div className="flex flex-col gap-4 items-center">
<p>
{"Enter a 6-digit authentication code generated by you authenticator app"->React.string}
</p>
<OtpInput value={otp} setValue={setOtp} />
</div>
}
}

module ShowRecoveryCodes = {
@react.component
let make = (~recoveryCodes) => {
<div
className="border border-gray-200 rounded-md bg-jp-gray-100 py-6 px-12 flex gap-8 flex justify-evenly">
<div className="grid grid-cols-2 gap-4">
{recoveryCodes
->Array.map(recoveryCode =>
<div className="flex items-center gap-2">
<div className="p-1 rounded-full bg-jp-gray-600" />
<p className="text-jp-gray-700 text-xl"> {recoveryCode->React.string} </p>
</div>
)
->React.array}
</div>
</div>
}
}

0 comments on commit a3093b0

Please sign in to comment.