109 lines
2.4 KiB
TypeScript
109 lines
2.4 KiB
TypeScript
import {emit, on} from '@/scripts/event';
|
|
import {t} from '@/scripts/i18n';
|
|
import * as cssUtils from '@/styles/utils';
|
|
import React from 'react';
|
|
import Reaptcha from 'reaptcha';
|
|
|
|
const eventId = Symbol('EventId');
|
|
|
|
type State = {
|
|
value: string;
|
|
time: number;
|
|
sitekey: string;
|
|
invisible: boolean;
|
|
};
|
|
|
|
class Captcha extends React.Component<Record<string, unknown>, State> {
|
|
state: State;
|
|
// eslint-disable-next-line ts/no-restricted-types
|
|
ref: React.RefObject<Reaptcha | null>;
|
|
|
|
constructor(props: Record<string, unknown>) {
|
|
super(props);
|
|
this.state = {
|
|
value: '',
|
|
time: Date.now(),
|
|
sitekey: blessing.extra.recaptcha as string,
|
|
invisible: blessing.extra.invisible as boolean,
|
|
};
|
|
this.ref = React.createRef<Reaptcha>();
|
|
}
|
|
|
|
// eslint-disable-next-line react/no-unused-class-component-members
|
|
async execute() {
|
|
const recaptcha = this.ref.current;
|
|
if (recaptcha && this.state.invisible) {
|
|
return new Promise<string>(resolve => {
|
|
const off = on(eventId, (value: string) => {
|
|
resolve(value);
|
|
off();
|
|
});
|
|
void recaptcha.execute();
|
|
});
|
|
}
|
|
|
|
return this.state.value;
|
|
}
|
|
|
|
// eslint-disable-next-line react/no-unused-class-component-members
|
|
reset() {
|
|
const recaptcha = this.ref.current;
|
|
if (recaptcha) {
|
|
void recaptcha.reset();
|
|
} else {
|
|
this.setState({time: Date.now()});
|
|
}
|
|
}
|
|
|
|
handleValueChange = (event: React.ChangeEvent<HTMLInputElement>) => {
|
|
this.setState({value: event.target.value});
|
|
};
|
|
|
|
handleVerify = (value: string) => {
|
|
emit(eventId, value);
|
|
this.setState({value});
|
|
};
|
|
|
|
handleRefresh = () => {
|
|
this.setState({time: Date.now()});
|
|
};
|
|
|
|
render() {
|
|
return this.state.sitekey
|
|
? (
|
|
<div className='mb-2'>
|
|
<Reaptcha
|
|
ref={this.ref}
|
|
sitekey={this.state.sitekey}
|
|
size={this.state.invisible ? 'invisible' : 'normal'}
|
|
onVerify={this.handleVerify}
|
|
/>
|
|
</div>
|
|
)
|
|
: (
|
|
<div className='d-flex'>
|
|
<div className='form-group mb-3 mr-2'>
|
|
<input
|
|
required
|
|
type='text'
|
|
className='form-control'
|
|
placeholder={t('auth.captcha')}
|
|
value={this.state.value}
|
|
onChange={this.handleValueChange}
|
|
/>
|
|
</div>
|
|
<img
|
|
src={`${blessing.base_url}/auth/captcha?v=${this.state.time}`}
|
|
alt={t('auth.captcha')}
|
|
css={cssUtils.pointerCursor}
|
|
height={34}
|
|
title={t('auth.change-captcha')}
|
|
onClick={this.handleRefresh}
|
|
/>
|
|
</div>
|
|
);
|
|
}
|
|
}
|
|
|
|
export default Captcha;
|