]> Untitled Git - lemmy-ui.git/blobdiff - src/shared/components/home/signup.tsx
Add show/hide button to password fields (#1861)
[lemmy-ui.git] / src / shared / components / home / signup.tsx
index 6961a14af068a6b1e4fa7ad3f1e614d45bba8ca6..c57d545aa8b368045ab495baf3b7e5e52b61bfaf 100644 (file)
@@ -1,6 +1,6 @@
+import { myAuth, setIsoData } from "@utils/app";
 import { isBrowser } from "@utils/browser";
-import { Options, passwordStrength } from "check-password-strength";
-import { NoOptionI18nKeys } from "i18next";
+import { validEmail } from "@utils/helpers";
 import { Component, linkEvent } from "inferno";
 import { T } from "inferno-i18next-dess";
 import {
@@ -10,47 +10,15 @@ import {
   LoginResponse,
   SiteView,
 } from "lemmy-js-client";
-import { i18n } from "../../i18next";
-import { UserService } from "../../services";
+import { joinLemmyUrl } from "../../config";
+import { mdToHtml } from "../../markdown";
+import { I18NextService, UserService } from "../../services";
 import { HttpService, RequestState } from "../../services/HttpService";
-import {
-  joinLemmyUrl,
-  mdToHtml,
-  myAuth,
-  setIsoData,
-  toast,
-  validEmail,
-} from "../../utils";
+import { toast } from "../../toast";
 import { HtmlTags } from "../common/html-tags";
 import { Icon, Spinner } from "../common/icon";
 import { MarkdownTextArea } from "../common/markdown-textarea";
-
-const passwordStrengthOptions: Options<string> = [
-  {
-    id: 0,
-    value: "very_weak",
-    minDiversity: 0,
-    minLength: 0,
-  },
-  {
-    id: 1,
-    value: "weak",
-    minDiversity: 2,
-    minLength: 10,
-  },
-  {
-    id: 2,
-    value: "medium",
-    minDiversity: 3,
-    minLength: 12,
-  },
-  {
-    id: 3,
-    value: "strong",
-    minDiversity: 4,
-    minLength: 14,
-  },
-];
+import PasswordInput from "../common/password-input";
 
 interface State {
   registerRes: RequestState<LoginResponse>;
@@ -116,7 +84,7 @@ export class Signup extends Component<any, State> {
   }
 
   titleName(siteView: SiteView): string {
-    return i18n.t(
+    return I18NextService.i18n.t(
       siteView.local_site.private_instance ? "apply_to_join" : "sign_up"
     );
   }
@@ -127,7 +95,7 @@ export class Signup extends Component<any, State> {
 
   render() {
     return (
-      <div className="container-lg">
+      <div className="home-signup container-lg">
         <HtmlTags
           title={this.documentTitle}
           path={this.context.router.route.match.url}
@@ -144,11 +112,14 @@ export class Signup extends Component<any, State> {
   registerForm() {
     const siteView = this.state.siteRes.site_view;
     return (
-      <form onSubmit={linkEvent(this, this.handleRegisterSubmit)}>
-        <h5>{this.titleName(siteView)}</h5>
+      <form
+        className="was-validated"
+        onSubmit={linkEvent(this, this.handleRegisterSubmit)}
+      >
+        <h1 className="h4 mb-4">{this.titleName(siteView)}</h1>
 
         {this.isLemmyMl && (
-          <div className="form-group row">
+          <div className="mb-3 row">
             <div className="mt-2 mb-0 alert alert-warning" role="alert">
               <T i18nKey="lemmy_ml_registration_message">
                 #<a href={joinLemmyUrl}>#</a>
@@ -157,12 +128,12 @@ export class Signup extends Component<any, State> {
           </div>
         )}
 
-        <div className="form-group row">
+        <div className="mb-3 row">
           <label
             className="col-sm-2 col-form-label"
             htmlFor="register-username"
           >
-            {i18n.t("username")}
+            {I18NextService.i18n.t("username")}
           </label>
 
           <div className="col-sm-10">
@@ -175,14 +146,14 @@ export class Signup extends Component<any, State> {
               required
               minLength={3}
               pattern="[a-zA-Z0-9_]+"
-              title={i18n.t("community_reqs")}
+              title={I18NextService.i18n.t("community_reqs")}
             />
           </div>
         </div>
 
-        <div className="form-group row">
+        <div className="mb-3 row">
           <label className="col-sm-2 col-form-label" htmlFor="register-email">
-            {i18n.t("email")}
+            {I18NextService.i18n.t("email")}
           </label>
           <div className="col-sm-10">
             <input
@@ -191,8 +162,8 @@ export class Signup extends Component<any, State> {
               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={this.state.form.email}
               autoComplete="email"
@@ -204,68 +175,39 @@ export class Signup extends Component<any, State> {
               this.state.form.email &&
               !validEmail(this.state.form.email) && (
                 <div className="mt-2 mb-0 alert alert-warning" role="alert">
-                  <Icon icon="alert-triangle" classes="icon-inline mr-2" />
-                  {i18n.t("no_password_reset")}
+                  <Icon icon="alert-triangle" classes="icon-inline me-2" />
+                  {I18NextService.i18n.t("no_password_reset")}
                 </div>
               )}
           </div>
         </div>
 
-        <div className="form-group row">
-          <label
-            className="col-sm-2 col-form-label"
-            htmlFor="register-password"
-          >
-            {i18n.t("password")}
-          </label>
-          <div className="col-sm-10">
-            <input
-              type="password"
-              id="register-password"
-              value={this.state.form.password}
-              autoComplete="new-password"
-              onInput={linkEvent(this, this.handleRegisterPasswordChange)}
-              minLength={10}
-              maxLength={60}
-              className="form-control"
-              required
-            />
-            {this.state.form.password && (
-              <div className={this.passwordColorClass}>
-                {i18n.t(this.passwordStrength as NoOptionI18nKeys)}
-              </div>
-            )}
-          </div>
+        <div className="mb-3">
+          <PasswordInput
+            id="register-password"
+            value={this.state.form.password}
+            onInput={linkEvent(this, this.handleRegisterPasswordChange)}
+            showStrength
+            label={I18NextService.i18n.t("password")}
+          />
         </div>
 
-        <div className="form-group row">
-          <label
-            className="col-sm-2 col-form-label"
-            htmlFor="register-verify-password"
-          >
-            {i18n.t("verify_password")}
-          </label>
-          <div className="col-sm-10">
-            <input
-              type="password"
-              id="register-verify-password"
-              value={this.state.form.password_verify}
-              autoComplete="new-password"
-              onInput={linkEvent(this, this.handleRegisterPasswordVerifyChange)}
-              maxLength={60}
-              className="form-control"
-              required
-            />
-          </div>
+        <div className="mb-3">
+          <PasswordInput
+            id="register-verify-password"
+            value={this.state.form.password_verify}
+            onInput={linkEvent(this, this.handleRegisterPasswordVerifyChange)}
+            label={I18NextService.i18n.t("verify_password")}
+          />
         </div>
 
-        {siteView.local_site.registration_mode == "RequireApplication" && (
+        {siteView.local_site.registration_mode === "RequireApplication" && (
           <>
-            <div className="form-group row">
+            <div className="mb-3 row">
               <div className="offset-sm-2 col-sm-10">
                 <div className="mt-2 alert alert-warning" role="alert">
-                  <Icon icon="alert-triangle" classes="icon-inline mr-2" />
-                  {i18n.t("fill_out_application")}
+                  <Icon icon="alert-triangle" classes="icon-inline me-2" />
+                  {I18NextService.i18n.t("fill_out_application")}
                 </div>
                 {siteView.local_site.application_question && (
                   <div
@@ -278,12 +220,12 @@ export class Signup extends Component<any, State> {
               </div>
             </div>
 
-            <div className="form-group row">
+            <div className="mb-3 row">
               <label
                 className="col-sm-2 col-form-label"
                 htmlFor="application_answer"
               >
-                {i18n.t("answer")}
+                {I18NextService.i18n.t("answer")}
               </label>
               <div className="col-sm-10">
                 <MarkdownTextArea
@@ -298,7 +240,7 @@ export class Signup extends Component<any, State> {
           </>
         )}
         {this.renderCaptcha()}
-        <div className="form-group row">
+        <div className="mb-3 row">
           <div className="col-sm-10">
             <div className="form-check">
               <input
@@ -309,7 +251,7 @@ export class Signup extends Component<any, State> {
                 onChange={linkEvent(this, this.handleRegisterShowNsfwChange)}
               />
               <label className="form-check-label" htmlFor="register-show-nsfw">
-                {i18n.t("show_nsfw")}
+                {I18NextService.i18n.t("show_nsfw")}
               </label>
             </div>
           </div>
@@ -324,7 +266,7 @@ export class Signup extends Component<any, State> {
           value={this.state.form.honeypot}
           onInput={linkEvent(this, this.handleHoneyPotChange)}
         />
-        <div className="form-group row">
+        <div className="mb-3 row">
           <div className="col-sm-10">
             <button type="submit" className="btn btn-secondary">
               {this.state.registerRes.state == "loading" ? (
@@ -346,14 +288,16 @@ export class Signup extends Component<any, State> {
       case "success": {
         const res = this.state.captchaRes.data;
         return (
-          <div className="form-group row">
+          <div className="mb-3 row">
             <label className="col-sm-2" htmlFor="register-captcha">
-              <span className="mr-2">{i18n.t("enter_code")}</span>
+              <span className="me-2">
+                {I18NextService.i18n.t("enter_code")}
+              </span>
               <button
                 type="button"
                 className="btn btn-secondary"
                 onClick={linkEvent(this, this.handleRegenCaptcha)}
-                aria-label={i18n.t("captcha")}
+                aria-label={I18NextService.i18n.t("captcha")}
               >
                 <Icon icon="refresh-cw" classes="icon-refresh-cw" />
               </button>
@@ -387,13 +331,13 @@ export class Signup extends Component<any, State> {
             className="rounded-top img-fluid"
             src={this.captchaPngSrc(captchaRes)}
             style="border-bottom-right-radius: 0; border-bottom-left-radius: 0;"
-            alt={i18n.t("captcha")}
+            alt={I18NextService.i18n.t("captcha")}
           />
           {captchaRes.wav && (
             <button
-              className="rounded-bottom btn btn-sm btn-secondary btn-block"
+              className="rounded-bottom btn btn-sm btn-secondary d-block"
               style="border-top-right-radius: 0; border-top-left-radius: 0;"
-              title={i18n.t("play_captcha_audio")}
+              title={I18NextService.i18n.t("play_captcha_audio")}
               onClick={linkEvent(this, this.handleCaptchaPlay)}
               type="button"
               disabled={this.state.captchaPlaying}
@@ -408,25 +352,6 @@ export class Signup extends Component<any, State> {
     );
   }
 
-  get passwordStrength(): string | undefined {
-    const password = this.state.form.password;
-    return password
-      ? passwordStrength(password, passwordStrengthOptions).value
-      : undefined;
-  }
-
-  get passwordColorClass(): string {
-    const strength = this.passwordStrength;
-
-    if (strength && ["weak", "medium"].includes(strength)) {
-      return "text-warning";
-    } else if (strength == "strong") {
-      return "text-success";
-    } else {
-      return "text-danger";
-    }
-  }
-
   async handleRegisterSubmit(i: Signup, event: any) {
     event.preventDefault();
     const {
@@ -466,7 +391,9 @@ export class Signup extends Component<any, State> {
 
           // Only log them in if a jwt was set
           if (data.jwt) {
-            UserService.Instance.login(data);
+            UserService.Instance.login({
+              res: data,
+            });
 
             const site = await HttpService.client.getSite({ auth: myAuth() });
 
@@ -477,10 +404,10 @@ export class Signup extends Component<any, State> {
             i.props.history.replace("/communities");
           } else {
             if (data.verify_email_sent) {
-              toast(i18n.t("verify_email_sent"));
+              toast(I18NextService.i18n.t("verify_email_sent"));
             }
             if (data.registration_created) {
-              toast(i18n.t("registration_application_sent"));
+              toast(I18NextService.i18n.t("registration_application_sent"));
             }
             i.props.history.push("/");
           }