]> Untitled Git - lemmy-ui.git/commitdiff
Adding create private message.
authorDessalines <tyhou13@gmx.com>
Tue, 8 Sep 2020 18:44:55 +0000 (13:44 -0500)
committerDessalines <tyhou13@gmx.com>
Tue, 8 Sep 2020 18:44:55 +0000 (13:44 -0500)
src/shared/components/comment-node.tsx
src/shared/components/community.tsx
src/shared/components/create-post.tsx
src/shared/components/create-private-message.tsx
src/shared/components/private-message-form.tsx
src/shared/components/sidebar.tsx
src/shared/components/user.tsx
src/shared/routes.ts
src/shared/utils.ts

index 4a27280f96650f2e088bd48e20c9b7415627a873..b9edcae4ad678c7eaab209625fae6536ffa8a7d2 100644 (file)
@@ -344,7 +344,7 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
                             <button class="btn btn-link btn-animate">
                               <Link
                                 class="text-muted"
-                                to={`/create_private_message?recipient_id=${node.comment.creator_id}`}
+                                to={`/create_private_message/recipient/${node.comment.creator_id}`}
                                 title={i18n.t('message').toLowerCase()}
                               >
                                 <svg class="icon">
index bd23b173c683ee41a0d49b5de19c5f6b2d878400..d8c51a3d65eec6c3d10ec94415a252cb48665472 100644 (file)
@@ -21,6 +21,8 @@ import {
   CommentResponse,
   WebSocketJsonResponse,
   GetSiteResponse,
+  Category,
+  ListCategoriesResponse,
 } from 'lemmy-js-client';
 import { UserService, WebSocketService } from '../services';
 import { PostListings } from './post-listings';
@@ -65,6 +67,7 @@ interface State {
   dataType: DataType;
   sort: SortType;
   page: number;
+  categories: Category[];
 }
 
 interface CommunityProps {
@@ -93,6 +96,7 @@ export class Community extends Component<any, State> {
     sort: getSortTypeFromProps(this.props),
     page: getPageFromProps(this.props),
     siteRes: this.isoData.site,
+    categories: [],
   };
 
   constructor(props: any, context: any) {
@@ -113,10 +117,12 @@ export class Community extends Component<any, State> {
       } else {
         this.state.comments = this.isoData.routeData[1].comments;
       }
+      this.state.categories = this.isoData.routeData[2].categories;
       this.state.loading = false;
     } else {
       this.fetchCommunity();
       this.fetchData();
+      WebSocketService.Instance.listCategories();
     }
     setupTippy();
   }
@@ -195,6 +201,8 @@ export class Community extends Component<any, State> {
       promises.push(lemmyHttp.getComments(getCommentsForm));
     }
 
+    promises.push(lemmyHttp.listCategories());
+
     return promises;
   }
 
@@ -263,6 +271,7 @@ export class Community extends Component<any, State> {
                 admins={this.state.siteRes.admins}
                 online={this.state.communityRes.online}
                 enableNsfw={this.state.siteRes.site.enable_nsfw}
+                categories={this.state.categories}
               />
             </div>
           </div>
@@ -425,6 +434,9 @@ export class Community extends Component<any, State> {
     } else if (res.op == UserOperation.GetCommunity) {
       let data = res.data as GetCommunityResponse;
       this.state.communityRes = data;
+      if (this.state.posts.length || this.state.comments.length) {
+        this.state.loading = false;
+      }
       this.setState(this.state);
     } else if (
       res.op == UserOperation.EditCommunity ||
@@ -443,7 +455,10 @@ export class Community extends Component<any, State> {
     } else if (res.op == UserOperation.GetPosts) {
       let data = res.data as GetPostsResponse;
       this.state.posts = data.posts;
-      this.state.loading = false;
+
+      if (this.state.communityRes) {
+        this.state.loading = false;
+      }
       this.setState(this.state);
       setupTippy();
     } else if (
@@ -480,7 +495,9 @@ export class Community extends Component<any, State> {
     } else if (res.op == UserOperation.GetComments) {
       let data = res.data as GetCommentsResponse;
       this.state.comments = data.comments;
-      this.state.loading = false;
+      if (this.state.communityRes) {
+        this.state.loading = false;
+      }
       this.setState(this.state);
     } else if (
       res.op == UserOperation.EditComment ||
@@ -506,6 +523,10 @@ export class Community extends Component<any, State> {
       let data = res.data as CommentResponse;
       createCommentLikeRes(data, this.state.comments);
       this.setState(this.state);
+    } else if (res.op == UserOperation.ListCategories) {
+      let data = res.data as ListCategoriesResponse;
+      this.state.categories = data.categories;
+      this.setState(this.state);
     }
   }
 }
index fc759d0f08b67948db9d769dd2cb4649daae9640..25d4f593c2b4bdc8f19958ac4e73fc1fc21f057c 100644 (file)
@@ -3,6 +3,7 @@ import { Helmet } from 'inferno-helmet';
 import { Subscription } from 'rxjs';
 import { PostForm } from './post-form';
 import {
+  isBrowser,
   lemmyHttp,
   setAuth,
   setIsoData,
@@ -69,7 +70,9 @@ export class CreatePost extends Component<any, CreatePostState> {
   }
 
   componentWillUnmount() {
-    this.subscription.unsubscribe();
+    if (isBrowser()) {
+      this.subscription.unsubscribe();
+    }
   }
 
   get documentTitle(): string {
index 98c69d5b74bfa15b30799ca024138e062fa7d341..efdd5315cf36336c2f498bdf88adebebadc4b5aa 100644 (file)
@@ -1,30 +1,49 @@
 import { Component } from 'inferno';
 import { Helmet } from 'inferno-helmet';
 import { Subscription } from 'rxjs';
-import { retryWhen, delay, take } from 'rxjs/operators';
 import { PrivateMessageForm } from './private-message-form';
-import { WebSocketService, UserService } from '../services';
+import { UserService, WebSocketService } from '../services';
 import {
-  UserOperation,
-  WebSocketJsonResponse,
-  GetSiteResponse,
   Site,
-  PrivateMessageFormParams,
+  WebSocketJsonResponse,
+  UserOperation,
+  UserDetailsResponse,
+  UserView,
+  SortType,
+  GetUserDetailsForm,
 } from 'lemmy-js-client';
-import { toast, wsJsonToRes } from '../utils';
+import {
+  getRecipientIdFromProps,
+  isBrowser,
+  lemmyHttp,
+  setAuth,
+  setIsoData,
+  toast,
+  wsJsonToRes,
+  wsSubscribe,
+} from '../utils';
 import { i18n } from '../i18next';
 
+interface CreatePrivateMessageProps {}
+
 interface CreatePrivateMessageState {
   site: Site;
+  recipient: UserView;
+  recipient_id: number;
+  loading: boolean;
 }
 
 export class CreatePrivateMessage extends Component<
-  any,
+  CreatePrivateMessageProps,
   CreatePrivateMessageState
 > {
+  private isoData = setIsoData(this.context);
   private subscription: Subscription;
   private emptyState: CreatePrivateMessageState = {
-    site: undefined,
+    site: this.isoData.site.site,
+    recipient: undefined,
+    recipient_id: getRecipientIdFromProps(this.props),
+    loading: true,
   };
   constructor(props: any, context: any) {
     super(props, context);
@@ -33,31 +52,50 @@ export class CreatePrivateMessage extends Component<
       this
     );
 
+    this.parseMessage = this.parseMessage.bind(this);
+    this.subscription = wsSubscribe(this.parseMessage);
+
     if (!UserService.Instance.user) {
       toast(i18n.t('not_logged_in'), 'danger');
       this.context.router.history.push(`/login`);
     }
 
-    this.subscription = WebSocketService.Instance.subject
-      .pipe(retryWhen(errors => errors.pipe(delay(3000), take(10))))
-      .subscribe(
-        msg => this.parseMessage(msg),
-        err => console.error(err),
-        () => console.log('complete')
-      );
+    // Only fetch the data if coming from another route
+    if (this.isoData.path == this.context.router.route.match.url) {
+      this.state.recipient = this.isoData.routeData[0].user;
+      this.state.loading = false;
+    } else {
+      this.fetchUserDetails();
+    }
+  }
 
-    WebSocketService.Instance.getSite();
+  fetchUserDetails() {
+    let form: GetUserDetailsForm = {
+      user_id: this.state.recipient_id,
+      sort: SortType.New,
+      saved_only: false,
+    };
+    WebSocketService.Instance.getUserDetails(form);
   }
 
-  componentWillUnmount() {
-    this.subscription.unsubscribe();
+  static fetchInitialData(auth: string, path: string): Promise<any>[] {
+    let user_id = Number(path.split('/').pop());
+    let form: GetUserDetailsForm = {
+      user_id,
+      sort: SortType.New,
+      saved_only: false,
+    };
+    setAuth(form, auth);
+    return [lemmyHttp.getUserDetails(form)];
   }
 
   get documentTitle(): string {
-    if (this.state.site) {
-      return `${i18n.t('create_private_message')} - ${this.state.site.name}`;
-    } else {
-      return 'Lemmy';
+    return `${i18n.t('create_private_message')} - ${this.state.site.name}`;
+  }
+
+  componentWillUnmount() {
+    if (isBrowser()) {
+      this.subscription.unsubscribe();
     }
   }
 
@@ -65,44 +103,45 @@ export class CreatePrivateMessage extends Component<
     return (
       <div class="container">
         <Helmet title={this.documentTitle} />
-        <div class="row">
-          <div class="col-12 col-lg-6 offset-lg-3 mb-4">
-            <h5>{i18n.t('create_private_message')}</h5>
-            <PrivateMessageForm
-              onCreate={this.handlePrivateMessageCreate}
-              params={this.params}
-            />
+        {this.state.loading ? (
+          <h5>
+            <svg class="icon icon-spinner spin">
+              <use xlinkHref="#icon-spinner"></use>
+            </svg>
+          </h5>
+        ) : (
+          <div class="row">
+            <div class="col-12 col-lg-6 offset-lg-3 mb-4">
+              <h5>{i18n.t('create_private_message')}</h5>
+              <PrivateMessageForm
+                onCreate={this.handlePrivateMessageCreate}
+                recipient={this.state.recipient}
+              />
+            </div>
           </div>
-        </div>
+        )}
       </div>
     );
   }
 
-  get params(): PrivateMessageFormParams {
-    let urlParams = new URLSearchParams(this.props.location.search);
-    let params: PrivateMessageFormParams = {
-      recipient_id: Number(urlParams.get('recipient_id')),
-    };
-
-    return params;
-  }
-
   handlePrivateMessageCreate() {
     toast(i18n.t('message_sent'));
 
     // Navigate to the front
-    this.props.history.push(`/`);
+    this.context.router.history.push(`/`);
   }
 
   parseMessage(msg: WebSocketJsonResponse) {
-    console.log(msg);
     let res = wsJsonToRes(msg);
     if (msg.error) {
       toast(i18n.t(msg.error), 'danger');
+      this.state.loading = false;
+      this.setState(this.state);
       return;
-    } else if (res.op == UserOperation.GetSite) {
-      let data = res.data as GetSiteResponse;
-      this.state.site = data.site;
+    } else if (res.op == UserOperation.GetUserDetails) {
+      let data = res.data as UserDetailsResponse;
+      this.state.recipient = data.user;
+      this.state.loading = false;
       this.setState(this.state);
     }
   }
index 6d7825cd0c08c6455c9edbbd56d4e280222edb40..6abc5f337eb923af31b50379be74d8c6ad903897 100644 (file)
@@ -1,18 +1,13 @@
 import { Component, linkEvent } from 'inferno';
 import { Prompt } from 'inferno-router';
 import { Subscription } from 'rxjs';
-import { retryWhen, delay, take } from 'rxjs/operators';
 import {
   PrivateMessageForm as PrivateMessageFormI,
   EditPrivateMessageForm,
-  PrivateMessageFormParams,
   PrivateMessage,
   PrivateMessageResponse,
   UserView,
   UserOperation,
-  UserDetailsResponse,
-  GetUserDetailsForm,
-  SortType,
   WebSocketJsonResponse,
 } from 'lemmy-js-client';
 import { WebSocketService } from '../services';
@@ -21,6 +16,8 @@ import {
   wsJsonToRes,
   toast,
   setupTippy,
+  wsSubscribe,
+  isBrowser,
 } from '../utils';
 import { UserListing } from './user-listing';
 import { MarkdownTextArea } from './markdown-textarea';
@@ -28,8 +25,8 @@ import { i18n } from '../i18next';
 import { T } from 'inferno-i18next';
 
 interface PrivateMessageFormProps {
+  recipient: UserView;
   privateMessage?: PrivateMessage; // If a pm is given, that means this is an edit
-  params?: PrivateMessageFormParams;
   onCancel?(): any;
   onCreate?(message: PrivateMessage): any;
   onEdit?(message: PrivateMessage): any;
@@ -37,7 +34,6 @@ interface PrivateMessageFormProps {
 
 interface PrivateMessageFormState {
   privateMessageForm: PrivateMessageFormI;
-  recipient: UserView;
   loading: boolean;
   previewMode: boolean;
   showDisclaimer: boolean;
@@ -51,9 +47,8 @@ export class PrivateMessageForm extends Component<
   private emptyState: PrivateMessageFormState = {
     privateMessageForm: {
       content: null,
-      recipient_id: null,
+      recipient_id: this.props.recipient.id,
     },
-    recipient: null,
     loading: false,
     previewMode: false,
     showDisclaimer: false,
@@ -66,30 +61,15 @@ export class PrivateMessageForm extends Component<
 
     this.handleContentChange = this.handleContentChange.bind(this);
 
+    this.parseMessage = this.parseMessage.bind(this);
+    this.subscription = wsSubscribe(this.parseMessage);
+
     if (this.props.privateMessage) {
       this.state.privateMessageForm = {
         content: this.props.privateMessage.content,
         recipient_id: this.props.privateMessage.recipient_id,
       };
     }
-
-    if (this.props.params) {
-      this.state.privateMessageForm.recipient_id = this.props.params.recipient_id;
-      let form: GetUserDetailsForm = {
-        user_id: this.state.privateMessageForm.recipient_id,
-        sort: SortType.New,
-        saved_only: false,
-      };
-      WebSocketService.Instance.getUserDetails(form);
-    }
-
-    this.subscription = WebSocketService.Instance.subject
-      .pipe(retryWhen(errors => errors.pipe(delay(3000), take(10))))
-      .subscribe(
-        msg => this.parseMessage(msg),
-        err => console.error(err),
-        () => console.log('complete')
-      );
   }
 
   componentDidMount() {
@@ -105,8 +85,10 @@ export class PrivateMessageForm extends Component<
   }
 
   componentWillUnmount() {
-    this.subscription.unsubscribe();
-    window.onbeforeunload = null;
+    if (isBrowser()) {
+      this.subscription.unsubscribe();
+      window.onbeforeunload = null;
+    }
   }
 
   render() {
@@ -123,21 +105,18 @@ export class PrivateMessageForm extends Component<
                 {capitalizeFirstLetter(i18n.t('to'))}
               </label>
 
-              {this.state.recipient && (
-                <div class="col-sm-10 form-control-plaintext">
-                  <UserListing
-                    user={{
-                      name: this.state.recipient.name,
-                      preferred_username: this.state.recipient
-                        .preferred_username,
-                      avatar: this.state.recipient.avatar,
-                      id: this.state.recipient.id,
-                      local: this.state.recipient.local,
-                      actor_id: this.state.recipient.actor_id,
-                    }}
-                  />
-                </div>
-              )}
+              <div class="col-sm-10 form-control-plaintext">
+                <UserListing
+                  user={{
+                    name: this.props.recipient.name,
+                    preferred_username: this.props.recipient.preferred_username,
+                    avatar: this.props.recipient.avatar,
+                    id: this.props.recipient.id,
+                    local: this.props.recipient.local,
+                    actor_id: this.props.recipient.actor_id,
+                  }}
+                />
+              </div>
             </div>
           )}
           <div class="form-group row">
@@ -233,11 +212,6 @@ export class PrivateMessageForm extends Component<
     i.setState(i.state);
   }
 
-  handleRecipientChange(i: PrivateMessageForm, event: any) {
-    i.state.recipient = event.target.value;
-    i.setState(i.state);
-  }
-
   handleContentChange(val: string) {
     this.state.privateMessageForm.content = val;
     this.setState(this.state);
@@ -273,11 +247,6 @@ export class PrivateMessageForm extends Component<
       let data = res.data as PrivateMessageResponse;
       this.state.loading = false;
       this.props.onEdit(data.message);
-    } else if (res.op == UserOperation.GetUserDetails) {
-      let data = res.data as UserDetailsResponse;
-      this.state.recipient = data.user;
-      this.state.privateMessageForm.recipient_id = data.user.id;
-      this.setState(this.state);
     } else if (res.op == UserOperation.CreatePrivateMessage) {
       let data = res.data as PrivateMessageResponse;
       this.state.loading = false;
index 34cc8b3a4f89cd68bccaf8115e4f9a6d0cc6708b..60f7d7900c21c82c956c57af55e8f3bdb0445fc9 100644 (file)
@@ -8,6 +8,7 @@ import {
   RemoveCommunityForm,
   UserView,
   AddModToCommunityForm,
+  Category,
 } from 'lemmy-js-client';
 import { WebSocketService, UserService } from '../services';
 import { mdToHtml, getUnixTime } from '../utils';
@@ -19,6 +20,7 @@ import { i18n } from '../i18next';
 
 interface SidebarProps {
   community: Community;
+  categories: Category[];
   moderators: CommunityUser[];
   admins: UserView[];
   online: number;
@@ -57,6 +59,7 @@ export class Sidebar extends Component<SidebarProps, SidebarState> {
           this.sidebar()
         ) : (
           <CommunityForm
+            categories={this.props.categories}
             community={this.props.community}
             onEdit={this.handleEditCommunity}
             onCancel={this.handleEditCancel}
@@ -193,7 +196,7 @@ export class Sidebar extends Component<SidebarProps, SidebarState> {
     return (
       <div class="d-flex flex-wrap">
         <Link
-          class={`btn btn-secondary flex-fill mr-2 mb-2 ${
+          className={`btn btn-secondary flex-fill mr-2 mb-2 ${
             community.deleted || community.removed ? 'no-click' : ''
           }`}
           to={`/create_post?community=${community.name}`}
index 2c1a054cd3c18bec34052bf6ab275cebabce9bc3..a2d0e9a1da608b9568e71c6f75b7eb402e901cb0 100644 (file)
@@ -430,7 +430,7 @@ export class User extends Component<any, UserState> {
                   </a>
                   <Link
                     class="d-flex align-self-start btn btn-secondary ml-2"
-                    to={`/create_private_message?recipient_id=${this.state.user.id}`}
+                    to={`/create_private_message/recipient/${this.state.user.id}`}
                   >
                     {i18n.t('send_message')}
                   </Link>
index 34ca71896bdc479435c707401d398720887f5548..6580db4693831e4a02f8f9d0986877c773d73d86 100644 (file)
@@ -23,8 +23,8 @@ interface IRoutePropsWithFetch extends IRouteProps {
 
 export const routes: IRoutePropsWithFetch[] = [
   {
-    exact: true,
     path: `/`,
+    exact: true,
     component: Main,
     fetchInitialData: (auth, path) => Main.fetchInitialData(auth, path),
   },
@@ -46,8 +46,10 @@ export const routes: IRoutePropsWithFetch[] = [
       CreateCommunity.fetchInitialData(auth, path),
   },
   {
-    path: `/create_private_message`,
+    path: `/create_private_message/recipient/:recipient_id`,
     component: CreatePrivateMessage,
+    fetchInitialData: (auth, path) =>
+      CreatePrivateMessage.fetchInitialData(auth, path),
   },
   {
     path: `/communities/page/:page`,
index 3617fb685f0780896f20330de6c70d7c2a2068da..5ec209d93145e52e8f7126c8dbe8fd45072194ed 100644 (file)
@@ -839,6 +839,12 @@ export function getPageFromProps(props: any): number {
   return props.match.params.page ? Number(props.match.params.page) : 1;
 }
 
+export function getRecipientIdFromProps(props: any): number {
+  return props.match.params.recipient_id
+    ? Number(props.match.params.recipient_id)
+    : 1;
+}
+
 export function editCommentRes(data: CommentResponse, comments: Comment[]) {
   let found = comments.find(c => c.id == data.comment.id);
   if (found) {