X-Git-Url: http://these/git/?a=blobdiff_plain;f=src%2Fshared%2Fcomponents%2Fhome%2Fsignup.tsx;h=bb1e1f1142be867fd69c742914f90aa2b70d5ab6;hb=c3ab9e74f8775f4b811866d2675b00f9702bde3d;hp=2f6285033f620ae1cffa61c96116cf3d18645b87;hpb=24548ccba8cbfe95c883e763f3e3644d3f02139c;p=lemmy-ui.git diff --git a/src/shared/components/home/signup.tsx b/src/shared/components/home/signup.tsx index 2f62850..bb1e1f1 100644 --- a/src/shared/components/home/signup.tsx +++ b/src/shared/components/home/signup.tsx @@ -1,6 +1,8 @@ -import { None, Option, Some } from "@sniptt/monads"; +import { myAuth, setIsoData } from "@utils/app"; +import { isBrowser } from "@utils/browser"; +import { validEmail } from "@utils/helpers"; import { Options, passwordStrength } from "check-password-strength"; -import { I18nKeys } from "i18next"; +import { NoOptionI18nKeys } from "i18next"; import { Component, linkEvent } from "inferno"; import { T } from "inferno-i18next-dess"; import { @@ -8,26 +10,13 @@ import { GetCaptchaResponse, GetSiteResponse, LoginResponse, - Register, SiteView, - toUndefined, - UserOperation, - wsJsonToRes, - wsUserOp, } from "lemmy-js-client"; -import { Subscription } from "rxjs"; -import { i18n } from "../../i18next"; -import { UserService, WebSocketService } from "../../services"; -import { - isBrowser, - joinLemmyUrl, - mdToHtml, - setIsoData, - toast, - validEmail, - wsClient, - wsSubscribe, -} from "../../utils"; +import { joinLemmyUrl } from "../../config"; +import { mdToHtml } from "../../markdown"; +import { I18NextService, UserService } from "../../services"; +import { HttpService, RequestState } from "../../services/HttpService"; +import { toast } from "../../toast"; import { HtmlTags } from "../common/html-tags"; import { Icon, Spinner } from "../common/icon"; import { MarkdownTextArea } from "../common/markdown-textarea"; @@ -60,32 +49,33 @@ const passwordStrengthOptions: Options = [ ]; interface State { - registerForm: Register; - registerLoading: boolean; - captcha: Option; + registerRes: RequestState; + captchaRes: RequestState; + form: { + username?: string; + email?: string; + password?: string; + password_verify?: string; + show_nsfw: boolean; + captcha_uuid?: string; + captcha_answer?: string; + honeypot?: string; + answer?: string; + }; captchaPlaying: boolean; siteRes: GetSiteResponse; } export class Signup extends Component { private isoData = setIsoData(this.context); - private subscription: Subscription; - private audio: HTMLAudioElement; - - emptyState: State = { - registerForm: new Register({ - username: undefined, - password: undefined, - password_verify: undefined, + private audio?: HTMLAudioElement; + + state: State = { + registerRes: { state: "empty" }, + captchaRes: { state: "empty" }, + form: { show_nsfw: false, - captcha_uuid: None, - captcha_answer: None, - honeypot: None, - answer: None, - email: None, - }), - registerLoading: false, - captcha: None, + }, captchaPlaying: false, siteRes: this.isoData.site_res, }; @@ -93,30 +83,36 @@ export class Signup extends Component { constructor(props: any, context: any) { super(props, context); - this.state = this.emptyState; this.handleAnswerChange = this.handleAnswerChange.bind(this); + } - this.parseMessage = this.parseMessage.bind(this); - this.subscription = wsSubscribe(this.parseMessage); - - if (isBrowser()) { - WebSocketService.Instance.send(wsClient.getCaptcha()); + async componentDidMount() { + if (this.state.siteRes.site_view.local_site.captcha_enabled) { + await this.fetchCaptcha(); } } - componentWillUnmount() { - if (isBrowser()) { - this.subscription.unsubscribe(); - } + async fetchCaptcha() { + this.setState({ captchaRes: { state: "loading" } }); + this.setState({ + captchaRes: await HttpService.client.getCaptcha({}), + }); + + this.setState(s => { + if (s.captchaRes.state == "success") { + s.form.captcha_uuid = s.captchaRes.data.ok?.uuid; + } + return s; + }); } get documentTitle(): string { - let siteView = this.state.siteRes.site_view; + const siteView = this.state.siteRes.site_view; return `${this.titleName(siteView)} - ${siteView.site.name}`; } titleName(siteView: SiteView): string { - return i18n.t( + return I18NextService.i18n.t( siteView.local_site.private_instance ? "apply_to_join" : "sign_up" ); } @@ -127,12 +123,10 @@ export class Signup extends Component { render() { return ( -
+
@@ -144,13 +138,16 @@ export class Signup extends Component { } registerForm() { - let siteView = this.state.siteRes.site_view; + const siteView = this.state.siteRes.site_view; return ( -
-
{this.titleName(siteView)}
+ +

{this.titleName(siteView)}

{this.isLemmyMl && ( -
+
## @@ -159,12 +156,12 @@ export class Signup extends Component {
)} -
+
@@ -172,19 +169,19 @@ export class Signup extends Component { type="text" id="register-username" className="form-control" - value={this.state.registerForm.username} + value={this.state.form.username} onInput={linkEvent(this, this.handleRegisterUsernameChange)} required minLength={3} pattern="[a-zA-Z0-9_]+" - title={i18n.t("community_reqs")} + title={I18NextService.i18n.t("community_reqs")} />
-
+
{ className="form-control" placeholder={ siteView.local_site.require_email_verification - ? i18n.t("required") - : i18n.t("optional") + ? I18NextService.i18n.t("required") + : I18NextService.i18n.t("optional") } - value={toUndefined(this.state.registerForm.email)} + value={this.state.form.email} autoComplete="email" onInput={linkEvent(this, this.handleRegisterEmailChange)} required={siteView.local_site.require_email_verification} minLength={3} /> {!siteView.local_site.require_email_verification && - !this.state.registerForm.email.map(validEmail).unwrapOr(true) && ( + this.state.form.email && + !validEmail(this.state.form.email) && (
- - {i18n.t("no_password_reset")} + + {I18NextService.i18n.t("no_password_reset")}
)}
-
+
{ className="form-control" required /> - {this.state.registerForm.password && ( + {this.state.form.password && (
- {i18n.t(this.passwordStrength as I18nKeys)} + {I18NextService.i18n.t( + this.passwordStrength as NoOptionI18nKeys + )}
)}
-
+
{
- {siteView.local_site.require_application && ( + {siteView.local_site.registration_mode == "RequireApplication" && ( <> -
+
- - {i18n.t("fill_out_application")} + + {I18NextService.i18n.t("fill_out_application")}
- {siteView.local_site.application_question.match({ - some: question => ( -
- ), - none: <>, - })} + {siteView.local_site.application_question && ( +
+ )}
-
+
)} - - {this.state.captcha.isSome() && ( -
- - {this.showCaptcha()} -
+ {this.renderCaptcha()} +
+
+
+
- )} - {siteView.local_site.enable_nsfw && ( -
-
-
- - -
-
-
- )} +
{ type="text" className="form-control honeypot" id="register-honey" - value={toUndefined(this.state.registerForm.honeypot)} + value={this.state.form.honeypot} onInput={linkEvent(this, this.handleHoneyPotChange)} /> -
+
+ renderCaptcha() { + switch (this.state.captchaRes.state) { + case "loading": + return ; + case "success": { + const res = this.state.captchaRes.data; + return ( +
+ + {this.showCaptcha(res)} +
+ - ), - none: <>, - })} -
- ), - none: <>, - }); + required + /> +
+
+ ); + } + } + } + + showCaptcha(res: GetCaptchaResponse) { + const captchaRes = res?.ok; + return captchaRes ? ( +
+ <> + {I18NextService.i18n.t("captcha")} + {captchaRes.wav && ( + + )} + +
+ ) : ( + <> + ); } - get passwordStrength() { - return passwordStrength( - this.state.registerForm.password, - passwordStrengthOptions - ).value; + get passwordStrength(): string | undefined { + const password = this.state.form.password; + return password + ? passwordStrength(password, passwordStrengthOptions).value + : undefined; } get passwordColorClass(): string { - let strength = this.passwordStrength; + const strength = this.passwordStrength; - if (["weak", "medium"].includes(strength)) { + if (strength && ["weak", "medium"].includes(strength)) { return "text-warning"; } else if (strength == "strong") { return "text-success"; @@ -432,136 +430,143 @@ export class Signup extends Component { } } - handleRegisterSubmit(i: Signup, event: any) { + async handleRegisterSubmit(i: Signup, event: any) { event.preventDefault(); - i.setState({ registerLoading: true }); - WebSocketService.Instance.send(wsClient.register(i.state.registerForm)); + const { + show_nsfw, + answer, + captcha_answer, + captcha_uuid, + email, + honeypot, + password, + password_verify, + username, + } = i.state.form; + if (username && password && password_verify) { + i.setState({ registerRes: { state: "loading" } }); + + const registerRes = await HttpService.client.register({ + username, + password, + password_verify, + email, + show_nsfw, + captcha_uuid, + captcha_answer, + honeypot, + answer, + }); + switch (registerRes.state) { + case "failed": { + toast(registerRes.msg, "danger"); + i.setState({ registerRes: { state: "empty" } }); + break; + } + + case "success": { + const data = registerRes.data; + + // Only log them in if a jwt was set + if (data.jwt) { + UserService.Instance.login({ + res: data, + }); + + const site = await HttpService.client.getSite({ auth: myAuth() }); + + if (site.state === "success") { + UserService.Instance.myUserInfo = site.data.my_user; + } + + i.props.history.replace("/communities"); + } else { + if (data.verify_email_sent) { + toast(I18NextService.i18n.t("verify_email_sent")); + } + if (data.registration_created) { + toast(I18NextService.i18n.t("registration_application_sent")); + } + i.props.history.push("/"); + } + break; + } + } + } } handleRegisterUsernameChange(i: Signup, event: any) { - i.state.registerForm.username = event.target.value; + i.state.form.username = event.target.value.trim(); i.setState(i.state); } handleRegisterEmailChange(i: Signup, event: any) { - i.state.registerForm.email = Some(event.target.value); - if (i.state.registerForm.email.unwrap() == "") { - i.state.registerForm.email = None; + i.state.form.email = event.target.value; + if (i.state.form.email == "") { + i.state.form.email = undefined; } i.setState(i.state); } handleRegisterPasswordChange(i: Signup, event: any) { - i.state.registerForm.password = event.target.value; + i.state.form.password = event.target.value; i.setState(i.state); } handleRegisterPasswordVerifyChange(i: Signup, event: any) { - i.state.registerForm.password_verify = event.target.value; + i.state.form.password_verify = event.target.value; i.setState(i.state); } handleRegisterShowNsfwChange(i: Signup, event: any) { - i.state.registerForm.show_nsfw = event.target.checked; + i.state.form.show_nsfw = event.target.checked; i.setState(i.state); } handleRegisterCaptchaAnswerChange(i: Signup, event: any) { - i.state.registerForm.captcha_answer = Some(event.target.value); + i.state.form.captcha_answer = event.target.value; i.setState(i.state); } handleAnswerChange(val: string) { - this.setState(s => ((s.registerForm.answer = Some(val)), s)); + this.setState(s => ((s.form.answer = val), s)); } handleHoneyPotChange(i: Signup, event: any) { - i.state.registerForm.honeypot = Some(event.target.value); + i.state.form.honeypot = event.target.value; i.setState(i.state); } - handleRegenCaptcha(i: Signup) { - i.audio = null; + async handleRegenCaptcha(i: Signup) { + i.audio = undefined; i.setState({ captchaPlaying: false }); - WebSocketService.Instance.send(wsClient.getCaptcha()); + await i.fetchCaptcha(); } handleCaptchaPlay(i: Signup) { // This was a bad bug, it should only build the new audio on a new file. // Replays would stop prematurely if this was rebuilt every time. - i.state.captcha.match({ - some: captcha => - captcha.ok.match({ - some: res => { - if (i.audio == null) { - let base64 = `data:audio/wav;base64,${res.wav}`; - i.audio = new Audio(base64); - } - i.audio.play(); + if (i.state.captchaRes.state == "success" && i.state.captchaRes.data.ok) { + const captchaRes = i.state.captchaRes.data.ok; + if (!i.audio) { + const base64 = `data:audio/wav;base64,${captchaRes.wav}`; + i.audio = new Audio(base64); + i.audio.play(); - i.setState({ captchaPlaying: true }); + i.setState({ captchaPlaying: true }); - i.audio.addEventListener("ended", () => { - i.audio.currentTime = 0; - i.setState({ captchaPlaying: false }); - }); - }, - none: void 0, - }), - none: void 0, - }); - } - - captchaPngSrc(captcha: CaptchaResponse) { - return `data:image/png;base64,${captcha.png}`; - } - - parseMessage(msg: any) { - let op = wsUserOp(msg); - console.log(msg); - if (msg.error) { - toast(i18n.t(msg.error), "danger"); - this.setState(this.emptyState); - this.setState(s => ((s.registerForm.captcha_answer = undefined), s)); - // Refetch another captcha - // WebSocketService.Instance.send(wsClient.getCaptcha()); - return; - } else { - if (op == UserOperation.Register) { - let data = wsJsonToRes(msg, LoginResponse); - this.setState(this.emptyState); - // Only log them in if a jwt was set - if (data.jwt.isSome()) { - UserService.Instance.login(data); - this.props.history.push("/communities"); - location.reload(); - } else { - if (data.verify_email_sent) { - toast(i18n.t("verify_email_sent")); + i.audio.addEventListener("ended", () => { + if (i.audio) { + i.audio.currentTime = 0; + i.setState({ captchaPlaying: false }); } - if (data.registration_created) { - toast(i18n.t("registration_application_sent")); - } - this.props.history.push("/"); - } - } else if (op == UserOperation.GetCaptcha) { - let data = wsJsonToRes(msg, GetCaptchaResponse); - data.ok.match({ - some: res => { - this.setState({ captcha: Some(data) }); - this.setState( - s => ((s.registerForm.captcha_uuid = Some(res.uuid)), s) - ); - }, - none: void 0, }); - } else if (op == UserOperation.PasswordReset) { - toast(i18n.t("reset_password_mail_sent")); - } else if (op == UserOperation.GetSite) { - let data = wsJsonToRes(msg, GetSiteResponse); - this.setState({ siteRes: data }); } } } + + captchaPngSrc(captcha: CaptchaResponse) { + return `data:image/png;base64,${captcha.png}`; + } }