mirror of
https://github.com/LemmyNet/lemmy-ui.git
synced 2024-11-22 20:31:13 +00:00
Merge branch 'LemmyNet:main' into userpage
This commit is contained in:
commit
0eb4649c19
12 changed files with 523 additions and 475 deletions
|
@ -1 +1 @@
|
|||
Subproject commit 762cb699a98d11032fe924cf50bf09e252413f6e
|
||||
Subproject commit 0d6ef6791f9175fb98ec99598c724d83e8e0d4ef
|
48
package.json
48
package.json
|
@ -17,13 +17,13 @@
|
|||
},
|
||||
"repository": "https://github.com/LemmyNet/lemmy-ui",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/parser": "^4.32.0",
|
||||
"@typescript-eslint/parser": "^5.1.0",
|
||||
"autosize": "^5.0.1",
|
||||
"check-password-strength": "^2.0.3",
|
||||
"choices.js": "^9.0.1",
|
||||
"emoji-short-name": "^1.0.0",
|
||||
"express": "~4.17.1",
|
||||
"i18next": "^21.1.1",
|
||||
"i18next": "^21.3.2",
|
||||
"inferno": "^7.4.10",
|
||||
"inferno-create-element": "^7.4.10",
|
||||
"inferno-helmet": "^5.2.1",
|
||||
|
@ -41,41 +41,41 @@
|
|||
"moment": "^2.29.1",
|
||||
"reconnecting-websocket": "^4.4.0",
|
||||
"register-service-worker": "^1.7.2",
|
||||
"rxjs": "^7.2.0",
|
||||
"rxjs": "^7.4.0",
|
||||
"serialize-javascript": "^6.0.0",
|
||||
"tippy.js": "^6.3.1",
|
||||
"toastify-js": "^1.11.1",
|
||||
"tippy.js": "^6.3.2",
|
||||
"toastify-js": "^1.11.2",
|
||||
"tributejs": "^5.1.3",
|
||||
"ws": "^8.2.2"
|
||||
"ws": "^8.2.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.15.5",
|
||||
"@babel/plugin-transform-runtime": "^7.14.5",
|
||||
"@babel/plugin-transform-typescript": "^7.15.4",
|
||||
"@babel/preset-env": "7.15.6",
|
||||
"@babel/core": "^7.15.8",
|
||||
"@babel/plugin-transform-runtime": "^7.15.8",
|
||||
"@babel/plugin-transform-typescript": "^7.15.8",
|
||||
"@babel/preset-env": "7.15.8",
|
||||
"@babel/preset-typescript": "^7.14.5",
|
||||
"@babel/runtime": "^7.15.4",
|
||||
"@types/autosize": "^4.0.0",
|
||||
"@types/express": "^4.17.13",
|
||||
"@types/node": "^16.10.1",
|
||||
"@types/node": "^16.11.1",
|
||||
"@types/node-fetch": "^2.5.11",
|
||||
"@types/serialize-javascript": "^5.0.1",
|
||||
"@typescript-eslint/eslint-plugin": "^4.32.0",
|
||||
"@typescript-eslint/eslint-plugin": "^5.1.0",
|
||||
"babel-loader": "^8.2.2",
|
||||
"babel-plugin-inferno": "^6.3.0",
|
||||
"bootstrap": "^5.1.1",
|
||||
"bootswatch": "^5.1.1",
|
||||
"bootstrap": "^5.1.3",
|
||||
"bootswatch": "^5.1.3",
|
||||
"clean-webpack-plugin": "^4.0.0",
|
||||
"copy-webpack-plugin": "^9.0.1",
|
||||
"css-loader": "^6.3.0",
|
||||
"eslint": "^7.30.0",
|
||||
"css-loader": "^6.4.0",
|
||||
"eslint": "^8.0.1",
|
||||
"eslint-plugin-prettier": "^4.0.0",
|
||||
"husky": "^7.0.2",
|
||||
"import-sort-style-module": "^6.0.0",
|
||||
"iso-639-1": "^2.1.9",
|
||||
"lemmy-js-client": "0.13.1-rc.1",
|
||||
"lint-staged": "^11.0.1",
|
||||
"mini-css-extract-plugin": "^2.3.0",
|
||||
"lemmy-js-client": "0.13.4-rc.1",
|
||||
"lint-staged": "^11.2.3",
|
||||
"mini-css-extract-plugin": "^2.4.2",
|
||||
"node-fetch": "^2.6.1",
|
||||
"node-sass": "^6.0.1",
|
||||
"prettier": "^2.4.1",
|
||||
|
@ -84,14 +84,14 @@
|
|||
"prettier-plugin-packagejson": "^2.2.13",
|
||||
"rimraf": "^3.0.2",
|
||||
"run-node-webpack-plugin": "^1.3.0",
|
||||
"sass-loader": "^12.1.0",
|
||||
"sass-loader": "^12.2.0",
|
||||
"sortpack": "^2.2.0",
|
||||
"style-loader": "^3.3.0",
|
||||
"terser": "^5.9.0",
|
||||
"typescript": "^4.4.3",
|
||||
"webpack": "5.54.0",
|
||||
"webpack-cli": "^4.7.2",
|
||||
"webpack-dev-server": "4.3.0",
|
||||
"typescript": "^4.4.4",
|
||||
"webpack": "5.58.2",
|
||||
"webpack-cli": "^4.9.1",
|
||||
"webpack-dev-server": "4.3.1",
|
||||
"webpack-node-externals": "^3.0.0"
|
||||
},
|
||||
"engines": {
|
||||
|
|
|
@ -2,19 +2,12 @@ import { Component, createRef, linkEvent, RefObject } from "inferno";
|
|||
import { Link } from "inferno-router";
|
||||
import {
|
||||
CommentResponse,
|
||||
CommentView,
|
||||
GetPersonMentions,
|
||||
GetPersonMentionsResponse,
|
||||
GetPrivateMessages,
|
||||
GetReplies,
|
||||
GetRepliesResponse,
|
||||
GetReportCount,
|
||||
GetReportCountResponse,
|
||||
GetSiteResponse,
|
||||
GetUnreadCount,
|
||||
GetUnreadCountResponse,
|
||||
PrivateMessageResponse,
|
||||
PrivateMessagesResponse,
|
||||
PrivateMessageView,
|
||||
SortType,
|
||||
UserOperation,
|
||||
} from "lemmy-js-client";
|
||||
import { Subscription } from "rxjs";
|
||||
|
@ -23,7 +16,6 @@ import { UserService, WebSocketService } from "../../services";
|
|||
import {
|
||||
authField,
|
||||
donateLemmyUrl,
|
||||
fetchLimit,
|
||||
getLanguage,
|
||||
isBrowser,
|
||||
notifyComment,
|
||||
|
@ -47,9 +39,6 @@ interface NavbarProps {
|
|||
interface NavbarState {
|
||||
isLoggedIn: boolean;
|
||||
expanded: boolean;
|
||||
replies: CommentView[];
|
||||
mentions: CommentView[];
|
||||
messages: PrivateMessageView[];
|
||||
unreadInboxCount: number;
|
||||
unreadReportCount: number;
|
||||
searchParam: string;
|
||||
|
@ -68,9 +57,6 @@ export class Navbar extends Component<NavbarProps, NavbarState> {
|
|||
isLoggedIn: !!this.props.site_res.my_user,
|
||||
unreadInboxCount: 0,
|
||||
unreadReportCount: 0,
|
||||
replies: [],
|
||||
mentions: [],
|
||||
messages: [],
|
||||
expanded: false,
|
||||
searchParam: "",
|
||||
toggleSearch: false,
|
||||
|
@ -577,30 +563,10 @@ export class Navbar extends Component<NavbarProps, NavbarState> {
|
|||
})
|
||||
);
|
||||
this.fetchUnreads();
|
||||
} else if (op == UserOperation.GetReplies) {
|
||||
let data = wsJsonToRes<GetRepliesResponse>(msg).data;
|
||||
let unreadReplies = data.replies.filter(r => !r.comment.read);
|
||||
|
||||
this.state.replies = unreadReplies;
|
||||
this.state.unreadInboxCount = this.calculateUnreadInboxCount();
|
||||
this.setState(this.state);
|
||||
this.sendUnreadCount();
|
||||
} else if (op == UserOperation.GetPersonMentions) {
|
||||
let data = wsJsonToRes<GetPersonMentionsResponse>(msg).data;
|
||||
let unreadMentions = data.mentions.filter(r => !r.comment.read);
|
||||
|
||||
this.state.mentions = unreadMentions;
|
||||
this.state.unreadInboxCount = this.calculateUnreadInboxCount();
|
||||
this.setState(this.state);
|
||||
this.sendUnreadCount();
|
||||
} else if (op == UserOperation.GetPrivateMessages) {
|
||||
let data = wsJsonToRes<PrivateMessagesResponse>(msg).data;
|
||||
let unreadMessages = data.private_messages.filter(
|
||||
r => !r.private_message.read
|
||||
);
|
||||
|
||||
this.state.messages = unreadMessages;
|
||||
this.state.unreadInboxCount = this.calculateUnreadInboxCount();
|
||||
} else if (op == UserOperation.GetUnreadCount) {
|
||||
let data = wsJsonToRes<GetUnreadCountResponse>(msg).data;
|
||||
this.state.unreadInboxCount =
|
||||
data.replies + data.mentions + data.private_messages;
|
||||
this.setState(this.state);
|
||||
this.sendUnreadCount();
|
||||
} else if (op == UserOperation.GetReportCount) {
|
||||
|
@ -628,7 +594,6 @@ export class Navbar extends Component<NavbarProps, NavbarState> {
|
|||
UserService.Instance.myUserInfo.local_user_view.local_user.id
|
||||
)
|
||||
) {
|
||||
this.state.replies.push(data.comment_view);
|
||||
this.state.unreadInboxCount++;
|
||||
this.setState(this.state);
|
||||
this.sendUnreadCount();
|
||||
|
@ -643,7 +608,6 @@ export class Navbar extends Component<NavbarProps, NavbarState> {
|
|||
data.private_message_view.recipient.id ==
|
||||
UserService.Instance.myUserInfo.local_user_view.person.id
|
||||
) {
|
||||
this.state.messages.push(data.private_message_view);
|
||||
this.state.unreadInboxCount++;
|
||||
this.setState(this.state);
|
||||
this.sendUnreadCount();
|
||||
|
@ -654,41 +618,13 @@ export class Navbar extends Component<NavbarProps, NavbarState> {
|
|||
}
|
||||
|
||||
fetchUnreads() {
|
||||
// TODO we should just add a count call to the API for these, because this is a limited fetch,
|
||||
// and it shouldn't have to fetch the actual content
|
||||
if (this.currentLocation !== "/inbox") {
|
||||
console.log("Fetching inbox unreads...");
|
||||
let repliesForm: GetReplies = {
|
||||
sort: SortType.New,
|
||||
unread_only: true,
|
||||
page: 1,
|
||||
limit: fetchLimit,
|
||||
|
||||
let unreadForm: GetUnreadCount = {
|
||||
auth: authField(),
|
||||
};
|
||||
|
||||
let personMentionsForm: GetPersonMentions = {
|
||||
sort: SortType.New,
|
||||
unread_only: true,
|
||||
page: 1,
|
||||
limit: fetchLimit,
|
||||
auth: authField(),
|
||||
};
|
||||
|
||||
let privateMessagesForm: GetPrivateMessages = {
|
||||
unread_only: true,
|
||||
page: 1,
|
||||
limit: fetchLimit,
|
||||
auth: authField(),
|
||||
};
|
||||
|
||||
WebSocketService.Instance.send(wsClient.getReplies(repliesForm));
|
||||
WebSocketService.Instance.send(
|
||||
wsClient.getPersonMentions(personMentionsForm)
|
||||
);
|
||||
WebSocketService.Instance.send(
|
||||
wsClient.getPrivateMessages(privateMessagesForm)
|
||||
);
|
||||
}
|
||||
WebSocketService.Instance.send(wsClient.getUnreadCount(unreadForm));
|
||||
|
||||
console.log("Fetching reports...");
|
||||
|
||||
|
@ -713,14 +649,6 @@ export class Navbar extends Component<NavbarProps, NavbarState> {
|
|||
);
|
||||
}
|
||||
|
||||
calculateUnreadInboxCount(): number {
|
||||
return (
|
||||
this.state.replies.filter(r => !r.comment.read).length +
|
||||
this.state.mentions.filter(r => !r.comment.read).length +
|
||||
this.state.messages.filter(r => !r.private_message.read).length
|
||||
);
|
||||
}
|
||||
|
||||
get canAdmin(): boolean {
|
||||
return (
|
||||
UserService.Instance.myUserInfo &&
|
||||
|
|
|
@ -182,6 +182,11 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
|
|||
{i18n.t("creator")}
|
||||
</div>
|
||||
)}
|
||||
{cv.creator.bot_account && (
|
||||
<div className="badge badge-light d-none d-sm-inline mr-2">
|
||||
{i18n.t("bot_account").toLowerCase()}
|
||||
</div>
|
||||
)}
|
||||
{(cv.creator_banned_from_community || cv.creator.banned) && (
|
||||
<div className="badge badge-danger mr-2">
|
||||
{i18n.t("banned")}
|
||||
|
|
|
@ -23,13 +23,27 @@ export class MomentTime extends Component<MomentTimeProps, any> {
|
|||
moment.locale(lang);
|
||||
}
|
||||
|
||||
createdAndModifiedTimes() {
|
||||
let created = this.props.data.published || this.props.data.when_;
|
||||
return `
|
||||
<div>
|
||||
<div>
|
||||
${capitalizeFirstLetter(i18n.t("created"))}: ${this.format(created)}
|
||||
</div>
|
||||
<div>
|
||||
${capitalizeFirstLetter(i18n.t("modified"))} ${this.format(
|
||||
this.props.data.updated
|
||||
)}
|
||||
</div>
|
||||
</div>`;
|
||||
}
|
||||
|
||||
render() {
|
||||
if (!this.props.ignoreUpdated && this.props.data.updated) {
|
||||
return (
|
||||
<span
|
||||
data-tippy-content={`${capitalizeFirstLetter(
|
||||
i18n.t("modified")
|
||||
)} ${this.format(this.props.data.updated)}`}
|
||||
data-tippy-content={this.createdAndModifiedTimes()}
|
||||
data-tippy-allowHtml={true}
|
||||
className="font-italics pointer unselectable"
|
||||
>
|
||||
<Icon icon="edit-2" classes="icon-inline mr-1" />
|
||||
|
@ -37,13 +51,13 @@ export class MomentTime extends Component<MomentTimeProps, any> {
|
|||
</span>
|
||||
);
|
||||
} else {
|
||||
let str = this.props.data.published || this.props.data.when_;
|
||||
let created = this.props.data.published || this.props.data.when_;
|
||||
return (
|
||||
<span
|
||||
className="pointer unselectable"
|
||||
data-tippy-content={this.format(str)}
|
||||
data-tippy-content={this.format(created)}
|
||||
>
|
||||
{moment.utc(str).fromNow(!this.props.showAgo)}
|
||||
{moment.utc(created).fromNow(!this.props.showAgo)}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -31,7 +31,7 @@ import { Icon, Spinner } from "../common/icon";
|
|||
const passwordStrengthOptions: Options<string> = [
|
||||
{
|
||||
id: 0,
|
||||
value: "too_weak",
|
||||
value: "very_weak",
|
||||
minDiversity: 0,
|
||||
minLength: 0,
|
||||
},
|
||||
|
|
|
@ -533,11 +533,20 @@ export class Inbox extends Component<any, InboxState> {
|
|||
i.state.replies = [];
|
||||
i.state.mentions = [];
|
||||
i.state.messages = [];
|
||||
i.sendUnreadCount();
|
||||
UserService.Instance.unreadInboxCountSub.next(0);
|
||||
window.scrollTo(0, 0);
|
||||
i.setState(i.state);
|
||||
}
|
||||
|
||||
sendUnreadCount(read: boolean) {
|
||||
let urcs = UserService.Instance.unreadInboxCountSub;
|
||||
if (read) {
|
||||
urcs.next(urcs.getValue() - 1);
|
||||
} else {
|
||||
urcs.next(urcs.getValue() + 1);
|
||||
}
|
||||
}
|
||||
|
||||
parseMessage(msg: any) {
|
||||
let op = wsUserOp(msg);
|
||||
console.log(msg);
|
||||
|
@ -551,7 +560,6 @@ export class Inbox extends Component<any, InboxState> {
|
|||
this.state.replies = data.replies;
|
||||
this.state.combined = this.buildCombined();
|
||||
this.state.loading = false;
|
||||
this.sendUnreadCount();
|
||||
window.scrollTo(0, 0);
|
||||
this.setState(this.state);
|
||||
setupTippy();
|
||||
|
@ -559,7 +567,6 @@ export class Inbox extends Component<any, InboxState> {
|
|||
let data = wsJsonToRes<GetPersonMentionsResponse>(msg).data;
|
||||
this.state.mentions = data.mentions;
|
||||
this.state.combined = this.buildCombined();
|
||||
this.sendUnreadCount();
|
||||
window.scrollTo(0, 0);
|
||||
this.setState(this.state);
|
||||
setupTippy();
|
||||
|
@ -567,7 +574,6 @@ export class Inbox extends Component<any, InboxState> {
|
|||
let data = wsJsonToRes<PrivateMessagesResponse>(msg).data;
|
||||
this.state.messages = data.private_messages;
|
||||
this.state.combined = this.buildCombined();
|
||||
this.sendUnreadCount();
|
||||
window.scrollTo(0, 0);
|
||||
this.setState(this.state);
|
||||
setupTippy();
|
||||
|
@ -635,7 +641,7 @@ export class Inbox extends Component<any, InboxState> {
|
|||
data.private_message_view.private_message.read;
|
||||
}
|
||||
}
|
||||
this.sendUnreadCount();
|
||||
this.sendUnreadCount(data.private_message_view.private_message.read);
|
||||
this.setState(this.state);
|
||||
} else if (op == UserOperation.MarkAllAsRead) {
|
||||
// Moved to be instant
|
||||
|
@ -671,7 +677,8 @@ export class Inbox extends Component<any, InboxState> {
|
|||
found.comment.read = combinedView.comment.read =
|
||||
data.comment_view.comment.read;
|
||||
}
|
||||
this.sendUnreadCount();
|
||||
|
||||
this.sendUnreadCount(data.comment_view.comment.read);
|
||||
this.setState(this.state);
|
||||
setupTippy();
|
||||
} else if (op == UserOperation.MarkPersonMentionAsRead) {
|
||||
|
@ -719,7 +726,7 @@ export class Inbox extends Component<any, InboxState> {
|
|||
data.person_mention_view.person_mention.read;
|
||||
}
|
||||
}
|
||||
this.sendUnreadCount();
|
||||
this.sendUnreadCount(data.person_mention_view.person_mention.read);
|
||||
this.setState(this.state);
|
||||
} else if (op == UserOperation.CreateComment) {
|
||||
let data = wsJsonToRes<CommentResponse>(msg).data;
|
||||
|
@ -736,6 +743,37 @@ export class Inbox extends Component<any, InboxState> {
|
|||
data.comment_view.creator.id ==
|
||||
UserService.Instance.myUserInfo.local_user_view.person.id
|
||||
) {
|
||||
// If youre in the unread view, just remove it from the list
|
||||
if (this.state.unreadOrAll == UnreadOrAll.Unread) {
|
||||
this.state.replies = this.state.replies.filter(
|
||||
r => r.comment.id !== data.comment_view.comment.parent_id
|
||||
);
|
||||
this.state.mentions = this.state.mentions.filter(
|
||||
m => m.comment.id !== data.comment_view.comment.parent_id
|
||||
);
|
||||
this.state.combined = this.state.combined.filter(r => {
|
||||
if (this.isMention(r.view))
|
||||
return r.view.comment.id !== data.comment_view.comment.parent_id;
|
||||
else return r.id !== data.comment_view.comment.parent_id;
|
||||
});
|
||||
} else {
|
||||
let mention_found = this.state.mentions.find(
|
||||
i => i.comment.id == data.comment_view.comment.parent_id
|
||||
);
|
||||
if (mention_found) {
|
||||
mention_found.person_mention.read = true;
|
||||
}
|
||||
let reply_found = this.state.replies.find(
|
||||
i => i.comment.id == data.comment_view.comment.parent_id
|
||||
);
|
||||
if (reply_found) {
|
||||
reply_found.comment.read = true;
|
||||
}
|
||||
this.state.combined = this.buildCombined();
|
||||
}
|
||||
this.sendUnreadCount(true);
|
||||
this.setState(this.state);
|
||||
setupTippy();
|
||||
// TODO this seems wrong, you should be using form_id
|
||||
toast(i18n.t("reply_sent"));
|
||||
}
|
||||
|
@ -776,22 +814,7 @@ export class Inbox extends Component<any, InboxState> {
|
|||
}
|
||||
}
|
||||
|
||||
sendUnreadCount() {
|
||||
UserService.Instance.unreadInboxCountSub.next(this.unreadCount());
|
||||
}
|
||||
|
||||
unreadCount(): number {
|
||||
return (
|
||||
this.state.replies.filter(r => !r.comment.read).length +
|
||||
this.state.mentions.filter(r => !r.person_mention.read).length +
|
||||
this.state.messages.filter(
|
||||
r =>
|
||||
UserService.Instance.myUserInfo &&
|
||||
!r.private_message.read &&
|
||||
// TODO also seems very strange and wrong
|
||||
r.creator.id !==
|
||||
UserService.Instance.myUserInfo.local_user_view.person.id
|
||||
).length
|
||||
);
|
||||
isMention(view: any): view is PersonMentionView {
|
||||
return (view as PersonMentionView).person_mention !== undefined;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -396,6 +396,16 @@ export class Profile extends Component<any, ProfileState> {
|
|||
{i18n.t("banned")}
|
||||
</li>
|
||||
)}
|
||||
{pv.person.admin && (
|
||||
<li className="list-inline-item badge badge-light">
|
||||
{i18n.t("admin")}
|
||||
</li>
|
||||
)}
|
||||
{pv.person.bot_account && (
|
||||
<li className="list-inline-item badge badge-light">
|
||||
{i18n.t("bot_account").toLowerCase()}
|
||||
</li>
|
||||
)}
|
||||
</ul>
|
||||
</div>
|
||||
<div className="flex-grow-1 unselectable pointer mx-2"></div>
|
||||
|
|
|
@ -288,6 +288,11 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
|
|||
{this.isAdmin && (
|
||||
<span className="mx-1 badge badge-light">{i18n.t("admin")}</span>
|
||||
)}
|
||||
{post_view.creator.bot_account && (
|
||||
<span className="mx-1 badge badge-light">
|
||||
{i18n.t("bot_account").toLowerCase()}
|
||||
</span>
|
||||
)}
|
||||
{(post_view.creator_banned_from_community ||
|
||||
post_view.creator.banned) && (
|
||||
<span className="mx-1 badge badge-danger">{i18n.t("banned")}</span>
|
||||
|
|
|
@ -13,18 +13,35 @@ interface PostListingsProps {
|
|||
enableNsfw: boolean;
|
||||
}
|
||||
|
||||
export class PostListings extends Component<PostListingsProps, any> {
|
||||
private duplicatesMap = new Map<number, PostView[]>();
|
||||
interface PostListingsState {
|
||||
posts: PostView[];
|
||||
}
|
||||
|
||||
export class PostListings extends Component<
|
||||
PostListingsProps,
|
||||
PostListingsState
|
||||
> {
|
||||
duplicatesMap = new Map<number, PostView[]>();
|
||||
|
||||
private emptyState: PostListingsState = {
|
||||
posts: [],
|
||||
};
|
||||
|
||||
constructor(props: any, context: any) {
|
||||
super(props, context);
|
||||
this.state = this.emptyState;
|
||||
if (this.props.removeDuplicates) {
|
||||
this.state.posts = this.removeDuplicates();
|
||||
} else {
|
||||
this.state.posts = this.props.posts;
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
{this.props.posts.length > 0 ? (
|
||||
this.outer().map(post_view => (
|
||||
{this.state.posts.length > 0 ? (
|
||||
this.state.posts.map(post_view => (
|
||||
<>
|
||||
<PostListing
|
||||
post_view={post_view}
|
||||
|
@ -50,16 +67,10 @@ export class PostListings extends Component<PostListingsProps, any> {
|
|||
);
|
||||
}
|
||||
|
||||
outer(): PostView[] {
|
||||
let out = this.props.posts;
|
||||
if (this.props.removeDuplicates) {
|
||||
out = this.removeDuplicates(out);
|
||||
}
|
||||
removeDuplicates(): PostView[] {
|
||||
// Must use a spread to clone the props, because splice will fail below otherwise.
|
||||
let posts = [...this.props.posts];
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
removeDuplicates(posts: PostView[]): PostView[] {
|
||||
// A map from post url to list of posts (dupes)
|
||||
let urlMap = new Map<string, PostView[]>();
|
||||
|
||||
|
|
|
@ -103,6 +103,7 @@ function format(value: any, format: any): any {
|
|||
|
||||
i18next.init({
|
||||
debug: false,
|
||||
compatibilityJSON: "v3",
|
||||
// load: 'languageOnly',
|
||||
|
||||
// initImmediate: false,
|
||||
|
|
Loading…
Reference in a new issue