blessing-skin-server/resources/assets/src/components/Captcha.tsx
2025-01-19 15:25:15 +08:00

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;