]> Untitled Git - lemmy-ui.git/blobdiff - src/shared/components/person/profile.tsx
Use canonical URLs (#1883)
[lemmy-ui.git] / src / shared / components / person / profile.tsx
index d00036871a04c9ec922c93a56e5c9b6eb43fec8b..d493f787d5602240ef2b0bfc339315da72863a10 100644 (file)
@@ -18,11 +18,14 @@ import {
   getQueryParams,
   getQueryString,
   numToSI,
+  randomStr,
 } from "@utils/helpers";
 import { canMod, isAdmin, isBanned } from "@utils/roles";
 import type { QueryParams } from "@utils/types";
 import { RouteDataResponse } from "@utils/types";
 import classNames from "classnames";
+import format from "date-fns/format";
+import parseISO from "date-fns/parseISO";
 import { NoOptionI18nKeys } from "i18next";
 import { Component, linkEvent } from "inferno";
 import { Link } from "inferno-router";
@@ -70,7 +73,6 @@ import {
   SortType,
   TransferCommunity,
 } from "lemmy-js-client";
-import moment from "moment";
 import { fetchLimit, relTags } from "../../config";
 import { InitialFetchRequest, PersonDetailsView } from "../../interfaces";
 import { mdToHtml } from "../../markdown";
@@ -83,6 +85,7 @@ import { HtmlTags } from "../common/html-tags";
 import { Icon, Spinner } from "../common/icon";
 import { MomentTime } from "../common/moment-time";
 import { SortSelect } from "../common/sort-select";
+import { UserBadges } from "../common/user-badges";
 import { CommunityLink } from "../community/community-link";
 import { PersonDetails } from "./person-details";
 import { PersonListing } from "./person-listing";
@@ -135,7 +138,7 @@ const getCommunitiesListing = (
   communityViews.length > 0 && (
     <div className="card border-secondary mb-3">
       <div className="card-body">
-        <h5>{I18NextService.i18n.t(translationKey)}</h5>
+        <h2 className="h5">{I18NextService.i18n.t(translationKey)}</h2>
         <ul className="list-unstyled mb-0">
           {communityViews.map(({ community }) => (
             <li key={community.id}>
@@ -204,6 +207,7 @@ export class Profile extends Component<
     this.handleSavePost = this.handleSavePost.bind(this);
     this.handlePurgePost = this.handlePurgePost.bind(this);
     this.handleFeaturePost = this.handleFeaturePost.bind(this);
+    this.handleModBanSubmit = this.handleModBanSubmit.bind(this);
 
     // Only fetch the data if coming from another route
     if (FirstLoadService.isFirstLoad) {
@@ -229,7 +233,7 @@ export class Profile extends Component<
   async fetchUserData() {
     const { page, sort, view } = getProfileQueryParams();
 
-    this.setState({ personRes: { state: "empty" } });
+    this.setState({ personRes: { state: "loading" } });
     this.setState({
       personRes: await HttpService.client.getPersonDetails({
         username: this.props.match.params.username,
@@ -320,6 +324,7 @@ export class Profile extends Component<
               <HtmlTags
                 title={this.documentTitle}
                 path={this.context.router.route.match.url}
+                canonicalPath={personRes.person_view.person.actor_id}
                 description={personRes.person_view.person.bio}
                 image={personRes.person_view.person.avatar}
               />
@@ -394,7 +399,7 @@ export class Profile extends Component<
 
   get viewRadios() {
     return (
-      <div className="btn-group btn-group-toggle flex-wrap mb-2">
+      <div className="btn-group btn-group-toggle flex-wrap mb-2" role="group">
         {this.getRadio(PersonDetailsView.Overview)}
         {this.getRadio(PersonDetailsView.Comments)}
         {this.getRadio(PersonDetailsView.Posts)}
@@ -406,22 +411,27 @@ export class Profile extends Component<
   getRadio(view: PersonDetailsView) {
     const { view: urlView } = getProfileQueryParams();
     const active = view === urlView;
+    const radioId = randomStr();
 
     return (
-      <label
-        className={classNames("btn btn-outline-secondary pointer", {
-          active,
-        })}
-      >
+      <>
         <input
+          id={radioId}
           type="radio"
           className="btn-check"
           value={view}
           checked={active}
           onChange={linkEvent(this, this.handleViewChange)}
         />
-        {I18NextService.i18n.t(view.toLowerCase() as NoOptionI18nKeys)}
-      </label>
+        <label
+          htmlFor={radioId}
+          className={classNames("btn btn-outline-secondary pointer", {
+            active,
+          })}
+        >
+          {I18NextService.i18n.t(view.toLowerCase() as NoOptionI18nKeys)}
+        </label>
+      </>
     );
   }
 
@@ -469,7 +479,7 @@ export class Profile extends Component<
               <div className="mb-0 d-flex flex-wrap">
                 <div>
                   {pv.person.display_name && (
-                    <h5 className="mb-0">{pv.person.display_name}</h5>
+                    <h1 className="h4 mb-4">{pv.person.display_name}</h1>
                   )}
                   <ul className="list-inline mb-2">
                     <li className="list-inline-item">
@@ -481,26 +491,15 @@ export class Profile extends Component<
                         hideAvatar
                       />
                     </li>
-                    {isBanned(pv.person) && (
-                      <li className="list-inline-item badge text-bg-danger">
-                        {I18NextService.i18n.t("banned")}
-                      </li>
-                    )}
-                    {pv.person.deleted && (
-                      <li className="list-inline-item badge text-bg-danger">
-                        {I18NextService.i18n.t("deleted")}
-                      </li>
-                    )}
-                    {pv.person.admin && (
-                      <li className="list-inline-item badge text-bg-light">
-                        {I18NextService.i18n.t("admin")}
-                      </li>
-                    )}
-                    {pv.person.bot_account && (
-                      <li className="list-inline-item badge text-bg-light">
-                        {I18NextService.i18n.t("bot_account").toLowerCase()}
-                      </li>
-                    )}
+                    <li className="list-inline-item">
+                      <UserBadges
+                        classNames="ms-1"
+                        isBanned={isBanned(pv.person)}
+                        isDeleted={pv.person.deleted}
+                        isAdmin={pv.person.admin}
+                        isBot={pv.person.bot_account}
+                      />
+                    </li>
                   </ul>
                 </div>
                 {this.banDialog(pv)}
@@ -613,10 +612,7 @@ export class Profile extends Component<
                 <Icon icon="cake" />
                 <span className="ms-2">
                   {I18NextService.i18n.t("cake_day_title")}{" "}
-                  {moment
-                    .utc(pv.person.published)
-                    .local()
-                    .format("MMM DD, YYYY")}
+                  {format(parseISO(pv.person.published), "PPP")}
                 </span>
               </div>
               {!UserService.Instance.myUserInfo && (
@@ -649,12 +645,12 @@ export class Profile extends Component<
               value={this.state.banReason}
               onInput={linkEvent(this, this.handleModBanReasonChange)}
             />
-            <label className="col-form-label" htmlFor={`mod-ban-expires`}>
+            <label className="col-form-label" htmlFor="mod-ban-expires">
               {I18NextService.i18n.t("expires")}
             </label>
             <input
               type="number"
-              id={`mod-ban-expires`}
+              id="mod-ban-expires"
               className="form-control me-2"
               placeholder={I18NextService.i18n.t("number_of_days")}
               value={this.state.banExpireDays}
@@ -693,6 +689,8 @@ export class Profile extends Component<
             >
               {I18NextService.i18n.t("cancel")}
             </button>
+          </div>
+          <div className="mb-3 row">
             <button
               type="submit"
               className="btn btn-secondary"
@@ -989,6 +987,7 @@ export class Profile extends Component<
           s.personRes.data.comments
             .filter(c => c.creator.id == banRes.data.person_view.person.id)
             .forEach(c => (c.creator.banned = banRes.data.banned));
+          s.personRes.data.person_view.person.banned = banRes.data.banned;
         }
         return s;
       });