From aa4faeb96cb4e7ba482176063567da21520ca84f Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Fri, 6 May 2022 17:58:04 -0500 Subject: [PATCH] Captcha: convert to tsx --- .../features/auth_login/components/captcha.js | 125 ------------------ .../auth_login/components/captcha.tsx | 118 +++++++++++++++++ 2 files changed, 118 insertions(+), 125 deletions(-) delete mode 100644 app/soapbox/features/auth_login/components/captcha.js create mode 100644 app/soapbox/features/auth_login/components/captcha.tsx diff --git a/app/soapbox/features/auth_login/components/captcha.js b/app/soapbox/features/auth_login/components/captcha.js deleted file mode 100644 index bcdaf74a4..000000000 --- a/app/soapbox/features/auth_login/components/captcha.js +++ /dev/null @@ -1,125 +0,0 @@ -import { Map as ImmutableMap } from 'immutable'; -import PropTypes from 'prop-types'; -import React from 'react'; -import ImmutablePropTypes from 'react-immutable-proptypes'; -import { FormattedMessage } from 'react-intl'; -import { connect } from 'react-redux'; - -import { fetchCaptcha } from 'soapbox/actions/auth'; -import { TextInput } from 'soapbox/features/forms'; - -const noOp = () => {}; - -export default @connect() -class CaptchaField extends React.Component { - - static propTypes = { - onChange: PropTypes.func, - onFetch: PropTypes.func, - onFetchFail: PropTypes.func, - onClick: PropTypes.func, - dispatch: PropTypes.func, - refreshInterval: PropTypes.number, - idempotencyKey: PropTypes.string, - } - - static defaultProps = { - onChange: noOp, - onFetch: noOp, - onFetchFail: noOp, - onClick: noOp, - refreshInterval: 5*60*1000, // 5 minutes, Pleroma default - } - - state = { - captcha: ImmutableMap(), - refresh: undefined, - } - - startRefresh = () => { - const { refreshInterval } = this.props; - if (refreshInterval) { - const refresh = setInterval(this.fetchCaptcha, refreshInterval); - this.setState({ refresh }); - } - } - - endRefresh = () => { - clearInterval(this.state.refresh); - } - - forceRefresh = () => { - this.fetchCaptcha(); - this.endRefresh(); - this.startRefresh(); - } - - fetchCaptcha = () => { - const { dispatch, onFetch, onFetchFail } = this.props; - dispatch(fetchCaptcha()).then(response => { - const captcha = ImmutableMap(response.data); - this.setState({ captcha }); - onFetch(captcha); - }).catch(error => { - onFetchFail(error); - }); - } - - componentDidMount() { - this.fetchCaptcha(); - this.startRefresh(); // Refresh periodically - } - - componentWillUnmount() { - this.endRefresh(); - } - - componentDidUpdate(prevProps) { - if (this.props.idempotencyKey !== prevProps.idempotencyKey) { - this.forceRefresh(); - } - } - - render() { - const { captcha } = this.state; - const { onChange, onClick, ...props } = this.props; - - switch(captcha.get('type')) { - case 'native': - return ( -
-

{}

- -
- ); - case 'none': - default: - return null; - } - } - -} - -export const NativeCaptchaField = ({ captcha, onChange, onClick, name, value }) => ( -
- captcha - -
-); - -NativeCaptchaField.propTypes = { - captcha: ImmutablePropTypes.map.isRequired, - onChange: PropTypes.func, - onClick: PropTypes.func, - name: PropTypes.string, - value: PropTypes.string, -}; diff --git a/app/soapbox/features/auth_login/components/captcha.tsx b/app/soapbox/features/auth_login/components/captcha.tsx new file mode 100644 index 000000000..c45010dac --- /dev/null +++ b/app/soapbox/features/auth_login/components/captcha.tsx @@ -0,0 +1,118 @@ +import { Map as ImmutableMap } from 'immutable'; +import React, { useState, useEffect } from 'react'; +import { FormattedMessage } from 'react-intl'; + +import { fetchCaptcha } from 'soapbox/actions/auth'; +import { TextInput } from 'soapbox/features/forms'; +import { useAppDispatch } from 'soapbox/hooks'; + +const noOp = () => {}; + +interface ICaptchaField { + name?: string, + value: string, + onChange?: React.ChangeEventHandler, + onFetch?: (captcha: ImmutableMap) => void, + onFetchFail?: (error: Error) => void, + onClick?: React.MouseEventHandler, + refreshInterval?: number, + idempotencyKey: string, +} + +const CaptchaField: React.FC = ({ + name, + value, + onChange = noOp, + onFetch = noOp, + onFetchFail = noOp, + onClick = noOp, + refreshInterval = 5*60*1000, // 5 minutes, Pleroma default + idempotencyKey, +}) => { + const dispatch = useAppDispatch(); + + const [captcha, setCaptcha] = useState(ImmutableMap()); + const [refresh, setRefresh] = useState(undefined); + + const getCaptcha = () => { + dispatch(fetchCaptcha()).then(response => { + const captcha = ImmutableMap(response.data); + setCaptcha(captcha); + onFetch(captcha); + }).catch((error: Error) => { + onFetchFail(error); + }); + }; + + const startRefresh = () => { + if (refreshInterval) { + const newRefresh = setInterval(getCaptcha, refreshInterval); + setRefresh(newRefresh); + } + }; + + const endRefresh = () => { + if (refresh) { + clearInterval(refresh); + } + }; + + useEffect(() => { + getCaptcha(); + endRefresh(); + startRefresh(); // Refresh periodically + + return () => { + endRefresh(); + }; + }, [idempotencyKey]); + + switch(captcha.get('type')) { + case 'native': + return ( +
+

{}

+ + +
+ ); + case 'none': + default: + return null; + } +}; + +interface INativeCaptchaField { + captcha: ImmutableMap, + onChange: React.ChangeEventHandler, + onClick: React.MouseEventHandler, + name?: string, + value: string, +} + +const NativeCaptchaField: React.FC = ({ captcha, onChange, onClick, name, value }) => ( +
+ captcha + +
+); + +export { + CaptchaField as default, + NativeCaptchaField, +};