import { Component, linkEvent } from 'inferno'; import { Link } from 'inferno-router'; import { WebSocketService, UserService } from '../services'; import { Post, CreatePostLikeForm, PostForm as PostFormI, SavePostForm, CommunityUser, UserView, BanType, BanFromCommunityForm, BanUserForm, AddModToCommunityForm, AddAdminForm, TransferSiteForm, TransferCommunityForm, } from '../interfaces'; import { MomentTime } from './moment-time'; import { PostForm } from './post-form'; import { mdToHtml, canMod, isMod, isImage, isVideo, getUnixTime, pictshareAvatarThumbnail, showAvatars, imageThumbnailer, } from '../utils'; import { i18n } from '../i18next'; import { T } from 'inferno-i18next'; interface PostListingState { showEdit: boolean; showRemoveDialog: boolean; removeReason: string; showBanDialog: boolean; banReason: string; banExpires: string; banType: BanType; showConfirmTransferSite: boolean; showConfirmTransferCommunity: boolean; imageExpanded: boolean; viewSource: boolean; upvoteLoading: boolean; downvoteLoading: boolean; } interface PostListingProps { post: Post; showCommunity?: boolean; showBody?: boolean; viewOnly?: boolean; moderators?: Array; admins?: Array; } export class PostListing extends Component { private emptyState: PostListingState = { showEdit: false, showRemoveDialog: false, removeReason: null, showBanDialog: false, banReason: null, banExpires: null, banType: BanType.Community, showConfirmTransferSite: false, showConfirmTransferCommunity: false, imageExpanded: false, viewSource: false, upvoteLoading: this.props.post.upvoteLoading, downvoteLoading: this.props.post.downvoteLoading, }; constructor(props: any, context: any) { super(props, context); this.state = this.emptyState; this.handlePostLike = this.handlePostLike.bind(this); this.handlePostDisLike = this.handlePostDisLike.bind(this); this.handleEditPost = this.handleEditPost.bind(this); this.handleEditCancel = this.handleEditCancel.bind(this); } componentWillReceiveProps(nextProps: PostListingProps) { if ( nextProps.post.upvoteLoading !== this.state.upvoteLoading || nextProps.post.downvoteLoading !== this.state.downvoteLoading ) { this.setState({ upvoteLoading: false, downvoteLoading: false, }); } } render() { return (
{!this.state.showEdit ? ( this.listing() ) : (
)}
); } listing() { let post = this.props.post; return (
{post.score}
{WebSocketService.Instance.site.enable_downvotes && ( )}
{post.url && isImage(post.url) && !post.nsfw && !post.community_nsfw && !this.state.imageExpanded && ( )} {post.url && isVideo(post.url) && ( )}
{post.url ? ( {post.name} ) : ( {post.name} )}
{post.url && ( {new URL(post.url).hostname} )} {post.url && isImage(post.url) && ( <> {!this.state.imageExpanded ? ( [+] ) : ( [-]
)} )} {post.removed && ( # )} {post.deleted && ( # )} {post.locked && ( # )} {post.stickied && ( # )} {post.nsfw && ( # )}
  • {i18n.t('by')} {post.creator_avatar && showAvatars() && ( )} {post.creator_name} {this.isMod && ( # )} {this.isAdmin && ( # )} {(post.banned_from_community || post.banned) && ( # )} {this.props.showCommunity && ( {i18n.t('to')} {post.community_name} )}
  • (+{post.upvotes} | -{post.downvotes} )
  • #
    {UserService.Instance.user && ( <> {this.props.showBody && ( <>
  • {post.saved ? i18n.t('unsave') : i18n.t('save')}
  • #
  • )} {this.myPost && this.props.showBody && ( <>
  • #
  • {!post.deleted ? i18n.t('delete') : i18n.t('restore')}
  • )} {this.canModOnSelf && ( <>
  • {post.locked ? i18n.t('unlock') : i18n.t('lock')}
  • {post.stickied ? i18n.t('unsticky') : i18n.t('sticky')}
  • )} {/* Mods can ban from community, and appoint as mods to community */} {(this.canMod || this.canAdmin) && (
  • {!post.removed ? ( # ) : ( # )}
  • )} {this.canMod && ( <> {!this.isMod && (
  • {!post.banned_from_community ? ( # ) : ( # )}
  • )} {!post.banned_from_community && (
  • {this.isMod ? i18n.t('remove_as_mod') : i18n.t('appoint_as_mod')}
  • )} )} {/* Community creators and admins can transfer community to another mod */} {(this.amCommunityCreator || this.canAdmin) && this.isMod && (
  • {!this.state.showConfirmTransferCommunity ? ( # ) : ( <> # # # )}
  • )} {/* Admins can ban from all, and appoint other admins */} {this.canAdmin && ( <> {!this.isAdmin && (
  • {!post.banned ? ( # ) : ( # )}
  • )} {!post.banned && (
  • {this.isAdmin ? i18n.t('remove_as_admin') : i18n.t('appoint_as_admin')}
  • )} )} {/* Site Creator can transfer to another admin */} {this.amSiteCreator && this.isAdmin && (
  • {!this.state.showConfirmTransferSite ? ( # ) : ( <> # # # )}
  • )} )} {this.props.showBody && post.body && (
  • #
  • )}
{this.state.showRemoveDialog && (
)} {this.state.showBanDialog && (
{/* TODO hold off on expires until later */} {/*
*/} {/* */} {/* */} {/*
*/}
)} {this.props.showBody && post.body && ( <> {this.state.viewSource ? (
{post.body}
) : (
)} )}
); } private get myPost(): boolean { return ( UserService.Instance.user && this.props.post.creator_id == UserService.Instance.user.id ); } get isMod(): boolean { return ( this.props.moderators && isMod( this.props.moderators.map(m => m.user_id), this.props.post.creator_id ) ); } get isAdmin(): boolean { return ( this.props.admins && isMod( this.props.admins.map(a => a.id), this.props.post.creator_id ) ); } get canMod(): boolean { if (this.props.admins && this.props.moderators) { let adminsThenMods = this.props.admins .map(a => a.id) .concat(this.props.moderators.map(m => m.user_id)); return canMod( UserService.Instance.user, adminsThenMods, this.props.post.creator_id ); } else { return false; } } get canModOnSelf(): boolean { if (this.props.admins && this.props.moderators) { let adminsThenMods = this.props.admins .map(a => a.id) .concat(this.props.moderators.map(m => m.user_id)); return canMod( UserService.Instance.user, adminsThenMods, this.props.post.creator_id, true ); } else { return false; } } get canAdmin(): boolean { return ( this.props.admins && canMod( UserService.Instance.user, this.props.admins.map(a => a.id), this.props.post.creator_id ) ); } get amCommunityCreator(): boolean { return ( this.props.moderators && UserService.Instance.user && this.props.post.creator_id != UserService.Instance.user.id && UserService.Instance.user.id == this.props.moderators[0].user_id ); } get amSiteCreator(): boolean { return ( this.props.admins && UserService.Instance.user && this.props.post.creator_id != UserService.Instance.user.id && UserService.Instance.user.id == this.props.admins[0].id ); } handlePostLike(i: PostListing) { i.setState({ upvoteLoading: true }); let form: CreatePostLikeForm = { post_id: i.props.post.id, score: i.props.post.my_vote == 1 ? 0 : 1, }; WebSocketService.Instance.likePost(form); } handlePostDisLike(i: PostListing) { i.setState({ downvoteLoading: true }); let form: CreatePostLikeForm = { post_id: i.props.post.id, score: i.props.post.my_vote == -1 ? 0 : -1, }; WebSocketService.Instance.likePost(form); } handleEditClick(i: PostListing) { i.state.showEdit = true; i.setState(i.state); } handleEditCancel() { this.state.showEdit = false; this.setState(this.state); } // The actual editing is done in the recieve for post handleEditPost() { this.state.showEdit = false; this.setState(this.state); } handleDeleteClick(i: PostListing) { let deleteForm: PostFormI = { body: i.props.post.body, community_id: i.props.post.community_id, name: i.props.post.name, url: i.props.post.url, edit_id: i.props.post.id, creator_id: i.props.post.creator_id, deleted: !i.props.post.deleted, nsfw: i.props.post.nsfw, auth: null, }; WebSocketService.Instance.editPost(deleteForm); } handleSavePostClick(i: PostListing) { let saved = i.props.post.saved == undefined ? true : !i.props.post.saved; let form: SavePostForm = { post_id: i.props.post.id, save: saved, }; WebSocketService.Instance.savePost(form); } get crossPostParams(): string { let params = `?name=${this.props.post.name}`; if (this.props.post.url) { params += `&url=${this.props.post.url}`; } if (this.props.post.body) { params += `&body=${this.props.post.body}`; } return params; } handleModRemoveShow(i: PostListing) { i.state.showRemoveDialog = true; i.setState(i.state); } handleModRemoveReasonChange(i: PostListing, event: any) { i.state.removeReason = event.target.value; i.setState(i.state); } handleModRemoveSubmit(i: PostListing) { event.preventDefault(); let form: PostFormI = { name: i.props.post.name, community_id: i.props.post.community_id, edit_id: i.props.post.id, creator_id: i.props.post.creator_id, removed: !i.props.post.removed, reason: i.state.removeReason, nsfw: i.props.post.nsfw, auth: null, }; WebSocketService.Instance.editPost(form); i.state.showRemoveDialog = false; i.setState(i.state); } handleModLock(i: PostListing) { let form: PostFormI = { name: i.props.post.name, community_id: i.props.post.community_id, edit_id: i.props.post.id, creator_id: i.props.post.creator_id, nsfw: i.props.post.nsfw, locked: !i.props.post.locked, auth: null, }; WebSocketService.Instance.editPost(form); } handleModSticky(i: PostListing) { let form: PostFormI = { name: i.props.post.name, community_id: i.props.post.community_id, edit_id: i.props.post.id, creator_id: i.props.post.creator_id, nsfw: i.props.post.nsfw, stickied: !i.props.post.stickied, auth: null, }; WebSocketService.Instance.editPost(form); } handleModBanFromCommunityShow(i: PostListing) { i.state.showBanDialog = true; i.state.banType = BanType.Community; i.setState(i.state); } handleModBanShow(i: PostListing) { i.state.showBanDialog = true; i.state.banType = BanType.Site; i.setState(i.state); } handleModBanReasonChange(i: PostListing, event: any) { i.state.banReason = event.target.value; i.setState(i.state); } handleModBanExpiresChange(i: PostListing, event: any) { i.state.banExpires = event.target.value; i.setState(i.state); } handleModBanFromCommunitySubmit(i: PostListing) { i.state.banType = BanType.Community; i.setState(i.state); i.handleModBanBothSubmit(i); } handleModBanSubmit(i: PostListing) { i.state.banType = BanType.Site; i.setState(i.state); i.handleModBanBothSubmit(i); } handleModBanBothSubmit(i: PostListing) { event.preventDefault(); if (i.state.banType == BanType.Community) { let form: BanFromCommunityForm = { user_id: i.props.post.creator_id, community_id: i.props.post.community_id, ban: !i.props.post.banned_from_community, reason: i.state.banReason, expires: getUnixTime(i.state.banExpires), }; WebSocketService.Instance.banFromCommunity(form); } else { let form: BanUserForm = { user_id: i.props.post.creator_id, ban: !i.props.post.banned, reason: i.state.banReason, expires: getUnixTime(i.state.banExpires), }; WebSocketService.Instance.banUser(form); } i.state.showBanDialog = false; i.setState(i.state); } handleAddModToCommunity(i: PostListing) { let form: AddModToCommunityForm = { user_id: i.props.post.creator_id, community_id: i.props.post.community_id, added: !i.isMod, }; WebSocketService.Instance.addModToCommunity(form); i.setState(i.state); } handleAddAdmin(i: PostListing) { let form: AddAdminForm = { user_id: i.props.post.creator_id, added: !i.isAdmin, }; WebSocketService.Instance.addAdmin(form); i.setState(i.state); } handleShowConfirmTransferCommunity(i: PostListing) { i.state.showConfirmTransferCommunity = true; i.setState(i.state); } handleCancelShowConfirmTransferCommunity(i: PostListing) { i.state.showConfirmTransferCommunity = false; i.setState(i.state); } handleTransferCommunity(i: PostListing) { let form: TransferCommunityForm = { community_id: i.props.post.community_id, user_id: i.props.post.creator_id, }; WebSocketService.Instance.transferCommunity(form); i.state.showConfirmTransferCommunity = false; i.setState(i.state); } handleShowConfirmTransferSite(i: PostListing) { i.state.showConfirmTransferSite = true; i.setState(i.state); } handleCancelShowConfirmTransferSite(i: PostListing) { i.state.showConfirmTransferSite = false; i.setState(i.state); } handleTransferSite(i: PostListing) { let form: TransferSiteForm = { user_id: i.props.post.creator_id, }; WebSocketService.Instance.transferSite(form); i.state.showConfirmTransferSite = false; i.setState(i.state); } handleImageExpandClick(i: PostListing) { i.state.imageExpanded = !i.state.imageExpanded; i.setState(i.state); } handleViewSource(i: PostListing) { i.state.viewSource = !i.state.viewSource; i.setState(i.state); } }