FeaturePost,
Language,
LockPost,
- PersonViewSafe,
- PostFeatureType,
+ PersonView,
PostView,
PurgePerson,
PurgePost,
SavePost,
TransferCommunity,
} from "lemmy-js-client";
-import { externalHost } from "../../env";
+import { getExternalHost, getHttpBase } from "../../env";
import { i18n } from "../../i18next";
-import { BanType, PurgeType } from "../../interfaces";
+import { BanType, PostFormParams, PurgeType } from "../../interfaces";
import { UserService, WebSocketService } from "../../services";
import {
amAdmin,
amCommunityCreator,
+ amMod,
canAdmin,
canMod,
+ canShare,
futureDaysToUnixTime,
hostname,
isAdmin,
numToSI,
relTags,
setupTippy,
+ share,
showScores,
wsClient,
} from "../../utils";
post_view: PostView;
duplicates?: PostView[];
moderators?: CommunityModeratorView[];
- admins?: PersonViewSafe[];
+ admins?: PersonView[];
allLanguages: Language[];
siteLanguages: number[];
showCommunity?: boolean;
}
render() {
- let post = this.props.post_view.post;
+ const post = this.props.post_view.post;
+
return (
<div className="post-listing">
{!this.state.showEdit ? (
<PersonListing person={post_view.creator} />
{this.creatorIsMod_ && (
- <span className="mx-1 badge badge-light">{i18n.t("mod")}</span>
+ <span className="mx-1 badge badge-muted">{i18n.t("mod")}</span>
)}
{this.creatorIsAdmin_ && (
- <span className="mx-1 badge badge-light">{i18n.t("admin")}</span>
+ <span className="mx-1 badge badge-muted">{i18n.t("admin")}</span>
)}
{post_view.creator.bot_account && (
- <span className="mx-1 badge badge-light">
+ <span className="mx-1 badge badge-muted">
{i18n.t("bot_account").toLowerCase()}
</span>
)}
- {(post_view.creator_banned_from_community ||
- isBanned(post_view.creator)) && (
- <span className="mx-1 badge badge-danger">{i18n.t("banned")}</span>
- )}
- {post_view.creator_blocked && (
- <span className="mx-1 badge badge-danger">{"blocked"}</span>
- )}
{this.props.showCommunity && (
<span>
<span className="mx-1"> {i18n.t("to")} </span>
</span>
)}
</li>
+ {post_view.post.language_id !== 0 && (
+ <span className="mx-1 badge badge-muted">
+ {
+ this.props.allLanguages.find(
+ lang => lang.id === post_view.post.language_id
+ )?.name
+ }
+ </span>
+ )}
<li className="list-inline-item">•</li>
- {url && !(hostname(url) == externalHost) && (
+ {url && !(hostname(url) === getExternalHost()) && (
<>
<li className="list-inline-item">
<a
commentsLine(mobile = false) {
let post = this.props.post_view.post;
+
return (
<div className="d-flex justify-content-start flex-wrap text-muted font-weight-bold mb-1">
{this.commentsButton}
+ {canShare() && (
+ <button
+ className="btn btn-link"
+ onClick={linkEvent(this, this.handleShare)}
+ type="button"
+ >
+ <Icon icon="share" inline />
+ </button>
+ )}
{!post.local && (
<a
className="btn btn-link btn-animate text-muted py-0"
{this.state.showAdvanced && (
<>
{this.showBody && post_view.post.body && this.viewSourceButton}
- {this.canModOnSelf_ && (
+ {/* Any mod can do these, not limited to hierarchy*/}
+ {(amMod(this.props.moderators) || amAdmin()) && (
<>
{this.lockButton}
{this.featureButton}
<Link
className="text-muted"
title={i18n.t("number_of_comments", {
- count: post_view.counts.comments,
- formattedCount: post_view.counts.comments,
+ count: Number(post_view.counts.comments),
+ formattedCount: Number(post_view.counts.comments),
})}
to={`/post/${post_view.post.id}?scrollToComments=true`}
>
<Icon icon="message-square" classes="mr-1" inline />
<span className="mr-2">
{i18n.t("number_of_comments", {
- count: post_view.counts.comments,
+ count: Number(post_view.counts.comments),
formattedCount: numToSI(post_view.counts.comments),
})}
</span>
return (
<Link
className="btn btn-link btn-animate text-muted py-0"
- to={`/create_post${this.crossPostParams}`}
+ to={{
+ /* Empty string properties are required to satisfy type*/
+ pathname: "/create_post",
+ state: { ...this.crossPostParams },
+ hash: "",
+ key: "",
+ search: "",
+ }}
title={i18n.t("cross_post")}
>
<Icon icon="copy" inline />
}
get featureButton() {
- const featured_community = this.props.post_view.post.featured_community;
- const label_community = featured_community
+ const featuredCommunity = this.props.post_view.post.featured_community;
+ const labelCommunity = featuredCommunity
? i18n.t("unfeature_from_community")
: i18n.t("feature_in_community");
- const is_admin = amAdmin();
- const featured_local = this.props.post_view.post.featured_local;
- const label_local = featured_local
+ const featuredLocal = this.props.post_view.post.featured_local;
+ const labelLocal = featuredLocal
? i18n.t("unfeature_from_local")
: i18n.t("feature_in_local");
return (
<span>
<button
className="btn btn-link btn-animate text-muted py-0 pl-0"
- onClick={() => this.handleModFeaturePost(this, true)}
- data-tippy-content={label_community}
- aria-label={label_community}
+ onClick={linkEvent(this, this.handleModFeaturePostCommunity)}
+ data-tippy-content={labelCommunity}
+ aria-label={labelCommunity}
>
<Icon
icon="pin"
- classes={classNames({ "text-success": featured_community })}
+ classes={classNames({ "text-success": featuredCommunity })}
inline
/>{" "}
Community
</button>
- {is_admin && (
+ {amAdmin() && (
<button
className="btn btn-link btn-animate text-muted py-0"
- onClick={() => this.handleModFeaturePost(this, false)}
- data-tippy-content={label_local}
- aria-label={label_local}
+ onClick={linkEvent(this, this.handleModFeaturePostLocal)}
+ data-tippy-content={labelLocal}
+ aria-label={labelLocal}
>
<Icon
icon="pin"
- classes={classNames({ "text-success": featured_local })}
+ classes={classNames({ "text-success": featuredLocal })}
inline
/>{" "}
Local
this,
this.handleModBanFromCommunityShow
)}
- aria-label={i18n.t("ban")}
+ aria-label={i18n.t("ban_from_community")}
>
- {i18n.t("ban")}
+ {i18n.t("ban_from_community")}
</button>
) : (
<button
this.setState({ showEdit: false });
}
+ handleShare(i: PostListing) {
+ const { name, body, id } = i.props.post_view.post;
+ share({
+ title: name,
+ text: body?.slice(0, 50),
+ url: `${getHttpBase()}/post/${id}`,
+ });
+ }
+
handleShowReportDialog(i: PostListing) {
i.setState({ showReportDialog: !i.state.showReportDialog });
}
}
}
- get crossPostParams(): string {
- let post = this.props.post_view.post;
- let params = `?title=${encodeURIComponent(post.name)}`;
+ get crossPostParams(): PostFormParams {
+ const queryParams: PostFormParams = {};
+ const { name, url } = this.props.post_view.post;
+
+ queryParams.name = name;
- if (post.url) {
- params += `&url=${encodeURIComponent(post.url)}`;
+ if (url) {
+ queryParams.url = url;
}
- let crossPostBody = this.crossPostBody();
+
+ const crossPostBody = this.crossPostBody();
if (crossPostBody) {
- params += `&body=${encodeURIComponent(crossPostBody)}`;
+ queryParams.body = crossPostBody;
}
- return params;
+
+ return queryParams;
}
crossPostBody(): string | undefined {
}
}
- handleModFeaturePost(i: PostListing, is_community: boolean) {
+ handleModFeaturePostLocal(i: PostListing) {
let auth = myAuth();
if (auth) {
- let featured: [PostFeatureType, boolean] = is_community
- ? [
- PostFeatureType.Community,
- !i.props.post_view.post.featured_community,
- ]
- : [PostFeatureType.Local, !i.props.post_view.post.featured_local];
+ let form: FeaturePost = {
+ post_id: i.props.post_view.post.id,
+ feature_type: "Local",
+ featured: !i.props.post_view.post.featured_local,
+ auth,
+ };
+ WebSocketService.Instance.send(wsClient.featurePost(form));
+ }
+ }
+ handleModFeaturePostCommunity(i: PostListing) {
+ let auth = myAuth();
+ if (auth) {
let form: FeaturePost = {
post_id: i.props.post_view.post.id,
- feature_type: featured[0],
- featured: featured[1],
+ feature_type: "Community",
+ featured: !i.props.post_view.post.featured_community,
auth,
};
WebSocketService.Instance.send(wsClient.featurePost(form));
get pointsTippy(): string {
let points = i18n.t("number_of_points", {
- count: this.state.score,
- formattedCount: this.state.score,
+ count: Number(this.state.score),
+ formattedCount: Number(this.state.score),
});
let upvotes = i18n.t("number_of_upvotes", {
- count: this.state.upvotes,
- formattedCount: this.state.upvotes,
+ count: Number(this.state.upvotes),
+ formattedCount: Number(this.state.upvotes),
});
let downvotes = i18n.t("number_of_downvotes", {
- count: this.state.downvotes,
- formattedCount: this.state.downvotes,
+ count: Number(this.state.downvotes),
+ formattedCount: Number(this.state.downvotes),
});
return `${points} • ${upvotes} • ${downvotes}`;