File

src/lib/components/discussion-details/discussion-details.component.ts

Implements

OnInit OnDestroy

Metadata

Index

Properties
Methods
Inputs
Outputs

Constructor

constructor(route: ActivatedRoute, discussionService: DiscussionService, configService: ConfigService, formBuilder: UntypedFormBuilder, router: Router, telemetryUtils: TelemetryUtilsService, renderer: Renderer2, location: Location, navigationService: NavigationServiceService)
Parameters :
Name Type Optional
route ActivatedRoute No
discussionService DiscussionService No
configService ConfigService No
formBuilder UntypedFormBuilder No
router Router No
telemetryUtils TelemetryUtilsService No
renderer Renderer2 No
location Location No
navigationService NavigationServiceService No

Inputs

slug
Type : string
topicId
Type : any
widget
Type : boolean

Outputs

stateChange
Type : EventEmitter<any>

Methods

acceptData
acceptData(discuss)
Parameters :
Name Optional
discuss No
Returns : void
appendResponse
appendResponse(data)
Parameters :
Name Optional
data No
Returns : void
bookmark
bookmark(discuss: any)
Parameters :
Name Type Optional
discuss any No
Returns : void
closeModal
closeModal(event: any)
Parameters :
Name Type Optional
event any No
Returns : void
commentReplyHandler
commentReplyHandler(event, post)
Parameters :
Name Optional
event No
post No
Returns : void
confirmDelete
confirmDelete(pid)
Parameters :
Name Optional
pid No
Returns : void
deletePost
deletePost(postId: number)
Parameters :
Name Type Optional
postId number No
Returns : void
deleteTopic
deleteTopic(event, topicData)
           If clicked yes, then will call the delete topic handler.
Parameters :
Name Optional
event No
topicData No
Returns : void
deleteTopicHandler
deleteTopicHandler(topicId)
Parameters :
Name Optional
topicId No
Returns : void
deleteVote
deleteVote(discuss: any)
Parameters :
Name Type Optional
discuss any No
Returns : void
downvote
downvote(discuss: NSDiscussData.IDiscussionData)
Parameters :
Name Type Optional
discuss NSDiscussData.IDiscussionData No
Returns : void
editReplyHandler
editReplyHandler(event, post)
Parameters :
Name Optional
event No
post No
Returns : void
editTopic
editTopic(event, topicData)
Parameters :
Name Optional
event No
topicData No
Returns : void
editTopicHandler
editTopicHandler(event, tid, updateTopicRequest)
Parameters :
Name Optional
event No
tid No
updateTopicRequest No
Returns : void
filter
filter(key: string | "timestamp" | "upvotes")
Parameters :
Name Type Optional
key string | "timestamp" | "upvotes" No
Returns : void
Public getBgColor
getBgColor(tagTitle: any)
Parameters :
Name Type Optional
tagTitle any No
Returns : { color: string; 'background-color': string; }
getContrast
getContrast()
Returns : string
getRealtimePost
getRealtimePost(post: any, index: any)
Parameters :
Name Type Optional
post any No
index any No
Returns : void
initializeFormFiled
initializeFormFiled()
Returns : void
logTelemetry
logTelemetry(event, data?)
Parameters :
Name Optional
event No
data Yes
Returns : void
navigateWithPage
navigateWithPage(page: any)
Parameters :
Name Type Optional
page any No
Returns : void
ngOnChanges
ngOnChanges()
Returns : void
ngOnDestroy
ngOnDestroy()
Returns : void
ngOnInit
ngOnInit()
Returns : void
onEditMode
onEditMode(UpdatePostStatus: boolean)
Parameters :
Name Type Optional
UpdatePostStatus boolean No
Returns : void
onMenuClick
onMenuClick()
Returns : void
postCommentsReply
postCommentsReply(replyContent: string, post: NSDiscussData.IPosts)
Parameters :
Name Type Optional
replyContent string No
post NSDiscussData.IPosts No
Returns : void
postReply
postReply(replyContent: string, post: NSDiscussData.IDiscussionData)
Parameters :
Name Type Optional
replyContent string No
post NSDiscussData.IDiscussionData No
Returns : void
postReplyHandler
postReplyHandler(event, post)
Parameters :
Name Optional
event No
post No
Returns : void
Private Async processVote
processVote(discuss: any, req: any)
Parameters :
Name Type Optional
discuss any No
req any No
Returns : any
Async refreshPostData
refreshPostData(page?: any)
Parameters :
Name Type Optional
page any Yes
Returns : any
setPagination
setPagination()
Returns : void
showError
showError(meta: string)
Parameters :
Name Type Optional
meta string No
Returns : boolean
stringToColor
stringToColor(title)
Parameters :
Name Optional
title No
Returns : string
togglePost
togglePost(post)
Parameters :
Name Optional
post No
Returns : void
unBookMark
unBookMark(discuss: any)
Parameters :
Name Type Optional
discuss any No
Returns : void
updatePost
updatePost(updatedPostContent: any, pid: number)
Parameters :
Name Type Optional
updatedPostContent any No
pid number No
Returns : void
upvote
upvote(discuss: NSDiscussData.IDiscussionData)
Parameters :
Name Type Optional
discuss NSDiscussData.IDiscussionData No
Returns : void

Properties

categoryId
Type : any
contentPost
Type : any
currentActivePage
Type : number
Default value : 1
currentFilter
Type : string
Default value : 'timestamp'
data
Type : any
dropdownContent
Default value : true
editableTopicDetails
Type : any
editContentIndex
Type : any
editMode
Default value : false
fetchSingleCategoryLoader
Default value : false
mainUid
Type : number
pager
Type : object
Default value : {}
paginationData
Type : any
paramsSubscription
Type : Subscription
postAnswerForm
Type : UntypedFormGroup
replyForm
Type : UntypedFormGroup
routeParams
Type : any
Public router
Type : Router
showEditTopicModal
Default value : false
showLoader
Default value : false
similarPosts
Type : any[]
updatedPost
Default value : false
UpdatePostAnswerForm
Type : UntypedFormGroup
import { TelemetryUtilsService } from './../../telemetry-utils.service';
import { DiscussionService } from './../../services/discussion.service';
import { ActivatedRoute, Router } from '@angular/router';
import { Component, OnInit, OnDestroy, Input, Renderer2, Output, EventEmitter } from '@angular/core';
import { NSDiscussData } from './../../models/discuss.model';
import { UntypedFormGroup, UntypedFormBuilder, Validators } from '@angular/forms';
import * as CONSTANTS from '../../common/constants.json';
/* tslint:disable */
import * as _ from 'lodash'
import { Subscription } from 'rxjs';
import { ConfigService } from '../../services/config.service';
/* tslint:enable */
import { Location } from '@angular/common';

import { NavigationServiceService } from '../../navigation-service.service';

const MSGS = {
  deletePost: `Are you sure you want to delete this Post? This can't be undone.`,
  deleteTopic: `Are you sure you want to delete this topic? Your action cannot be undone.`
};

@Component({
  selector: 'lib-discussion-details',
  templateUrl: './discussion-details.component.html',
  styleUrls: ['./discussion-details.component.scss']
})
export class DiscussionDetailsComponent implements OnInit, OnDestroy {
  @Input() topicId: any;
  @Input() slug: string;
  @Input() widget: boolean;

  @Output() stateChange: EventEmitter<any> = new EventEmitter();

  routeParams: any;
  currentActivePage = 1;
  currentFilter = 'timestamp'; // 'recent
  data: any;
  paginationData!: any;
  pager = {};
  postAnswerForm!: UntypedFormGroup;
  UpdatePostAnswerForm: UntypedFormGroup;
  replyForm: UntypedFormGroup;
  fetchSingleCategoryLoader = false;
  paramsSubscription: Subscription;
  editMode = false;
  updatedPost = false;
  contentPost: any;
  editContentIndex: any;
  mainUid: number;
  similarPosts: any[];
  showEditTopicModal = false;
  editableTopicDetails: any;
  dropdownContent = true;
  categoryId: any;
  showLoader = false;

  constructor(
    private route: ActivatedRoute,
    private discussionService: DiscussionService,
    private configService: ConfigService,
    private formBuilder: UntypedFormBuilder,
    public router: Router,
    private telemetryUtils: TelemetryUtilsService,
    private renderer: Renderer2,
    private location: Location,
    private navigationService: NavigationServiceService,
  ) {
    /**
     * @description - It will check for the outside click while kebab menu is in open mode.
     */
    this.renderer.listen('window', 'click', (e: Event) => {
      // tslint:disable-next-line:no-string-literal
      if (e.target['id'] !== 'group-actions') {
        this.dropdownContent = true;
      }
    });
  }

  ngOnInit() {
    this.initializeFormFiled();
    if(this.widget){
      this.fetchSingleCategoryLoader = true
    }
    if (!this.topicId && !this.slug) {
      this.route.params.subscribe(params => {
        this.routeParams = params;
        this.slug = _.get(this.routeParams, 'slug');
        this.topicId = _.get(this.routeParams, 'topicId');
        this.refreshPostData(this.currentActivePage);
        // this.getRealtedDiscussion(this.cid)
      });
    } else {
      this.refreshPostData(this.currentActivePage);
      // this.getRealtedDiscussion(this.cid)
    }


    this.telemetryUtils.logImpression(NSDiscussData.IPageName.DETAILS);
  }

  // tslint:disable-next-line: use-life-cycle-interface
  ngOnChanges() {
    if (!this.topicId && !this.slug) {
      this.route.params.subscribe(params => {
        this.routeParams = params;
        this.slug = _.get(this.routeParams, 'slug');
        this.topicId = _.get(this.routeParams, 'topicId');
        this.refreshPostData(this.currentActivePage);
        // this.getRealtedDiscussion(this.cid)
      });
    } else {
      this.refreshPostData(this.currentActivePage);
      // this.getRealtedDiscussion(this.cid)
    }
  }

  // new method
  acceptData(discuss) {
    // debugger
    const matchedTopic = _.find(this.telemetryUtils.getContext(), { type: 'Topic' });
    if (matchedTopic) {
      this.telemetryUtils.deleteContext(matchedTopic);
    }

    this.telemetryUtils.uppendContext({
      id: _.get(discuss, 'tid'),
      type: 'Topic'
    });

    const slug = _.trim(_.get(discuss, 'slug'))
    const input = {
      data: { url: `${this.configService.getRouterSlug()}${CONSTANTS.ROUTES.TOPIC}${slug}`, queryParams: {} },
      action: CONSTANTS.CATEGORY_DETAILS };

    this.navigationService.navigate(input);
    this.stateChange.emit({ action: CONSTANTS.CATEGORY_DETAILS, title: discuss.title, tid: discuss.tid });
  }

  initializeFormFiled() {
    this.postAnswerForm = this.formBuilder.group({
      answer: [],
    });
    this.UpdatePostAnswerForm = this.formBuilder.group({
      updatedAnswer: [],
    });
    this.replyForm = this.formBuilder.group({
      reply: []
    });
  }

  async refreshPostData(page?: any) {
    if (this.currentFilter === 'timestamp') {

      this.discussionService.fetchTopicById(this.topicId, this.slug, page).subscribe(
        (data: NSDiscussData.IDiscussionData) => {
          this.appendResponse(data)
          this.showLoader = true;
        },
        (err: any) => {
          // error code check
          this.discussionService.showTrafficAlert(err);
          console.log('Error in fetching topics')
          // toast message
          // this.openSnackbar(err.error.message.split('|')[1] || this.defaultError);
        });
    } else {
      this.discussionService.fetchTopicByIdSort(this.topicId, 'voted', page).subscribe(
        (data: NSDiscussData.IDiscussionData) => {
          this.appendResponse(data)
          this.showLoader = true;
        },
        (err: any) => {
          // error code check
          this.discussionService.showTrafficAlert(err);
          console.log('Error in fetching topics')
        });
    }
  }

  appendResponse(data) {
    this.data = data;
    this.paginationData = _.get(data, 'pagination');
    // TODO: After updating the nodebb version to v1.18.6 or above. Remove the fallback after 2/3 releases.
    this.mainUid = _.get(data, 'loggedInUser.uid') || _.get(data, 'privileges.uid');
    this.categoryId = _.get(data, 'cid');
    this.topicId = _.get(data, 'tid');
  }


  setPagination() {
    this.pager = {
      startIndex: this.paginationData.first.page,
      endIndex: this.paginationData.last.page,
      pages: this.paginationData.pages,
      currentPage: this.paginationData.currentPage,
      totalPage: this.paginationData.pageCount,
    };
  }

  upvote(discuss: NSDiscussData.IDiscussionData) {
    const req = {
      delta: 1,
    };
    this.processVote(discuss, req);
  }

  downvote(discuss: NSDiscussData.IDiscussionData) {
    const req = {
      delta: -1,
    };
    this.processVote(discuss, req);
  }

  private async processVote(discuss: any, req: any) {
    if (discuss && discuss.uid) {
      this.discussionService.votePost(discuss.pid, req).subscribe(
        () => {
          // toast
          // this.openSnackbar(this.toastSuccess.nativeElement.value);
          this.postAnswerForm.reset();
          this.refreshPostData(this.currentActivePage);
        },
        (err: any) => {
          // error code check
          this.discussionService.showTrafficAlert(err);
          // toast
          // this.openSnackbar(err.error.message.split('|')[1] || this.defaultError);
        });
    }
  }

  bookmark(discuss: any) {
    this.discussionService.bookmarkPost(discuss.pid).subscribe(data => {
      // toast
      // this.openSnackbar('Bookmark added successfully!');
      this.refreshPostData(this.currentActivePage);
    },
      (err: any) => {
        // error code check
        this.discussionService.showTrafficAlert(err);
        // toast
        // this.openSnackbar(err.error.message.split('|')[1] || this.defaultError);
      });
  }

  unBookMark(discuss: any) {
    this.discussionService.deleteBookmarkPost(discuss.pid).subscribe(data => {
      // toast
      this.refreshPostData(this.currentActivePage);
    },
      (err: any) => {
        // error code check
        this.discussionService.showTrafficAlert(err);
        // toast
        // this.openSnackbar(err.error.message.split('|')[1] || this.defaultError);
      });
  }

  deleteVote(discuss: any) {
    this.discussionService.deleteVotePost(discuss.pid).subscribe(data => {
      // toast
      this.refreshPostData(this.currentActivePage);
    },
      (err: any) => {
        // error code check
        this.discussionService.showTrafficAlert(err);
        // toast
        // this.openSnackbar(err.error.message.split('|')[1] || this.defaultError);
      });
  }

  postReply(replyContent: string, post: NSDiscussData.IDiscussionData) {
    const req = {
      content: replyContent,
    };
    this.postAnswerForm.controls['answer'].setValue('');
    if (post && post.tid) {
      this.discussionService.replyPost(post.tid, req).subscribe(
        () => {
          // toast
          // this.openSnackbar('Your reply was saved succesfuly!');
          // this.fetchNewData = true;
          this.refreshPostData(this.currentActivePage);
        },
        (err: any) => {
          // error code check
          this.discussionService.showTrafficAlert(err);
          // toast
          // this.openSnackbar(err.error.message.split('|')[1] || this.defaultError);
        });
    }
  }

  postCommentsReply(replyContent: string, post: NSDiscussData.IPosts) {
    const req = {
      content: replyContent,
      toPid: post.pid,
    };
    if (post && post.tid) {
      this.discussionService.replyPost(post.tid, req).subscribe(
        () => {
          // toast
          // this.openSnackbar('Your reply was saved succesfuly!');
          this.refreshPostData(this.currentActivePage);
        },
        (err: any) => {
          // error code check
          this.discussionService.showTrafficAlert(err);
          // toast
          // this.openSnackbar(err.error.message.split('|')[1] || this.defaultError);
        });
    }
  }

  confirmDelete(pid) {
    if (window.confirm(MSGS.deletePost)) {
      this.deletePost(pid);
    }
  }

  filter(key: string | 'timestamp' | 'upvotes') {
    if (key) {
      this.currentFilter = key;
      this.refreshPostData(this.currentActivePage);
    }
  }

  navigateWithPage(page: any) {
    if (page !== this.currentActivePage) {
      this.router.navigate([`${this.configService.getRouterSlug()}${CONSTANTS.ROUTES.CATEGORY} ${this.topicId}`], { queryParams: { page },  queryParamsHandling: "merge"  });
    }
  }

  showError(meta: string) {
    if (meta) {
      return true;
    }
    return false;
  }

  public getBgColor(tagTitle: any) {
    const bgColor = this.stringToColor(tagTitle.toLowerCase());
    const color = this.getContrast();
    return { color, 'background-color': bgColor };
  }

  stringToColor(title) {
    let hash = 0;

    for (let i = 0; i < title.length; i++) {
      // tslint:disable-next-line: no-bitwise
      hash = title.charCodeAt(i) + ((hash << 5) - hash);
    }
    const hue = Math.abs(hash % 360);
    // tslint:disable-next-line: prefer-template
    const colour = 'hsl(' + hue + ',100%,30%)';
    return colour;
  }

  getContrast() {
    return 'rgba(255, 255, 255, 80%)';
  }

  logTelemetry(event, data?) {
    const pid = _.get(data, 'pid') || _.get(data, 'mainPid') ?
      { id: _.get(data, 'pid') || _.get(data, 'mainPid'), type: 'Post' } : {};
    this.telemetryUtils.uppendContext(pid);
    this.telemetryUtils.logInteract(event, NSDiscussData.IPageName.DETAILS);
  }

  onEditMode(UpdatePostStatus: boolean) {
    if (UpdatePostStatus) {
      this.editMode = true;
    } else {
      this.editMode = false;
    }
  }

  getRealtimePost(post: any, index: any) {
    this.editMode = true;
    this.editContentIndex = index;
    this.contentPost = _.get(post, 'content').replace(/<[^>]*>/g, '');
    post.toggle = false;
  }

  updatePost(updatedPostContent: any, pid: number) {
    this.editMode = false;
    const req = {
      content: updatedPostContent,
      title: '',
      tags: [],
      uid: this.mainUid
    };
    this.discussionService.editPost(pid, req).subscribe((data: any) => {
      // TODO: Success toast
      this.refreshPostData(this.currentActivePage);
    }, (error) => {
      // error code check
      this.discussionService.showTrafficAlert(error);
      // TODO: error toast
      console.log('e', error);
    });
    console.log(pid);
  }

  deletePost(postId: number) {
    this.discussionService.deletePost(postId, this.mainUid).subscribe((data: any) => {
      // TODO: Success toast
      this.refreshPostData(this.currentActivePage);
    }, (error) => {
      // error code check
      this.discussionService.showTrafficAlert(error);
      // TODO: error toast
      console.log('e', error);
    });
  }

  editReplyHandler(event, post) {
    if (_.get(event, 'action') === 'cancel') {
      this.onEditMode(false);
    } else if (_.get(event, 'action') === 'edit') {
      this.updatePost(_.get(event, 'content'), _.get(post, 'pid'));
      this.logTelemetry(event, post);
    }
  }

  commentReplyHandler(event, post) {
    if (_.get(event, 'action') === 'cancel') {
      this.togglePost(post);
    } else if (_.get(event, 'action') === 'reply') {
      this.postCommentsReply(_.get(event, 'content'), post);
      this.logTelemetry(event, post);
    }
  }

  postReplyHandler(event, post) {
    if (_.get(event, 'action') === 'reply') {
      this.postReply(_.get(event, 'content'), post);
      this.logTelemetry(event, post);
    }
  }

  togglePost(post) {
    post.toggle = !post.toggle;
    this.onEditMode(false);
  }

  /**
   * @description - It will trigger the event handlers and close the update thread popup.
   */
  closeModal(event: any) {
    console.log('close event', event);
    if (_.get(event, 'action') === 'update') {
      this.editTopicHandler(event, _.get(event, 'tid'), _.get(event, 'request'));
    }
    this.showEditTopicModal = false;
  }

  /**
   * @description - It will open update thread popup.
   */
   editTopic(event, topicData) {
    this.showEditTopicModal = true;
    this.logTelemetry(event, topicData);
  }

  /**
   * @description - It will all the update topic api. If success, then will refresh the data.
   */
  editTopicHandler(event, tid, updateTopicRequest) {
    this.logTelemetry(event, this.editableTopicDetails);
    this.discussionService.editPost(tid, updateTopicRequest).subscribe(data => {
      console.log('update success', data);
      this.refreshPostData(this.currentActivePage);
    }, error => {
      // error code check
      this.discussionService.showTrafficAlert(error);
      console.log('error while updating', error);
    });
  }

  /**
   * @description - It will open the confirmation popup before deleting the topic,
   *                If clicked yes, then will call the delete topic handler.
   */
  deleteTopic(event, topicData) {
    if (window.confirm(MSGS.deleteTopic)) {
      this.logTelemetry(event, topicData);
      this.deleteTopicHandler(_.get(topicData, 'tid'));
    }
  }

  /**
   * @description - It will all the delete topic api. If success, then will navigate back to the previous page.
   */
  deleteTopicHandler(topicId) {
    this.discussionService.deleteTopic(topicId).subscribe(data => {
      this.location.back();
    }, error => {
      // error code check
      this.discussionService.showTrafficAlert(error);
      console.log('error while deleting', error);
    });
  }
  /**
   * @description - It will toggle the kebab menu click
   */
  onMenuClick() {
    this.dropdownContent = !this.dropdownContent;
  }

  ngOnDestroy() {
    if (this.paramsSubscription) {
      this.paramsSubscription.unsubscribe();
    }
  }

}
<lib-app-loader *ngIf="!showLoader"></lib-app-loader>
<div class="discuss-details-content" *ngIf="showLoader">
  <div class="discussion-details" tabindex="0" role="link">

      <!-- header -->
      <div class="discuss-card-kabab-menu">
        <h3 class="discussion-card-title df-label-color" [innerHTML]="data?.title"></h3>
        <div *ngIf="data?.uid === mainUid">
          <div class="kabab-menu" id="group-actions" (click)="onMenuClick()" tabindex="0"></div>
          <div class="kabab-menu-dropdown-content" [hidden]="dropdownContent">
              <div id="edit-topic" class="list" tabindex="0"
                (click)="editTopic($event, data); editableTopicDetails = data">Edit
              </div>
              <div id="delete-topic" class="list" (click)="deleteTopic($event, data)" tabindex="0">Delete</div>
          </div>
        </div>
      </div>
      <!-- /header -->

      <ng-container *ngFor="let post of data?.posts">
        <div class="post-reply-card" *ngIf="post?.index === 0">
          <h3 class="discussion-heading df-text-color" [innerHTML]="post?.content"></h3>
          <div class="discussion-content">
            <div class="circle-text">
              <div class="circle-label">{{ post?.user?.username | splitInitials }}</div>
            </div>
            <div class="discussion-labels">{{'Asked by '}}</div>
            <div class="discussion-labels" *ngIf="post.user.fullname" [innerHTML]="post.user.fullname"></div>
            <div class="discussion-labels" *ngIf="!post.user.fullname" [innerHTML]="post.user.username"></div>
          </div>

          <div class="tags" aria-label="tags">
            <ng-container *ngIf="data && data?.tags && data?.tags?.length > 0">
              <span *ngFor="let tag of data?.tags" class="tag" role="link" tabindex="0"
                [ngStyle]="getBgColor(tag.value)">
                {{tag.value}}
              </span>
            </ng-container>
          </div>

          <div class="comments-area">
            <div>
              <span class="post-icons mobile">
                <span role="link" tabindex="0" *ngIf="!post.upvoted" (click)="upvote(post);logTelemetry($event, post)"
                  aria-label="upvote the post" id="up-vote">
                  <!-- upward arrow -->
                  <img src="./assets/discussion-ui/images/up-arrow.png" alt="up-arrow" class="icons"
                    alt="up arrow icon for like the post">
                </span>
                <span *ngIf="post.upvoted" role="link" tabindex="0"
                  (click)="deleteVote(post);logTelemetry($event, post)" aria-label="remove upvote" id="delete-vote">
                  <!-- upward arrow -->
                  <img src="./assets/discussion-ui/images/up.svg" alt="select-up-arrow" class="icons" alt="up image">
                </span>
                <span class="vote-value" role="text"
                  [attr.aria-label]="'total upvoat is' + data?.upvotes">{{data?.upvotes}}</span>
              </span>
              <span class="post-icons mobile">
                <span *ngIf="!post?.downvoted" role="link" tabindex="0"
                  (click)="downvote(post);logTelemetry($event, post)" aria-label="downvote post" id="down-vote">
                  <!-- downward arrow -->
                  <img src="./assets/discussion-ui/images/down-arrow.png" class="icons"
                    alt="down arrow icon for unlike post">
                </span>
                <span *ngIf="post?.downvoted" role="link" tabindex="0"
                  (click)="deleteVote(post);logTelemetry($event, post)" aria-label="remove down vote" id="delete-vote">
                  <!-- downward arrow -->
                  <img src="./assets/discussion-ui/images/down.svg" class="icons" alt="down image">
                </span>
                <span class="vote-value" role="text"
                  [attr.aria-label]="'total upvoat is' + data?.upvotes">{{data?.downvotes}}</span>
              </span>
              <span class="post-icons mobile" role="link" tabindex="0">
                <!-- trending -->
                <img src="./assets/discussion-ui/images/views.svg" alt="views icon for seeing the posts" class="icons">
                <span class="vote-value" aria-label="views count">{{data.viewcount}} Views</span>
              </span>
              <span class="post-icons mobile">
                <span *ngIf="!data?.posts[0]?.bookmarked" role="link" tabindex="0"
                  (click)="bookmark(post);logTelemetry($event, post)" aria-label="Bookmark post" id="bookmark">
                  <!-- bookmark -->
                  <img src="./assets/discussion-ui/images/bookmarks.png" class="icons" alt="bookmark icon">
                </span>
                <span *ngIf="data?.posts[0]?.bookmarked" role="link" tabindex="0"
                  (click)="unBookMark(post);logTelemetry($event, post)" aria-label="unBookmark post"
                  id="un-bookmark-vote">
                  <!-- bookmark -->
                  <img src="./assets/discussion-ui/images/select-bookmarks.png" class="icons bookmark-icon"
                    alt="select bookmark icon">
                </span>
              </span>
            </div>
            <div class="comments-count">
              <span *ngIf="data?.postcount-1 > 0" aria-label="comments count">
                {{data?.postcount-1}}
                comments
              </span>
              <span *ngIf="data?.postcount-1 <=0" aria-label="comments count">
                0 comments</span>
            </div>
          </div>
        <!-- /card content -->
        <!-- post reply -->
        <lib-post-reply (actionEvent)="postReplyHandler($event, post); logTelemetry($event, post)" [mode]="'reply'"
          [showCancel]="false"></lib-post-reply>
          
        </div>
      </ng-container>
    <!-- /card end -->

    <ng-container *ngIf="data?.posts && data?.postcount > 1">
      <div class="recent-tabs">
        <div class="tabs-content">
          <div class="tabs-filter">
            <a href="javascript:void(0)" class="filter-option" role="link" tabindex="0" [ngClass]="{'tabs-active' : currentFilter === 'timestamp',
                            'ws-mat-accent-border':currentFilter !== 'timestamp'}"
              (click)="filter('timestamp');logTelemetry($event)" id="recent-post">
              Recent </a>
          </div>
        </div>
      </div>
    </ng-container>

    <ng-container *ngFor="let post of data?.posts | sortBy: 'timestampISO':'desc'; index as i">
      <!-- card content -->
      <div *ngIf="post?.index != 0" class="post-card">
        <!-- header -->
        <div class="comment-section">
          <div class="post-header-content">
            <span class="circle-text"><span class="circle-label">{{ post?.user?.username | splitInitials
                }}</span></span>
            <span class="post-name" *ngIf="post?.user?.fullname" [innerHTML]="post?.user?.fullname"></span>
            <span class="post-name df-label-color" *ngIf="!post?.user?.fullname"
              [innerHTML]="post?.user?.username"></span>
          </div>
          <div class="custom-actions">
            <span class="post-time">{{ post?.timestamp | date: 'dd MMM yyyy hh:mm a'}}</span>
            <ng-container *ngIf="mainUid === post?.uid">
              <img src="./assets/discussion-ui/images/edit.svg" class="edit-icon" id="edit-post" alt="edit icon"
                (click)="getRealtimePost(post, i)" tabindex="0">
              <img src="./assets/discussion-ui/images/delete.svg" class="delete-icon" id="delete-post" alt="delete icon"
                (click)="confirmDelete(post?.pid)" tabindex="0">
            </ng-container>
          </div>
        </div>
        <!-- / header -->
        <div>
          <div class="edit-text" *ngIf="!editMode || editContentIndex !== i">
            <p [innerHTML]="post?.content" class="post-labels df-text-color"></p>
            <div class="edited-text" *ngIf="post?.edited">(edited)</div>
          </div>
          <div *ngIf="editMode && editContentIndex === i">
            <lib-post-reply (actionEvent)="editReplyHandler($event, post)" [mode]="'edit'" [showCancel]="true"
              [content]="contentPost"></lib-post-reply>
          </div>
          <div class="reply-area">
            <div>
              <span class="flex mobile">
                <!-- upward arrow -->
                <span class="up-vote-text" *ngIf="!post?.upvoted" role="link" tabindex="0"
                  (click)="upvote(post);logTelemetry($event, post)" aria-label="upvote comment" id="up-vote">
                  <img src="./assets/discussion-ui/images/up.svg" class="icons" alt="up icon">
                </span>
              </span>
              <span class="post-icons mobile">
                <!-- upward arrow -->
                <span class="down-vote-text" *ngIf="post.upvoted" role="link" tabindex="0"
                  (click)="deleteVote(post);logTelemetry($event, post)" aria-label="delete upvote on comment"
                  id="delete-vote">
                  <img src="./assets/discussion-ui/images/up.svg" class="icons" alt="up icon">
                </span>
                <span class="vote-value">{{post?.upvotes}}</span>
              </span>

              <span class="flex mobile">
                <span id="down-vote" *ngIf="!post?.downvoted" role="link" tabindex="0"
                  (click)="downvote(post);logTelemetry($event, post)" aria-label="downvote comment">
                  <!-- downward arrow -->
                  <img src="./assets/discussion-ui/images/down-arrow.png" class="icons" alt="down arrow icon">
                </span>
              </span>
              <span class="post-icons mobile">
                <span id="delete-vote" *ngIf="post?.downvoted" role="link" tabindex="0"
                  (click)="deleteVote(post);logTelemetry($event, post)" aria-label="delete downvote on comment">
                  <!-- down arrow -->
                  <img src="./assets/discussion-ui/images/down.svg" class="icons" alt="down icon">
                </span>
                <span class="vote-value">{{post?.downvotes}}</span>
              </span>
            </div>

            <button (click)="togglePost(post); logTelemetry($event, post)"
              class="df-btn df-btn-normal df-btn-primary df-reply-btn" id="reply-comment">
              Reply </button>

          </div>
          <div class="replies" *ngIf="post?.toggle">
            <ng-container [ngTemplateOutlet]="reply" [ngTemplateOutletContext]="{post:post}">
            </ng-container>
          </div>
          <ng-container *ngIf="post?.replies?.count > 0">
            <div>
              <div>
                <div class="reply-content" (click)="post.replyCountToggle = !post.replyCountToggle" tabindex="0">
                  <span class="replies-count"> {{post?.replies?.count}} reply(s) </span>
                  <div *ngIf="post?.replyCountToggle" role="link" tabindex="0" aria-label="reply toggle">
                    <span class="toggle-icon" *ngIf="post?.replyCountToggle" aria-label="reply toggle upwards">
                      <!-- up arrow -->
                      <img src="./assets/discussion-ui/images/up-chevron.png" class="icons" alt="up chevron icon">
                    </span>
                  </div>
                  <div *ngIf="!post.replyCountToggle" role="link" tabindex="0" aria-label="reply toggle">
                    <span class="toggle-icon" *ngIf="!post.replyCountToggle" aria-label="reply toggle downwards">
                      <!-- down arrow -->
                      <img src="./assets/discussion-ui/images/down-chevron.png" class="icons" alt="down chevron icon">
                    </span>
                  </div>
                </div>
              </div>
              <div class="last-reply-data">
                <span *ngIf="!post.replyCountToggle">Last reply
                  {{ post?.replies?.timestampISO | date: 'dd MMM yyyy hh:mm a' }} </span>
              </div>
            </div>
            <div class="replies" *ngIf="post?.replyCountToggle">
              <ng-container [ngTemplateOutlet]="replies"
                [ngTemplateOutletContext]="{posts:data.posts, postId:post.pid}">
              </ng-container>
            </div>
          </ng-container>
        </div>
        <!-- /card content -->
      </div>
      <!--  / card -->
      <!-- Divider -->
      <div *ngIf="post.index != 0"></div>
    </ng-container>
  </div>

  <div class="related-discuss-part">
    <div *ngIf="fetchSingleCategoryLoader" class="related-discuss-part-content"></div>
    <lib-related-discussion *ngIf="!fetchSingleCategoryLoader" [catId]="categoryId" [topicId]="topicId">
    </lib-related-discussion>
  </div>
</div>

<ng-template #reply let-post="post">
  <lib-post-reply (actionEvent)="commentReplyHandler($event, post)" [mode]="'reply'" [showCancel]="true">
  </lib-post-reply>
</ng-template>

<ng-template #replies let-posts="posts" let-postId="postId">
  <ng-container *ngFor="let post of posts | pipeFilter:'toPid': postId; index as index; last as last">
    <!-- card -->
    <div class="post-sub-card">
      <!-- card-header -->
      <div class="comment-section">
        <div class="post-header-content">
          <div class="circle-text"><div class="circle-label">{{ post?.user?.username | splitInitials }}</div></div>
          <div class="post-name" *ngIf="post?.user?.fullname" [innerHTML]="post?.user?.fullname"></div>
          <div class="df-label-color post-name" *ngIf="!post?.user?.fullname"
            [innerHTML]="post?.user?.username"></div>
        </div>
        <div class="post-time">{{ post?.timestamp | date}}</div>
      </div>
      <!-- /card-header -->

      <!-- card-content -->
      <div>
        <p role="link" tabindex="0" tabindex="0" [innerHTML]="post?.content"></p>
        <div class="reply-area">
          <div class="reply-area-content">
            <span class="post-icons mobile">
              <!-- up arrow -->
              <img *ngIf="!post?.upvoted" class="cursor-pointer" (click)="upvote(post);logTelemetry($event, post)"
                src="./assets/discussion-ui/images/up-arrow.png" alt="up arrow icon" class="icons" tabindex="0">
              <img *ngIf="post?.upvoted" class="cursor-pointer" (click)="deleteVote(post);logTelemetry($event, post)"
                src="./assets/discussion-ui/images/up.svg" alt="select up arrow icon" class="icons" tabindex="0">
              <span class="vote-value">{{post.upvotes}}</span>
            </span>
            <span class="post-icons mobile">
              <img *ngIf="!post?.downvoted" class="cursor-pointer" (click)="downvote(post); logTelemetry($event, post)"
                id="up-vote" tabindex="0" src="./assets/discussion-ui/images/down-arrow.png" alt="down arrow icon"
                class="icons">
              <img *ngIf="post?.downvoted" class="cursor-pointer" (click)="deleteVote(post);logTelemetry($event, post)"
                id="delete-vote" tabindex="0" src="./assets/discussion-ui/images/down.svg" alt="select down arrow icon"
                class="icons">
              <span class="vote-value">{{post?.downvotes}}</span>
            </span>
          </div>
        </div>
      </div>
    </div>  
    <!-- /card -->
  </ng-container>
</ng-template>

<input type="hidden" i18-value i18-aria-value aria-value="Thank you for voting!" value="Thank you for voting!!"
  #toastSuccess />
<input type="hidden" i18-value i18-aria-value aria-value="Something went wrong, please try again later!"
  value="Something went wrong, please try again later!" #toastError />

<lib-discuss-start [mode]="'edit'" [topicData]="editableTopicDetails" (close)="closeModal($event)"
  *ngIf="showEditTopicModal"></lib-discuss-start>

./discussion-details.component.scss

.discuss-details-content {
    display: flex;
    flex-direction: row;
}

.discussion-details {
    box-shadow: 0 2px 1px -1px rgba(0, 0, 0, .2), 0 1px 1px 0 rgba(0, 0, 0, .14), 0 1px 3px 0 rgba(0, 0, 0, .12);
    background:var(--df-card-bg);
    color:var(--df-text);
    flex: 3;
    height: auto;
    transition: box-shadow 280ms cubic-bezier(.4, 0, .2, 1);
    display: block;
    position: relative;
    padding: 0.875rem 1rem;
    justify-content: space-between;
    z-index: unset;
    margin-bottom: 1rem;
}

.related-discuss-part {
    padding: 0 0 1rem 1.5rem;
    position: relative;
    z-index: 2;
    .related-discuss-part-content{
        padding: 0 0.25rem;
    }
}

.discussion-card-title {
    font-size: 1.25rem;
    font-weight: 700;
}

.discussion-heading {
    font-size: 0.875rem;
    font-weight: 400;
    pointer-events: none;
    margin-bottom: 0px;
    margin-top: 0.5rem;
}

.discussion-content {
    display: flex;
    align-items: center;
    margin-bottom: 1rem;
    font-size: 0.875rem;
    flex-wrap: wrap;
    margin-bottom: 0;
    margin-top: 1rem;
}

.comment-section {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin: 0.5rem 0;
    flex-direction: row;
    flex-wrap: wrap;
}

.post-header-content {
    display: flex;
    align-items: center;
}

.circle-text {
    border-radius: 50%;
    width: 1.75rem;
    height: 1.75rem;
    display: flex;
    justify-content: center;
    align-items: center;
    background-color: rgb(48, 105, 51);
}

.circle-label {
    color: var(--white);
    font-size: 1rem;
    line-height: 0.75rem;
    letter-spacing: .2625px;
    text-transform: uppercase;
}

.discussion-labels {
    color: var(--gray-400);
    margin-left: 0.5rem;
    font-size: 00.875rem;
}

.comments-area {
    display: flex;
    align-items: center;
    justify-content: space-between;
    font-weight: 700;
    flex-direction: row;
    font-size: 0.875rem;
    margin: 1rem 0;
}

.text-form-field {
    display: flex;
    flex-direction: column;
    /* width: 97.6%;   */
}

.text-content {
    min-height: 6.75rem;
    max-height: 33.75rem;
    margin-bottom: 0.875rem;
    background-color: var(--df-field-control-bg);
    border: 0.0625rem solid var(--gray-200);
    border-radius: 0.1875rem;
    color: var(--df-text);
    display: block;
    font-size: .8125rem;
    font-family: sans-serif;
    position: relative;
    cursor: pointer;
    outline: 0;
    padding: 0.5rem 0.875rem;
}

.text-content.is-invalid,
.text-content.is-invalid:hover,
.text-content.is-invalid:focus {
    border: 0.0625rem solid var(--red-100);
}

.text-content.is-valid,
.text-content.is-valid:hover,
.text-content.is-valid:focus {
    border: 0.0625rem solid var(--primary-400);
}

.up-vote-text,
.down-vote-text {
    font-size: 1rem;
    color: var(--black);
    margin-right: 0.5rem;
}

.post-card,
.post-reply-card {
    border-bottom: 0.0625rem solid var(--gray-100);
    margin-bottom: 1.5rem;
}

.post-sub-card {
    margin: 0 0.5rem 0.5rem;
    border: 0;
}

.comments-section {
    display: flex;
    align-items: center;
    justify-content: space-between;
}

.post-icons{
    margin-right: 1rem;
}

.post-name {
    font-size: 1rem;
    font-weight: 700;
    margin-left: 1rem;
    word-break: break-all;
    text-transform: capitalize;
}

.post-time {
    color: var( var(--gray-400));
    margin: 0 1rem;
    font-size: 0.875rem;
}

.post-labels {
    font-size: 0.875rem;
    margin: 0;
}

.reply-area {
    display: flex;
    justify-content: space-between;
    align-items: center;
}

.reply-area-content{
    position: relative;
    margin-top: 1rem;
}

.margin-gap-tb {
    margin: 1rem 0;
}

.custom-actions {
    display: flex;
    align-items: center;
}

.edit-post {
    margin-right: 1.25rem;
}

.border-0 {
    border-bottom: 0px;
}

.comments-count {
    color: var(--primary);
    font-weight: 700;
    cursor: pointer;
}

@media (max-width: 768px) {
    .discuss-details-content {
        flex-direction: column;
    }

    .related-discuss-part {
        padding: 0px;
    }

    .post-btn {
        width: 100%;
        margin-top: 0.5rem;
        cursor:pointer;
    }


    .post-time {
        margin-top: 0.5rem;
        margin-left: 0px;
    }

    .comment-section {
        display: flex;
        flex-direction: column;
        align-items: start;
        margin-bottom: 0.5rem;
    }
}

.df-btn-disabled {
    background-color: var(--gray-100) !important;
    color: var(--gray-200) !important;
}

.df-reply-btn{
margin-bottom: 0.5rem;
}
.edited-text {
    padding-left: 0.5rem;
    margin-top: 0.25rem;
    font-size: 0.75rem;
    color: var(--gray-200);
}

.delete-icon,
.edit-icon {
    cursor: pointer;
    width: 1rem;
    height: 1rem;
    margin:0 0.5rem;
}

.discuss-card-kabab-menu {
    display: flex;
    justify-content: space-between;
    flex-wrap: wrap;
}

.kabab-menu {
    color: var(--primary-400);
    width: 1.875rem;
    height: 1.875rem;
    line-height: 1.75rem;
    text-align: center;
    border-radius: 50%;
    padding-left: 0.5rem;
    position: absolute;
    right: 0.5rem;

    &:hover {
        background: var(--gray-0);
        cursor: pointer;
    }

    &::after {
        content: '\2807';
        font-size: 1.5rem;
    }
}

.kabab-menu-dropdown-content {
    position: absolute;
    border-radius: 0.125rem;
    background-color: var(--white);
    box-shadow: 0 3px 5px 4px rgba(var(--rc-rgba-black), 0.05);
    padding: 0.5rem;
    z-index: 1;
    text-align: left;
    right: 0;
    top: 0;
    min-width: 13.125rem;

    .list {
        display: flex;
        align-items: center;
        width: 100%;
        cursor: pointer;
        font-size: 0.875rem;
        padding: 0.5rem;

        &:hover,
        &:active {
            background-color: var(--primary-100);
        }

        &:last-child {
            .df-btn-normal {
                color: var(--red-400);
            }
        }

        .df-btn-normal {
            font-size: 0.875rem;
        }
    }
}

::ng-deep {
    html[dir='rtl'] .kabab-menu-dropdown-content {
        right: auto;
        left: 0;
    }
}

.vote-value{
    margin-left: 0.5rem;
}

.icons {
    width: 0.875rem;
    height: 0.875rem;
    position: relative;
    cursor: pointer;
}

.edit-text{
    display: flex;
}

.last-reply-data{
    margin: 1rem 0;
    font-size: 0.875rem;
}

.reply-content{
    display: flex;
    align-items: center;
}

.replies{
    width: 100%;
}

.replies-count{
    font-size: 0.875rem;
    font-weight: bold;
    cursor: pointer;
}

.toggle-icon{
    padding: 0 1rem;
    cursor: pointer;
}
Legend
Html element
Component
Html element with directive

results matching ""

    No results matching ""