-
Notifications
You must be signed in to change notification settings - Fork 4
Mod. React. Continue switch auth block. #640
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 10 commits
307e9c1
3822954
0a9a23e
8cbe9c6
8371e35
cbd39e2
754a91a
60adb05
9a23df1
6552cff
2a8c331
d918c1b
4f7ff2e
46d33c1
65d7d1b
0258811
2a73ac1
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,48 @@ | ||
| /** | ||
| * AJAX helpers for 2FA email confirmation (admin settings). | ||
| * @return {Promise<Object>} | ||
| */ | ||
| function sendTwoFaRequest(action, payload = {}) { | ||
| if (typeof spbcSendAJAXRequest !== 'function') { | ||
| return Promise.resolve({success: false, data: 'spbcSendAJAXRequest is not available'}); | ||
| } | ||
|
|
||
| return new Promise((resolve) => { | ||
| const data = { | ||
| action, | ||
| ...payload, | ||
| }; | ||
|
|
||
| const params = { | ||
| callback: (result) => resolve(result), | ||
| error: (jqXHR, textStatus, errorThrown) => | ||
| resolve({success: false, data: errorThrown || textStatus || 'Request failed'}), | ||
| }; | ||
|
|
||
| spbcSendAJAXRequest(data, params); | ||
| }); | ||
| } | ||
|
|
||
| export async function generateTwoFaConfirmationCode() { | ||
| const s = window.spbcSettings; | ||
| if (!s || !s.ajaxurl || !s.ajax_nonce) { | ||
| return {success: false, data: 'spbcSettings is not available'}; | ||
| } | ||
|
svfcode marked this conversation as resolved.
|
||
|
|
||
| return sendTwoFaRequest('spbc_generate_confirmation_code'); | ||
| } | ||
|
|
||
| /** | ||
| * @param {string} code | ||
| * @return {Promise<Object>} | ||
| */ | ||
| export async function checkTwoFaConfirmationCode(code) { | ||
| const s = window.spbcSettings; | ||
| if (!s || !s.ajaxurl || !s.ajax_nonce) { | ||
| return {success: false, data: 'spbcSettings is not available'}; | ||
| } | ||
|
|
||
| return sendTwoFaRequest('spbc_check_confirmation_code', { | ||
| code: String(code), | ||
| }); | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,173 @@ | ||
| import React, {useState, useEffect, useRef, useCallback} from 'react'; | ||
| import ReactFileViewDialog from '../../../ReactFileViewDialog/ReactFileViewDialog'; | ||
| import {generateTwoFaConfirmationCode, checkTwoFaConfirmationCode} from './2faConfirmationApi'; | ||
|
|
||
| const {__, sprintf} = wp.i18n; | ||
|
|
||
| /** | ||
| * @param {object} props | ||
| * @param {boolean} props.isOpen | ||
| * @param {function(): void} props.onCancel | ||
| * @param {function(): void} props.onVerified | ||
| * @param {string} props.verificationEmail | ||
| * @return {JSX.Element|null} | ||
| */ | ||
| export default function TwoFaConfirmationDialog(props) { | ||
| const {isOpen, onCancel, onVerified, verificationEmail} = props; | ||
| const [code, setCode] = useState(''); | ||
| const [resendBusy, setResendBusy] = useState(false); | ||
| const [resendCooldown, setResendCooldown] = useState(false); | ||
| const [okBusy, setOkBusy] = useState(false); | ||
| const resendTimerRef = useRef(null); | ||
|
|
||
| const clearResendTimer = useCallback(() => { | ||
| if (resendTimerRef.current) { | ||
| clearTimeout(resendTimerRef.current); | ||
| resendTimerRef.current = null; | ||
| } | ||
| }, []); | ||
|
|
||
| const startResendCooldown = useCallback(() => { | ||
| clearResendTimer(); | ||
| setResendCooldown(true); | ||
| resendTimerRef.current = setTimeout(() => { | ||
| setResendCooldown(false); | ||
| resendTimerRef.current = null; | ||
| }, 30000); | ||
| }, [clearResendTimer]); | ||
|
|
||
| useEffect(() => { | ||
| if (!isOpen) { | ||
| setCode(''); | ||
| setResendBusy(false); | ||
| setResendCooldown(false); | ||
| setOkBusy(false); | ||
| clearResendTimer(); | ||
| return; | ||
| } | ||
| startResendCooldown(); | ||
| return () => { | ||
| clearResendTimer(); | ||
| }; | ||
| }, [isOpen, clearResendTimer, startResendCooldown]); | ||
|
|
||
| const handleResend = async () => { | ||
| if (resendBusy || resendCooldown) { | ||
| return; | ||
| } | ||
| setResendBusy(true); | ||
| try { | ||
| const res = await generateTwoFaConfirmationCode(); | ||
| if (res.success) { | ||
| setCode(''); | ||
| startResendCooldown(); | ||
|
svfcode marked this conversation as resolved.
|
||
| } else { | ||
| const msg = typeof res.data === 'string' ? | ||
| res.data : | ||
| __('Request failed.', 'security-malware-firewall'); | ||
| alert(msg); | ||
| } | ||
| } catch (error) { | ||
| console.error(error); | ||
|
svfcode marked this conversation as resolved.
|
||
| } finally { | ||
| setResendBusy(false); | ||
| } | ||
| }; | ||
|
|
||
| const handleOk = async () => { | ||
| if (okBusy) { | ||
| return; | ||
| } | ||
|
|
||
| setOkBusy(true); | ||
|
|
||
| let res; | ||
| try { | ||
| res = await checkTwoFaConfirmationCode(code.trim()); | ||
| } catch (e) { | ||
| alert(__('Code verification failed. Please try again.', 'security-malware-firewall')); | ||
| return; | ||
| } | ||
|
svfcode marked this conversation as resolved.
Outdated
|
||
|
|
||
| try { | ||
| if (res.success) { | ||
| clearResendTimer(); | ||
| onVerified(); | ||
| } else { | ||
| const msg = typeof res.data === 'string' ? | ||
| res.data : | ||
| __('Code verification failed!', 'security-malware-firewall'); | ||
| alert(msg); | ||
| } | ||
| } finally { | ||
| setOkBusy(false); | ||
| } | ||
| }; | ||
|
|
||
| const email = verificationEmail || ''; | ||
| const checkInboxMsg = __( | ||
| 'Check %s inbox for the confirmation code.', | ||
| 'security-malware-firewall', | ||
| ); | ||
| /* eslint-disable max-len */ | ||
| const codeValidityNote = __( | ||
| 'The code is valid for 10 minutes. If you want to change the status in this period, the new code won\'t be sent, please, use the code you\'ve already received.', | ||
| 'security-malware-firewall', | ||
| ); | ||
| /* eslint-enable max-len */ | ||
|
|
||
| return ( | ||
| <ReactFileViewDialog | ||
| isOpen={isOpen} | ||
| onClose={onCancel} | ||
| title={__('Confirmation code', 'security-malware-firewall')} | ||
| maxWidth="360px" | ||
| > | ||
| <p> | ||
| {sprintf( | ||
| /* translators: %s: email address */ | ||
| checkInboxMsg, | ||
| email, | ||
| )} | ||
| </p> | ||
| <p> | ||
| <em> | ||
| {codeValidityNote} | ||
| </em> | ||
| </p> | ||
| <p> | ||
| <input | ||
| type="text" | ||
| name="spbct-confirmation-code" | ||
| value={code} | ||
| onChange={(e) => setCode(e.target.value)} | ||
| className="regular-text" | ||
| autoComplete="one-time-code" | ||
| /> | ||
| | ||
| <button | ||
| type="button" | ||
| className="button button-primary spbc-2fa-confirmation-resend" | ||
| onClick={handleResend} | ||
| disabled={resendBusy || resendCooldown} | ||
| > | ||
| {__('Resend', 'security-malware-firewall')} | ||
| {resendCooldown && ( | ||
| <span className="circle circle--small -animation--circle -animation--30s"> | ||
| <span className="circle-inner"></span> | ||
| </span> | ||
| )} | ||
| </button> | ||
| </p> | ||
| <p style={{marginTop: 16, textAlign: 'right'}}> | ||
| <button type="button" className="button" onClick={onCancel} disabled={okBusy}> | ||
| {__('Cancel', 'security-malware-firewall')} | ||
| </button> | ||
| | ||
| <button type="button" className="button button-primary" onClick={handleOk} disabled={okBusy}> | ||
| {__('OK', 'security-malware-firewall')} | ||
| </button> | ||
| </p> | ||
| </ReactFileViewDialog> | ||
| ); | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.