Browse Source

convert all postlistings to immutable lists, convert community page to http

unoptim
DashEightMate 1 year ago
parent
commit
34ea362f46
  1. 1
      package.json
  2. 40
      src/components/FeaturedPosts.tsx
  3. 103
      src/components/community.tsx
  4. 120
      src/components/main.tsx
  5. 21
      src/components/post-form.tsx
  6. 15
      src/components/post-listings.tsx
  7. 32
      src/components/post.tsx
  8. 50
      src/utils.ts
  9. 5
      yarn.lock

1
package.json

@ -39,6 +39,7 @@
"emoji-short-name": "^1.0.0",
"i18next": "^19.6.3",
"immutability-helper": "^3.1.1",
"immutable": "^4.0.0-rc.12",
"js-cookie": "^2.2.1",
"jwt-decode": "^2.2.0",
"line-height": "^0.3.1",

40
src/components/FeaturedPosts.tsx

@ -1,4 +1,4 @@
import React from 'react';
import React, { useEffect } from 'react';
import {
Disclosure,
DisclosureButton,
@ -11,9 +11,10 @@ import useSWR from 'swr';
import { Box } from 'theme-ui';
import { GetPostsResponse, SortType } from '../interfaces';
import { UserService } from '../services';
import { toQueryString, fetcher } from '../utils';
import { toQueryString, fetcher, getSortTypeFromProps } from '../utils';
import { PostListings } from './post-listings';
import useLocalStorage from '../hooks/useLocalStorage';
import { List } from 'immutable';
interface FeaturedPostStore {
open: boolean;
@ -57,7 +58,7 @@ const FeaturedDisclosure = (props: DisclosureProps) => {
);
};
const FeaturedPosts = (): JSX.Element => {
function FeaturedPosts(props) {
const [store, setStore] = useLocalStorage('fp_store', {
open: true,
changed: false,
@ -68,33 +69,18 @@ const FeaturedPosts = (): JSX.Element => {
setStore({ ...store, changed: false, open: !store.open });
};
const handlePostsChange = (postIds: number[]): void => {
if (postIds.some(id => !store.postIds.includes(id))) {
setStore({ ...store, changed: true, postIds });
useEffect(() => {
if (props.posts){
const postIds: List<number> = props.posts.map(p => p.id);
if (postIds.some(id => !store.postIds.includes(id))) {
setStore({ ...store, changed: true, postIds: postIds.toArray() });
}
}
};
let featuredParams = '';
if (UserService.Instance.auth) {
featuredParams = toQueryString({
auth: UserService.Instance.auth,
});
}
const { data } = useSWR<GetPostsResponse>(
`post/featured?${featuredParams}`,
fetcher,
{
revalidateOnFocus: false,
onSuccess: data => {
handlePostsChange(data.posts.flatMap(p => p.id));
},
}
);
});
return (
<>
{data?.posts?.length >= 1 && (
{props.posts && props.posts.size >= 1 && (
<Box
sx={{
width: 'calc(100% + 15px)',
@ -115,7 +101,7 @@ const FeaturedPosts = (): JSX.Element => {
<DisclosurePanel>
<PostListings
showCommunity
posts={[data?.posts?.[0], data?.posts?.[1]].filter(Boolean)} // filter out any undefined responses
posts={List([props.posts.get(0), props.posts.get(1)]).filter(Boolean)} // filter out any undefined responses
sort={SortType.New}
enableDownvotes
enableNsfw

103
src/components/community.tsx

@ -27,7 +27,7 @@ import {
Site,
FollowCommunityForm,
} from '../interfaces';
import { WebSocketService } from '../services';
import { UserService, WebSocketService } from '../services';
import { PostListings } from './post-listings';
import { CommentNodes } from './comment-nodes';
import { SortSelect } from './sort-select';
@ -50,6 +50,8 @@ import {
isCommentChanged,
isPostChanged,
siteName,
api,
savePostFindRes,
} from '../utils';
import { i18n } from '../i18next';
import { Icon } from './icon';
@ -61,6 +63,9 @@ import Block, { Flex } from './elements/Block';
import Header, { Separator } from './Header';
import StyledLink from '../StyledLink';
import Tooltip from './Tooltip';
import { List } from 'immutable';
import update from 'immutability-helper';
import { Box } from 'theme-ui';
interface State {
community: CommunityI;
@ -71,7 +76,7 @@ interface State {
sitemods: Array<UserView>;
online: number;
loading: boolean;
posts: Array<Post>;
posts: List<Post>;
comments: Array<Comment>;
dataType: DataType;
sort: SortType;
@ -122,7 +127,7 @@ export class BaseCommunity extends Component<any, State> {
communityName: this.props.match.params.name,
online: null,
loading: true,
posts: [],
posts: List(),
comments: [],
dataType: getDataTypeFromProps(this.props),
sort: getSortTypeFromProps(this.props),
@ -150,7 +155,9 @@ export class BaseCommunity extends Component<any, State> {
this.state = this.emptyState;
this.handleSortChange = this.handleSortChange.bind(this);
this.handleDataTypeChange = this.handleDataTypeChange.bind(this);
}
componentDidMount(){
this.subscription = WebSocketService.Instance.subject
.pipe(retryWhen(errors => errors.pipe(delay(3000), take(10))))
.subscribe(
@ -184,7 +191,6 @@ export class BaseCommunity extends Component<any, State> {
lastState.sort !== this.state.sort ||
lastState.page !== this.state.page
) {
this.setState({ loading: true });
this.fetchData();
}
@ -308,13 +314,27 @@ export class BaseCommunity extends Component<any, State> {
listings() {
return this.state.dataType == DataType.Post ? (
<PostListings
posts={this.state.posts}
removeDuplicates
sort={this.state.sort}
enableDownvotes
enableNsfw
/>
<>
<PostListings
// filter out sticky posts from main and announcements otherwise they show up twice
posts={this.state.posts}
sort={this.state.sort}
enableDownvotes
enableNsfw
/>
<Box my={4}>
{this.state.page > 1 && (
<Button mr={1} variant="muted" onClick={this.prevPage}>
{i18n.t('prev')}
</Button>
)}
{this.state.posts.size > 0 && (
<Button variant="muted" onClick={this.nextPage}>
{i18n.t('next')}
</Button>
)}
</Box>
</>
) : (
<CommentNodes
nodes={commentsToFlatNodes(this.state.comments)}
@ -363,7 +383,7 @@ export class BaseCommunity extends Component<any, State> {
{i18n.t('prev')}
</Button>
)}
{this.state.posts.length > 0 && (
{this.state.posts.size > 0 && (
<Button
className="btn btn-sm btn-secondary"
onClick={linkEvent(this, this.nextPage)}
@ -422,16 +442,37 @@ export class BaseCommunity extends Component<any, State> {
);
}
fetchData() {
async fetchData() {
if (this.state.dataType == DataType.Post) {
let getPostsForm: GetPostsForm = {
this.setState({
loading: true,
})
const params = new URLSearchParams({
page: this.state.page,
limit: fetchLimit,
sort: SortType[this.state.sort],
type_: ListingType[ListingType.Community],
community_id: this.state.community.id,
};
WebSocketService.Instance.getPosts(getPostsForm);
type_: ListingType[2],
community_id: this.state.community.id
} as any);
if (UserService.Instance.auth) {
params.append('auth', UserService.Instance.auth);
}
api.get(`post/list?${params.toString()}`)
.then(res => res.data)
.then(
(result) => {
this.setState({
posts: List(result.posts),
loading: false,
})
}
);
//WebSocketService.Instance.communityJoinRoom(this.state.community.id);
setupTippy();
} else {
let getCommentsForm: GetCommentsForm = {
page: this.state.page,
@ -445,7 +486,6 @@ export class BaseCommunity extends Component<any, State> {
}
parseMessage(msg: WebSocketJsonResponse) {
console.log(msg);
let res = wsJsonToRes(msg);
if (msg.error) {
toast(i18n.t(msg.error), 'danger');
@ -483,7 +523,7 @@ export class BaseCommunity extends Component<any, State> {
let data = res.data as GetPostsResponse;
this.setState(
{
posts: data.posts,
posts: List(data.posts),
loading: false,
},
() => {
@ -492,16 +532,23 @@ export class BaseCommunity extends Component<any, State> {
);
} else if (isPostChanged(res.op)) {
let data = res.data as PostResponse;
editPostFindRes(data, this.state.posts);
this.setState(this.state);
this.setState({
posts: editPostFindRes(data, this.state.posts),
});
} else if (res.op == UserOperation.CreatePost) {
let data = res.data as PostResponse;
this.state.posts.unshift(data.post);
this.setState(this.state);
} else if (res.op == UserOperation.CreatePostLike) {
let data = res.data as PostResponse;
createPostLikeFindRes(data, this.state.posts);
this.setState(this.state);
this.setState({
posts: createPostLikeFindRes(data, this.state.posts),
});
} else if (res.op == UserOperation.SavePost) {
let data = res.data as PostResponse;
this.setState({
posts: savePostFindRes(data, this.state.posts),
});
} else if (res.op == UserOperation.AddModToCommunity) {
let data = res.data as AddModToCommunityResponse;
this.setState({
@ -510,9 +557,11 @@ export class BaseCommunity extends Component<any, State> {
} else if (res.op == UserOperation.BanFromCommunity) {
let data = res.data as BanFromCommunityResponse;
this.state.posts
.filter(p => p.creator_id == data.user.id)
.forEach(p => (p.banned = data.banned));
this.setState({
posts: this.state.posts
.filter(p => p.creator_id == data.user.id)
.map(p => update(p, {banned_from_community: {$set: data.banned}})),
});
} else if (res.op == UserOperation.GetComments) {
let data = res.data as GetCommentsResponse;
this.setState({

120
src/components/main.tsx

@ -59,6 +59,7 @@ import {
getMoscowTime,
siteName,
api,
savePostFindRes,
} from '../utils';
import { BASE_PATH } from '../isProduction';
import { i18n } from '../i18next';
@ -78,6 +79,7 @@ import Header, { Separator } from './Header';
import { siteSubject } from '../services/SiteService';
import FeaturedPosts from './FeaturedPosts';
import { AxiosError } from 'axios';
import { List } from 'immutable';
interface MainState {
subscribedCommunities: Array<CommunityUser>;
@ -85,7 +87,8 @@ interface MainState {
siteRes: GetSiteResponse;
showEditSite: boolean;
loading: boolean;
posts: Array<Post>;
posts: List<Post>;
featuredPosts: List<Post>;
comments: Array<Comment>;
listingType: ListingType;
dataType: DataType;
@ -153,7 +156,8 @@ class Main extends Component<MainProps & RouteComponentProps, MainState> {
},
showEditSite: false,
loading: true,
posts: [],
posts: List([]),
featuredPosts: List([]),
comments: [],
listingType: getListingTypeFromProps(this.props) || ListingType.Subscribed,
dataType: getDataTypeFromProps(this.props) || DataType.Post,
@ -542,7 +546,7 @@ class Main extends Component<MainProps & RouteComponentProps, MainState> {
listings() {
return this.state.dataType == DataType.Post ? (
<>
<FeaturedPosts />
<FeaturedPosts posts={this.state.featuredPosts} />
<PostListings
// filter out sticky posts from main and announcements otherwise they show up twice
@ -557,7 +561,7 @@ class Main extends Component<MainProps & RouteComponentProps, MainState> {
{i18n.t('prev')}
</Button>
)}
{this.state.posts.length > 0 && (
{this.state.posts.size > 0 && (
<Button variant="muted" onClick={this.nextPage}>
{i18n.t('next')}
</Button>
@ -670,7 +674,7 @@ class Main extends Component<MainProps & RouteComponentProps, MainState> {
{i18n.t('prev')}
</Button>
)}
{this.state.posts.length > 0 && (
{this.state.posts.size > 0 && (
<Button variant="muted" onClick={this.nextPage}>
{i18n.t('next')}
</Button>
@ -737,7 +741,7 @@ class Main extends Component<MainProps & RouteComponentProps, MainState> {
loading: true,
})
const params = new URLSearchParams({
let params = new URLSearchParams({
page: this.state.page,
limit: fetchLimit,
sort: SortType[this.state.sort],
@ -753,7 +757,24 @@ class Main extends Component<MainProps & RouteComponentProps, MainState> {
.then(
(result) => {
this.setState({
posts: result.posts,
posts: List(result.posts),
})
}
);
params = new URLSearchParams({});
if (UserService.Instance.auth) {
params.append('auth', UserService.Instance.auth);
}
api.get(`post/featured?${params.toString()}`)
.then(res => res.data)
.then(
(result) => {
console.log(result.posts);
this.setState({
featuredPosts: List(result.posts),
loading: false,
})
}
@ -838,12 +859,21 @@ class Main extends Component<MainProps & RouteComponentProps, MainState> {
this.setState(this.state);
} else if (isPostChanged(res.op)) {
let data = res.data as PostResponse;
editPostFindRes(data, this.state.posts);
this.setState(this.state);
this.setState({
posts: editPostFindRes(data, this.state.posts),
featuredPosts: editPostFindRes(data, this.state.featuredPosts),
});
} else if (res.op === UserOperation.CreatePostLike) {
let data = res.data as PostResponse;
this.setState({
posts: createPostLikeFindRes(data, this.state.posts),
featuredPosts: createPostLikeFindRes(data, this.state.featuredPosts),
});
} else if (res.op == UserOperation.SavePost) {
let data = res.data as PostResponse;
this.setState({
posts: savePostFindRes(data, this.state.posts),
featuredPosts: savePostFindRes(data, this.state.featuredPosts),
});
} else if (res.op === UserOperation.AddAdmin) {
let data = res.data as AddAdminResponse;
@ -920,77 +950,5 @@ class Main extends Component<MainProps & RouteComponentProps, MainState> {
}
}
interface DataWrapperProps extends Omit<PostListingsProps, 'posts'> {
page: number;
sort: SortType;
listingType: ListingType | string;
nextPage: () => void;
prevPage: () => void;
removeDuplicates?: boolean;
}
function DataWrapper({
page,
sort,
listingType,
nextPage,
prevPage,
...props
}: DataWrapperProps) {
const params = new URLSearchParams({
page: page,
limit: fetchLimit,
sort: SortType[sort],
type_: listingType,
} as any);
if (UserService.Instance.auth) {
params.append('auth', UserService.Instance.auth);
}
const { data } = useSWR(`post/list?${params.toString()}`, fetcher, {
revalidateOnFocus: false,
dedupingInterval: 10 * 1000, // 10 sec
});
if (!data) {
return <SpinnerSection />;
}
const posts: Post[] = data.posts;
return (
<>
<FeaturedPosts />
<PostListings
// filter out sticky posts from main and announcements otherwise they show up twice
posts={posts.filter(post => {
if (post.featured) {
return !post.stickied;
}
// return all other posts and sticky posts
return true;
})}
sort={sort}
{...props}
/>
<Box my={4}>
{page > 1 && (
<Button mr={1} variant="muted" onClick={prevPage}>
{i18n.t('prev')}
</Button>
)}
{data?.posts.length > 0 && (
<Button variant="muted" onClick={nextPage}>
{i18n.t('next')}
</Button>
)}
</Box>
</>
);
}
// @ts-ignore
export default withTranslation()(withRouter(Main));

21
src/components/post-form.tsx

@ -56,6 +56,7 @@ import { Alert, Button, Input, Textarea } from 'theme-ui';
import { AxiosError } from 'axios';
import { isProduction } from '../isProduction';
import { PictrsImage } from './PictrsImage';
import { List } from 'immutable';
export const MAX_POST_TITLE_LENGTH = 160;
export const MAX_POST_BODY_LENGTH = 20000;
@ -161,8 +162,8 @@ interface PostFormState {
previewMode: boolean;
editMode: boolean;
suggestedTitle: string;
suggestedPosts: Array<Post>;
crossPosts: Array<Post>;
suggestedPosts: List<Post>;
crossPosts: List<Post>;
crosspostCommunityId?: number;
}
@ -213,8 +214,8 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
previewMode: false,
editMode: false,
suggestedTitle: undefined,
suggestedPosts: [],
crossPosts: [],
suggestedPosts: List([]),
crossPosts: List([]),
};
state = this.emptyState;
@ -418,7 +419,7 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
title="post form thumbnail"
/>
)}
{this.state.crossPosts.length > 0 && (
{this.state.crossPosts.size > 0 && (
<>
<div className="my-1 text-muted small font-weight-bold">
{i18n.t('cross_posts')}
@ -454,7 +455,7 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
</div>
)}
</>
{this.state.suggestedPosts.length > 0 && (
{this.state.suggestedPosts.size > 0 && (
<>
<div className="my-1 text-muted small font-weight-bold">
{i18n.t('related_posts')}
@ -616,7 +617,7 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
this.setState({ suggestedTitle: title });
}
} else {
this.setState({ suggestedTitle: undefined, crossPosts: [] });
this.setState({ suggestedTitle: undefined, crossPosts: List() });
}
}
@ -641,7 +642,7 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
if (this.state.postForm.name !== '') {
WebSocketService.Instance.search(form);
} else {
this.setState({ suggestedPosts: [] });
this.setState({ suggestedPosts: List() });
}
}
@ -799,9 +800,9 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
let data = res.data as SearchResponse;
if (data.type_ == SearchType[SearchType.Posts]) {
this.setState({ suggestedPosts: data.posts });
this.setState({ suggestedPosts: List(data.posts) });
} else if (data.type_ == SearchType[SearchType.Url]) {
this.setState({ crossPosts: data.posts });
this.setState({ crossPosts: List(data.posts) });
}
}
}

15
src/components/post-listings.tsx

@ -5,9 +5,10 @@ import { postSort } from '../utils';
import { PostListing } from './post-listing';
import { i18n } from '../i18next';
import { Trans } from 'react-i18next';
import { List } from 'immutable';
export interface PostListingsProps {
posts: Array<Post>;
posts: List<Post>;
showCommunity?: boolean;
removeDuplicates?: boolean;
sort?: SortType;
@ -44,7 +45,7 @@ export class PostListings extends PureComponent<
// }
render() {
return this.props.posts.length > 0 ? (
return this.props.posts.size > 0 ? (
<div>
{this.outer().map(post => (
<PostListing
@ -69,20 +70,20 @@ export class PostListings extends PureComponent<
);
}
outer(): Array<Post> {
outer(): List<Post> {
let out = this.props.posts;
if (this.props.removeDuplicates) {
out = this.removeDuplicates(out);
}
if (this.props.sort !== undefined) {
//postSort(out, this.props.sort, this.props.showCommunity == undefined);
postSort(out, this.props.sort, this.props.showCommunity == undefined);
}
return out;
}
removeDuplicates(posts: Array<Post>): Array<Post> {
removeDuplicates(posts: List<Post>): List<Post> {
// A map from post url to list of posts (dupes)
let urlMap = new Map<string, Array<Post>>();
@ -113,8 +114,8 @@ export class PostListings extends PureComponent<
}
}
for (let i = 0; i < posts.length; i++) {
let post = posts[i];
for (let i = 0; i < posts.size; i++) {
let post = posts.get(i);
if (post.url) {
let found = urlMap.get(post.url);
if (found) {

32
src/components/post.tsx

@ -61,6 +61,7 @@ import Tooltip from './Tooltip';
import StyledLink from '../StyledLink';
import { siteSubject } from '../services/SiteService';
import { AxiosError } from 'axios';
import update from 'immutability-helper';
interface PostState {
post: PostI;
@ -565,7 +566,6 @@ export class Post extends Component<any, PostState> {
}
parseMessage(msg: WebSocketJsonResponse) {
console.log(msg);
let res = wsJsonToRes(msg);
if (msg.error) {
toast(i18n.t(msg.error), 'danger');
@ -602,24 +602,30 @@ export class Post extends Component<any, PostState> {
this.setState(this.state);
} else if (res.op == UserOperation.CreatePostLike) {
let data = res.data as PostResponse;
createPostLikeRes(data, this.state.post);
this.setState(this.state);
this.setState({
post: createPostLikeRes(data, this.state.post),
});
} else if (isPostChanged(res.op)) {
let data = res.data as PostResponse;
this.state.post = data.post;
this.setState(this.state);
this.setState({
post: data.post,
});
setupTippy();
} else if (res.op == UserOperation.SavePost) {
let data = res.data as PostResponse;
this.state.post = data.post;
this.setState(this.state);
this.setState({
post: data.post,
});
setupTippy();
} else if (res.op == UserOperation.EditCommunity) {
let data = res.data as CommunityResponse;
this.state.community = data.community;
this.state.post.community_id = data.community.id;
this.state.post.community_name = data.community.name;
this.setState(this.state);
this.setState({
community: data.community,
post: update(this.state.post, {
community_id: {$set: data.community.id},
community_name: {$set: data.community.name},
}),
});
} else if (res.op == UserOperation.FollowCommunity) {
let data = res.data as CommunityResponse;
this.state.community.subscribed = data.community.subscribed;
@ -632,7 +638,7 @@ export class Post extends Component<any, PostState> {
.filter(c => c.creator_id == data.user.id)
.forEach(c => (c.banned_from_community = data.banned));
if (this.state.post.creator_id == data.user.id) {
this.state.post.banned_from_community = data.banned;
this.state.post = update(this.state.post, {banned_from_community: {$set: data.banned}});
}
this.setState(this.state);
} else if (res.op == UserOperation.AddModToCommunity) {
@ -645,7 +651,7 @@ export class Post extends Component<any, PostState> {
.filter(c => c.creator_id == data.user.id)
.forEach(c => (c.banned = data.banned));
if (this.state.post.creator_id == data.user.id) {
this.state.post.banned = data.banned;
this.state.post = update(this.state.post, {banned: {$set: data.banned}});
}
this.setState(this.state);
} else if (res.op == UserOperation.AddAdmin) {

50
src/utils.ts

@ -71,6 +71,7 @@ import axios from 'axios';
// import normalizeUrl from './normalize-url';
import update from 'immutability-helper';
import { List } from 'immutable';
export const repoUrl = 'https://git.chapo.chat/chapo-collective/lemmy-hexbear';
export const helpGuideUrl = '/docs/about_guide.html';
@ -841,46 +842,53 @@ export function createCommentLikeRes(
export function createPostLikeFindRes(
data: PostResponse,
posts: Array<Post>
): Array<Post> {
posts: List<Post>
): List<Post> {
let found = posts.findIndex(c => c.id == data.post.id);
if (found !== -1) {
posts = update(posts, {[found]: {$set: createPostLikeRes(data, posts[found])}});
posts = posts.set(found, createPostLikeRes(data, posts.get(found)));
}
return posts;
}
export function createPostLikeRes(data: PostResponse, post: Post): Post {
//immutability-helper is used so that post listings can be pure with nested props
post = update(post, {
return update(post, {
score: {$set: data.post.score},
upvotes: {$set: data.post.upvotes},
downvotes: {$set: data.post.downvotes},
saved: {$set: data.post.saved},
my_vote: {$set: data.post.my_vote}
});
return post;
}
export function editPostFindRes(data: PostResponse, posts: Array<Post>): void {
let found = posts.find(c => c.id == data.post.id);
if (found) {
editPostRes(data, found);
export function editPostFindRes(data: PostResponse, posts: List<Post>): List<Post> {
let found = posts.findIndex(c => c.id == data.post.id);
if (found !== -1) {
posts = posts.set(found, editPostRes(data, posts.get(found)));
}
return posts;
}
export function editPostRes(data: PostResponse, post: Post): Post {
return update(post, {
url: {$set: data.post.url},
name: {$set: data.post.name},
nsfw: {$set: data.post.nsfw},
deleted: {$set: data.post.deleted},
removed: {$set: data.post.removed},
stickied: {$set: data.post.stickied},
body: {$set: data.post.body},
locked: {$set: data.post.locked},
});
}
export function editPostRes(data: PostResponse, post: Post): void {
if (post) {
post.url = data.post.url;
post.name = data.post.name;
post.nsfw = data.post.nsfw;
post.deleted = data.post.deleted;
post.removed = data.post.removed;
post.stickied = data.post.stickied;
post.body = data.post.body;
post.locked = data.post.locked;
export function savePostFindRes(data: PostResponse, posts: List<Post>): List<Post>{
let found = posts.findIndex(c => c.id == data.post.id);
if (found !== -1) {
posts = posts.set(found, update(posts.get(found), {saved: {$set: data.post.saved}}));
}
return posts;
}
export function commentsToFlatNodes(
@ -969,7 +977,7 @@ function convertCommentSortType(sort: SortType): CommentSortType {
}
export function postSort(
posts: Array<Post>,
posts: List<Post>,
sort: SortType,
communityType: boolean
): void {

5
yarn.lock

@ -8473,6 +8473,11 @@ [email protected]^3.1.1:
resolved "https://registry.yarnpkg.com/immutability-helper/-/immutability-helper-3.1.1.tgz#2b86b2286ed3b1241c9e23b7b21e0444f52f77b7"
integrity sha512-Q0QaXjPjwIju/28TsugCHNEASwoCcJSyJV3uO1sOIQGI0jKgm9f41Lvz0DZj3n46cNCyAZTsEYoY4C2bVRUzyQ==
[email protected]^4.0.0-rc.12:
version "4.0.0-rc.12"
resolved "https://registry.yarnpkg.com/immutable/-/immutable-4.0.0-rc.12.tgz#ca59a7e4c19ae8d9bf74a97bdf0f6e2f2a5d0217"
integrity sha512-0M2XxkZLx/mi3t8NVwIm1g8nHoEmM9p9UBl/G9k4+hm0kBgOVdMV/B3CY5dQ8qG8qc80NN4gDV4HQv6FTJ5q7A==
[email protected]^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/import-cwd/-/import-cwd-2.1.0.tgz#aa6cf36e722761285cb371ec6519f53e2435b0a9"

Loading…
Cancel
Save