mirror of
https://github.com/LemmyNet/lemmy-ui.git
synced 2024-11-21 22:27:11 +00:00
First pass at v2_api
This commit is contained in:
parent
6ffe0c530d
commit
ea317af269
|
@ -67,7 +67,7 @@
|
|||
"eslint": "^7.15.0",
|
||||
"eslint-plugin-jane": "^9.0.4",
|
||||
"husky": "^4.3.5",
|
||||
"lemmy-js-client": "^1.0.16",
|
||||
"lemmy-js-client": "1.0.17-beta5",
|
||||
"lint-staged": "^10.5.3",
|
||||
"mini-css-extract-plugin": "^1.3.2",
|
||||
"node-fetch": "^2.6.1",
|
||||
|
|
|
@ -3,12 +3,12 @@ import { BrowserRouter } from 'inferno-router';
|
|||
import { initializeSite } from '../shared/initialize';
|
||||
import { App } from '../shared/components/app';
|
||||
|
||||
const site = window.isoData.site;
|
||||
const site = window.isoData.site_res;
|
||||
initializeSite(site);
|
||||
|
||||
const wrapper = (
|
||||
<BrowserRouter>
|
||||
<App site={window.isoData.site} />
|
||||
<App siteRes={window.isoData.site_res} />
|
||||
</BrowserRouter>
|
||||
);
|
||||
|
||||
|
|
|
@ -8,8 +8,7 @@ import { App } from '../shared/components/app';
|
|||
import { InitialFetchRequest, IsoData } from '../shared/interfaces';
|
||||
import { routes } from '../shared/routes';
|
||||
import IsomorphicCookie from 'isomorphic-cookie';
|
||||
import { setAuth } from '../shared/utils';
|
||||
import { GetSiteForm, LemmyHttp } from 'lemmy-js-client';
|
||||
import { GetSite, LemmyHttp } from 'lemmy-js-client';
|
||||
import process from 'process';
|
||||
import { Helmet } from 'inferno-helmet';
|
||||
import { initializeSite } from '../shared/initialize';
|
||||
|
@ -30,8 +29,7 @@ server.get('/*', async (req, res) => {
|
|||
const context = {} as any;
|
||||
let auth: string = IsomorphicCookie.load('jwt', req);
|
||||
|
||||
let getSiteForm: GetSiteForm = {};
|
||||
setAuth(getSiteForm, auth);
|
||||
let getSiteForm: GetSite = { auth };
|
||||
|
||||
let promises: Promise<any>[] = [];
|
||||
|
||||
|
@ -70,14 +68,14 @@ server.get('/*', async (req, res) => {
|
|||
|
||||
let isoData: IsoData = {
|
||||
path: req.path,
|
||||
site,
|
||||
site_res: site,
|
||||
routeData,
|
||||
lang,
|
||||
};
|
||||
|
||||
const wrapper = (
|
||||
<StaticRouter location={req.url} context={isoData}>
|
||||
<App site={isoData.site} />
|
||||
<App siteRes={isoData.site_res} />
|
||||
</StaticRouter>
|
||||
);
|
||||
if (context.url) {
|
||||
|
|
|
@ -4,12 +4,11 @@ import {
|
|||
UserOperation,
|
||||
SiteResponse,
|
||||
GetSiteResponse,
|
||||
SiteConfigForm,
|
||||
SaveSiteConfig,
|
||||
GetSiteConfigResponse,
|
||||
WebSocketJsonResponse,
|
||||
GetSiteConfig,
|
||||
} from 'lemmy-js-client';
|
||||
import { WebSocketService } from '../services';
|
||||
import { UserService, WebSocketService } from '../services';
|
||||
import {
|
||||
wsJsonToRes,
|
||||
capitalizeFirstLetter,
|
||||
|
@ -18,7 +17,7 @@ import {
|
|||
setIsoData,
|
||||
wsSubscribe,
|
||||
isBrowser,
|
||||
setAuth,
|
||||
wsUserOp,
|
||||
} from '../utils';
|
||||
import autosize from 'autosize';
|
||||
import { SiteForm } from './site-form';
|
||||
|
@ -30,7 +29,7 @@ import { InitialFetchRequest } from 'shared/interfaces';
|
|||
interface AdminSettingsState {
|
||||
siteRes: GetSiteResponse;
|
||||
siteConfigRes: GetSiteConfigResponse;
|
||||
siteConfigForm: SiteConfigForm;
|
||||
siteConfigForm: SaveSiteConfig;
|
||||
loading: boolean;
|
||||
siteConfigLoading: boolean;
|
||||
}
|
||||
|
@ -40,10 +39,10 @@ export class AdminSettings extends Component<any, AdminSettingsState> {
|
|||
private isoData = setIsoData(this.context);
|
||||
private subscription: Subscription;
|
||||
private emptyState: AdminSettingsState = {
|
||||
siteRes: this.isoData.site,
|
||||
siteRes: this.isoData.site_res,
|
||||
siteConfigForm: {
|
||||
config_hjson: null,
|
||||
auth: null,
|
||||
auth: UserService.Instance.authField(),
|
||||
},
|
||||
siteConfigRes: {
|
||||
config_hjson: null,
|
||||
|
@ -67,13 +66,14 @@ export class AdminSettings extends Component<any, AdminSettingsState> {
|
|||
this.state.siteConfigLoading = false;
|
||||
this.state.loading = false;
|
||||
} else {
|
||||
WebSocketService.Instance.getSiteConfig();
|
||||
WebSocketService.Instance.client.getSiteConfig({
|
||||
auth: UserService.Instance.authField(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
static fetchInitialData(req: InitialFetchRequest): Promise<any>[] {
|
||||
let form: GetSiteConfig = {};
|
||||
setAuth(form, req.auth);
|
||||
let form: GetSiteConfig = { auth: req.auth };
|
||||
return [req.client.getSiteConfig(form)];
|
||||
}
|
||||
|
||||
|
@ -91,7 +91,9 @@ export class AdminSettings extends Component<any, AdminSettingsState> {
|
|||
}
|
||||
|
||||
get documentTitle(): string {
|
||||
return `${i18n.t('admin_settings')} - ${this.state.siteRes.site.name}`;
|
||||
return `${i18n.t('admin_settings')} - ${
|
||||
this.state.siteRes.site_view.site.name
|
||||
}`;
|
||||
}
|
||||
|
||||
render() {
|
||||
|
@ -110,8 +112,8 @@ export class AdminSettings extends Component<any, AdminSettingsState> {
|
|||
) : (
|
||||
<div class="row">
|
||||
<div class="col-12 col-md-6">
|
||||
{this.state.siteRes.site.id && (
|
||||
<SiteForm site={this.state.siteRes.site} />
|
||||
{this.state.siteRes.site_view.site.id && (
|
||||
<SiteForm site={this.state.siteRes.site_view.site} />
|
||||
)}
|
||||
{this.admins()}
|
||||
{this.bannedUsers()}
|
||||
|
@ -130,16 +132,7 @@ export class AdminSettings extends Component<any, AdminSettingsState> {
|
|||
<ul class="list-unstyled">
|
||||
{this.state.siteRes.admins.map(admin => (
|
||||
<li class="list-inline-item">
|
||||
<UserListing
|
||||
user={{
|
||||
name: admin.name,
|
||||
preferred_username: admin.preferred_username,
|
||||
avatar: admin.avatar,
|
||||
id: admin.id,
|
||||
local: admin.local,
|
||||
actor_id: admin.actor_id,
|
||||
}}
|
||||
/>
|
||||
<UserListing user={admin.user} />
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
|
@ -154,16 +147,7 @@ export class AdminSettings extends Component<any, AdminSettingsState> {
|
|||
<ul class="list-unstyled">
|
||||
{this.state.siteRes.banned.map(banned => (
|
||||
<li class="list-inline-item">
|
||||
<UserListing
|
||||
user={{
|
||||
name: banned.name,
|
||||
preferred_username: banned.preferred_username,
|
||||
avatar: banned.avatar,
|
||||
id: banned.id,
|
||||
local: banned.local,
|
||||
actor_id: banned.actor_id,
|
||||
}}
|
||||
/>
|
||||
<UserListing user={banned.user} />
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
|
@ -214,7 +198,7 @@ export class AdminSettings extends Component<any, AdminSettingsState> {
|
|||
handleSiteConfigSubmit(i: AdminSettings, event: any) {
|
||||
event.preventDefault();
|
||||
i.state.siteConfigLoading = true;
|
||||
WebSocketService.Instance.saveSiteConfig(i.state.siteConfigForm);
|
||||
WebSocketService.Instance.client.saveSiteConfig(i.state.siteConfigForm);
|
||||
i.setState(i.state);
|
||||
}
|
||||
|
||||
|
@ -223,9 +207,8 @@ export class AdminSettings extends Component<any, AdminSettingsState> {
|
|||
i.setState(i.state);
|
||||
}
|
||||
|
||||
parseMessage(msg: WebSocketJsonResponse) {
|
||||
console.log(msg);
|
||||
let res = wsJsonToRes(msg);
|
||||
parseMessage(msg: any) {
|
||||
let op = wsUserOp(msg);
|
||||
if (msg.error) {
|
||||
toast(i18n.t(msg.error), 'danger');
|
||||
this.context.router.history.push('/');
|
||||
|
@ -233,21 +216,21 @@ export class AdminSettings extends Component<any, AdminSettingsState> {
|
|||
this.setState(this.state);
|
||||
return;
|
||||
} else if (msg.reconnect) {
|
||||
} else if (res.op == UserOperation.EditSite) {
|
||||
let data = res.data as SiteResponse;
|
||||
this.state.siteRes.site = data.site;
|
||||
} else if (op == UserOperation.EditSite) {
|
||||
let data = wsJsonToRes<SiteResponse>(msg).data;
|
||||
this.state.siteRes.site_view = data.site_view;
|
||||
this.setState(this.state);
|
||||
toast(i18n.t('site_saved'));
|
||||
} else if (res.op == UserOperation.GetSiteConfig) {
|
||||
let data = res.data as GetSiteConfigResponse;
|
||||
} else if (op == UserOperation.GetSiteConfig) {
|
||||
let data = wsJsonToRes<GetSiteConfigResponse>(msg).data;
|
||||
this.state.siteConfigRes = data;
|
||||
this.state.loading = false;
|
||||
this.state.siteConfigForm.config_hjson = this.state.siteConfigRes.config_hjson;
|
||||
this.setState(this.state);
|
||||
var textarea: any = document.getElementById(this.siteConfigTextAreaId);
|
||||
autosize(textarea);
|
||||
} else if (res.op == UserOperation.SaveSiteConfig) {
|
||||
let data = res.data as GetSiteConfigResponse;
|
||||
} else if (op == UserOperation.SaveSiteConfig) {
|
||||
let data = wsJsonToRes<GetSiteConfigResponse>(msg).data;
|
||||
this.state.siteConfigRes = data;
|
||||
this.state.siteConfigForm.config_hjson = this.state.siteConfigRes.config_hjson;
|
||||
this.state.siteConfigLoading = false;
|
||||
|
|
|
@ -13,7 +13,7 @@ import { GetSiteResponse } from 'lemmy-js-client';
|
|||
import './styles.scss';
|
||||
|
||||
export interface AppProps {
|
||||
site: GetSiteResponse;
|
||||
siteRes: GetSiteResponse;
|
||||
}
|
||||
|
||||
export class App extends Component<AppProps, any> {
|
||||
|
@ -21,24 +21,25 @@ export class App extends Component<AppProps, any> {
|
|||
super(props, context);
|
||||
}
|
||||
render() {
|
||||
let siteRes = this.props.siteRes;
|
||||
return (
|
||||
<>
|
||||
<Provider i18next={i18n}>
|
||||
<div>
|
||||
<Theme user={this.props.site.my_user} />
|
||||
{this.props.site &&
|
||||
this.props.site.site &&
|
||||
this.props.site.site.icon && (
|
||||
<Theme user={siteRes.my_user} />
|
||||
{siteRes &&
|
||||
siteRes.site_view.site &&
|
||||
this.props.siteRes.site_view.site.icon && (
|
||||
<Helmet>
|
||||
<link
|
||||
id="favicon"
|
||||
rel="icon"
|
||||
type="image/x-icon"
|
||||
href={this.props.site.site.icon}
|
||||
href={this.props.siteRes.site_view.site.icon}
|
||||
/>
|
||||
</Helmet>
|
||||
)}
|
||||
<Navbar site={this.props.site} />
|
||||
<Navbar site_res={this.props.siteRes} />
|
||||
<div class="mt-4 p-0 fl-1">
|
||||
<Switch>
|
||||
{routes.map(({ path, exact, component: C, ...rest }) => (
|
||||
|
@ -53,7 +54,7 @@ export class App extends Component<AppProps, any> {
|
|||
</Switch>
|
||||
<Symbols />
|
||||
</div>
|
||||
<Footer site={this.props.site} />
|
||||
<Footer site={this.props.siteRes} />
|
||||
</div>
|
||||
</Provider>
|
||||
</>
|
||||
|
|
|
@ -2,13 +2,18 @@ import { Component } from 'inferno';
|
|||
import { Link } from 'inferno-router';
|
||||
import { Subscription } from 'rxjs';
|
||||
import {
|
||||
CommentNode as CommentNodeI,
|
||||
CommentForm as CommentFormI,
|
||||
WebSocketJsonResponse,
|
||||
CreateComment,
|
||||
EditComment,
|
||||
UserOperation,
|
||||
CommentResponse,
|
||||
} from 'lemmy-js-client';
|
||||
import { capitalizeFirstLetter, wsJsonToRes, wsSubscribe } from '../utils';
|
||||
import { CommentNode as CommentNodeI } from '../interfaces';
|
||||
import {
|
||||
capitalizeFirstLetter,
|
||||
wsJsonToRes,
|
||||
wsSubscribe,
|
||||
wsUserOp,
|
||||
} from '../utils';
|
||||
import { WebSocketService, UserService } from '../services';
|
||||
import { i18n } from '../i18next';
|
||||
import { T } from 'inferno-i18next';
|
||||
|
@ -24,30 +29,21 @@ interface CommentFormProps {
|
|||
}
|
||||
|
||||
interface CommentFormState {
|
||||
commentForm: CommentFormI;
|
||||
buttonTitle: string;
|
||||
finished: boolean;
|
||||
formId: string;
|
||||
}
|
||||
|
||||
export class CommentForm extends Component<CommentFormProps, CommentFormState> {
|
||||
private subscription: Subscription;
|
||||
private emptyState: CommentFormState = {
|
||||
commentForm: {
|
||||
auth: null,
|
||||
content: null,
|
||||
post_id: this.props.node
|
||||
? this.props.node.comment.post_id
|
||||
: this.props.postId,
|
||||
creator_id: UserService.Instance.user
|
||||
? UserService.Instance.user.id
|
||||
: null,
|
||||
},
|
||||
buttonTitle: !this.props.node
|
||||
? capitalizeFirstLetter(i18n.t('post'))
|
||||
: this.props.edit
|
||||
? capitalizeFirstLetter(i18n.t('save'))
|
||||
: capitalizeFirstLetter(i18n.t('reply')),
|
||||
finished: false,
|
||||
formId: null,
|
||||
};
|
||||
|
||||
constructor(props: any, context: any) {
|
||||
|
@ -58,18 +54,6 @@ export class CommentForm extends Component<CommentFormProps, CommentFormState> {
|
|||
|
||||
this.state = this.emptyState;
|
||||
|
||||
if (this.props.node) {
|
||||
if (this.props.edit) {
|
||||
this.state.commentForm.edit_id = this.props.node.comment.id;
|
||||
this.state.commentForm.parent_id = this.props.node.comment.parent_id;
|
||||
this.state.commentForm.content = this.props.node.comment.content;
|
||||
this.state.commentForm.creator_id = this.props.node.comment.creator_id;
|
||||
} else {
|
||||
// A reply gets a new parent id
|
||||
this.state.commentForm.parent_id = this.props.node.comment.id;
|
||||
}
|
||||
}
|
||||
|
||||
this.parseMessage = this.parseMessage.bind(this);
|
||||
this.subscription = wsSubscribe(this.parseMessage);
|
||||
}
|
||||
|
@ -83,7 +67,11 @@ export class CommentForm extends Component<CommentFormProps, CommentFormState> {
|
|||
<div class="mb-3">
|
||||
{UserService.Instance.user ? (
|
||||
<MarkdownTextArea
|
||||
initialContent={this.state.commentForm.content}
|
||||
initialContent={
|
||||
this.props.node
|
||||
? this.props.node.comment_view.comment.content
|
||||
: null
|
||||
}
|
||||
buttonTitle={this.state.buttonTitle}
|
||||
finished={this.state.finished}
|
||||
replyType={!!this.props.node}
|
||||
|
@ -110,12 +98,28 @@ export class CommentForm extends Component<CommentFormProps, CommentFormState> {
|
|||
}
|
||||
|
||||
handleCommentSubmit(msg: { val: string; formId: string }) {
|
||||
this.state.commentForm.content = msg.val;
|
||||
this.state.commentForm.form_id = msg.formId;
|
||||
let content = msg.val;
|
||||
this.state.formId = msg.formId;
|
||||
|
||||
let node = this.props.node;
|
||||
|
||||
if (this.props.edit) {
|
||||
WebSocketService.Instance.editComment(this.state.commentForm);
|
||||
let form: EditComment = {
|
||||
content,
|
||||
form_id: this.state.formId,
|
||||
edit_id: node.comment_view.comment.id,
|
||||
auth: UserService.Instance.authField(),
|
||||
};
|
||||
WebSocketService.Instance.client.editComment(form);
|
||||
} else {
|
||||
WebSocketService.Instance.createComment(this.state.commentForm);
|
||||
let form: CreateComment = {
|
||||
content,
|
||||
form_id: this.state.formId,
|
||||
post_id: node ? node.comment_view.post.id : this.props.postId,
|
||||
parent_id: node ? node.comment_view.comment.parent_id : null,
|
||||
auth: UserService.Instance.authField(),
|
||||
};
|
||||
WebSocketService.Instance.client.createComment(form);
|
||||
}
|
||||
this.setState(this.state);
|
||||
}
|
||||
|
@ -124,22 +128,22 @@ export class CommentForm extends Component<CommentFormProps, CommentFormState> {
|
|||
this.props.onReplyCancel();
|
||||
}
|
||||
|
||||
parseMessage(msg: WebSocketJsonResponse) {
|
||||
let res = wsJsonToRes(msg);
|
||||
parseMessage(msg: any) {
|
||||
let op = wsUserOp(msg);
|
||||
|
||||
// Only do the showing and hiding if logged in
|
||||
if (UserService.Instance.user) {
|
||||
if (
|
||||
res.op == UserOperation.CreateComment ||
|
||||
res.op == UserOperation.EditComment
|
||||
op == UserOperation.CreateComment ||
|
||||
op == UserOperation.EditComment
|
||||
) {
|
||||
let data = res.data as CommentResponse;
|
||||
let data = wsJsonToRes<CommentResponse>(msg).data;
|
||||
|
||||
// This only finishes this form, if the randomly generated form_id matches the one received
|
||||
if (this.state.commentForm.form_id == data.form_id) {
|
||||
if (this.state.formId == data.form_id) {
|
||||
this.setState({ finished: true });
|
||||
|
||||
// Necessary because it broke tribute for some reaso
|
||||
// Necessary because it broke tribute for some reason
|
||||
this.setState({ finished: false });
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,24 +1,29 @@
|
|||
import { Component, linkEvent } from 'inferno';
|
||||
import { Link } from 'inferno-router';
|
||||
import {
|
||||
CommentNode as CommentNodeI,
|
||||
CommentLikeForm,
|
||||
DeleteCommentForm,
|
||||
RemoveCommentForm,
|
||||
MarkCommentAsReadForm,
|
||||
MarkUserMentionAsReadForm,
|
||||
SaveCommentForm,
|
||||
BanFromCommunityForm,
|
||||
BanUserForm,
|
||||
CommunityUser,
|
||||
UserView,
|
||||
AddModToCommunityForm,
|
||||
AddAdminForm,
|
||||
TransferCommunityForm,
|
||||
TransferSiteForm,
|
||||
CreateCommentLike,
|
||||
DeleteComment,
|
||||
RemoveComment,
|
||||
MarkCommentAsRead,
|
||||
MarkUserMentionAsRead,
|
||||
SaveComment,
|
||||
BanFromCommunity,
|
||||
BanUser,
|
||||
CommunityModeratorView,
|
||||
UserViewSafe,
|
||||
AddModToCommunity,
|
||||
AddAdmin,
|
||||
TransferCommunity,
|
||||
TransferSite,
|
||||
SortType,
|
||||
CommentView,
|
||||
UserMentionView,
|
||||
} from 'lemmy-js-client';
|
||||
import { CommentSortType, BanType } from '../interfaces';
|
||||
import {
|
||||
CommentSortType,
|
||||
CommentNode as CommentNodeI,
|
||||
BanType,
|
||||
} from '../interfaces';
|
||||
import { WebSocketService, UserService } from '../services';
|
||||
import {
|
||||
mdToHtml,
|
||||
|
@ -70,8 +75,8 @@ interface CommentNodeProps {
|
|||
locked?: boolean;
|
||||
markable?: boolean;
|
||||
showContext?: boolean;
|
||||
moderators: CommunityUser[];
|
||||
admins: UserView[];
|
||||
moderators: CommunityModeratorView[];
|
||||
admins: UserViewSafe[];
|
||||
// TODO is this necessary, can't I get it from the node itself?
|
||||
postCreatorId?: number;
|
||||
showCommunity?: boolean;
|
||||
|
@ -98,12 +103,12 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
|
|||
showConfirmTransferCommunity: false,
|
||||
showConfirmAppointAsMod: false,
|
||||
showConfirmAppointAsAdmin: false,
|
||||
my_vote: this.props.node.comment.my_vote,
|
||||
score: this.props.node.comment.score,
|
||||
upvotes: this.props.node.comment.upvotes,
|
||||
downvotes: this.props.node.comment.downvotes,
|
||||
borderColor: this.props.node.comment.depth
|
||||
? colorList[this.props.node.comment.depth % colorList.length]
|
||||
my_vote: this.props.node.comment_view.my_vote,
|
||||
score: this.props.node.comment_view.counts.score,
|
||||
upvotes: this.props.node.comment_view.counts.upvotes,
|
||||
downvotes: this.props.node.comment_view.counts.downvotes,
|
||||
borderColor: this.props.node.depth
|
||||
? colorList[this.props.node.depth % colorList.length]
|
||||
: colorList[0],
|
||||
readLoading: false,
|
||||
saveLoading: false,
|
||||
|
@ -118,11 +123,13 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
|
|||
this.handleCommentDownvote = this.handleCommentDownvote.bind(this);
|
||||
}
|
||||
|
||||
// TODO see if there's a better way to do this, and all willReceiveProps
|
||||
componentWillReceiveProps(nextProps: CommentNodeProps) {
|
||||
this.state.my_vote = nextProps.node.comment.my_vote;
|
||||
this.state.upvotes = nextProps.node.comment.upvotes;
|
||||
this.state.downvotes = nextProps.node.comment.downvotes;
|
||||
this.state.score = nextProps.node.comment.score;
|
||||
let cv = nextProps.node.comment_view;
|
||||
this.state.my_vote = cv.my_vote;
|
||||
this.state.upvotes = cv.counts.upvotes;
|
||||
this.state.downvotes = cv.counts.downvotes;
|
||||
this.state.score = cv.counts.score;
|
||||
this.state.readLoading = false;
|
||||
this.state.saveLoading = false;
|
||||
this.setState(this.state);
|
||||
|
@ -130,43 +137,30 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
|
|||
|
||||
render() {
|
||||
let node = this.props.node;
|
||||
let cv = this.props.node.comment_view;
|
||||
return (
|
||||
<div
|
||||
className={`comment ${
|
||||
node.comment.parent_id && !this.props.noIndent ? 'ml-1' : ''
|
||||
cv.comment.parent_id && !this.props.noIndent ? 'ml-1' : ''
|
||||
}`}
|
||||
>
|
||||
<div
|
||||
id={`comment-${node.comment.id}`}
|
||||
id={`comment-${cv.comment.id}`}
|
||||
className={`details comment-node py-2 ${
|
||||
!this.props.noBorder ? 'border-top border-light' : ''
|
||||
} ${this.isCommentNew ? 'mark' : ''}`}
|
||||
style={
|
||||
!this.props.noIndent &&
|
||||
this.props.node.comment.parent_id &&
|
||||
cv.comment.parent_id &&
|
||||
`border-left: 2px ${this.state.borderColor} solid !important`
|
||||
}
|
||||
>
|
||||
<div
|
||||
class={`${
|
||||
!this.props.noIndent &&
|
||||
this.props.node.comment.parent_id &&
|
||||
'ml-2'
|
||||
}`}
|
||||
class={`${!this.props.noIndent && cv.comment.parent_id && 'ml-2'}`}
|
||||
>
|
||||
<div class="d-flex flex-wrap align-items-center text-muted small">
|
||||
<span class="mr-2">
|
||||
<UserListing
|
||||
user={{
|
||||
name: node.comment.creator_name,
|
||||
preferred_username: node.comment.creator_preferred_username,
|
||||
avatar: node.comment.creator_avatar,
|
||||
id: node.comment.creator_id,
|
||||
local: node.comment.creator_local,
|
||||
actor_id: node.comment.creator_actor_id,
|
||||
published: node.comment.creator_published,
|
||||
}}
|
||||
/>
|
||||
<UserListing user={cv.creator} />
|
||||
</span>
|
||||
|
||||
{this.isMod && (
|
||||
|
@ -184,7 +178,7 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
|
|||
{i18n.t('creator')}
|
||||
</div>
|
||||
)}
|
||||
{(node.comment.banned_from_community || node.comment.banned) && (
|
||||
{(cv.creator_banned_from_community || cv.creator.banned) && (
|
||||
<div className="badge badge-danger mr-2">
|
||||
{i18n.t('banned')}
|
||||
</div>
|
||||
|
@ -192,18 +186,10 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
|
|||
{this.props.showCommunity && (
|
||||
<>
|
||||
<span class="mx-1">{i18n.t('to')}</span>
|
||||
<CommunityLink
|
||||
community={{
|
||||
name: node.comment.community_name,
|
||||
id: node.comment.community_id,
|
||||
local: node.comment.community_local,
|
||||
actor_id: node.comment.community_actor_id,
|
||||
icon: node.comment.community_icon,
|
||||
}}
|
||||
/>
|
||||
<CommunityLink community={cv.community} />
|
||||
<span class="mx-2">•</span>
|
||||
<Link className="mr-2" to={`/post/${node.comment.post_id}`}>
|
||||
{node.comment.post_name}
|
||||
<Link className="mr-2" to={`/post/${cv.post.id}`}>
|
||||
{cv.post.name}
|
||||
</Link>
|
||||
</>
|
||||
)}
|
||||
|
@ -224,7 +210,7 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
|
|||
</a>
|
||||
<span className="mr-1">•</span>
|
||||
<span>
|
||||
<MomentTime data={node.comment} />
|
||||
<MomentTime data={cv.comment} />
|
||||
</span>
|
||||
</div>
|
||||
{/* end of user row */}
|
||||
|
@ -256,7 +242,7 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
|
|||
class="btn btn-link btn-animate text-muted"
|
||||
onClick={linkEvent(this, this.handleMarkRead)}
|
||||
data-tippy-content={
|
||||
node.comment.read
|
||||
cv.comment.read
|
||||
? i18n.t('mark_as_unread')
|
||||
: i18n.t('mark_as_read')
|
||||
}
|
||||
|
@ -266,7 +252,7 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
|
|||
) : (
|
||||
<svg
|
||||
class={`icon icon-inline ${
|
||||
node.comment.read && 'text-success'
|
||||
cv.comment.read && 'text-success'
|
||||
}`}
|
||||
>
|
||||
<use xlinkHref="#icon-check"></use>
|
||||
|
@ -333,7 +319,7 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
|
|||
<button class="btn btn-link btn-animate">
|
||||
<Link
|
||||
className="text-muted"
|
||||
to={`/create_private_message/recipient/${node.comment.creator_id}`}
|
||||
to={`/create_private_message/recipient/${cv.creator.id}`}
|
||||
title={i18n.t('message').toLowerCase()}
|
||||
>
|
||||
<svg class="icon">
|
||||
|
@ -350,9 +336,7 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
|
|||
this.handleSaveCommentClick
|
||||
)}
|
||||
data-tippy-content={
|
||||
node.comment.saved
|
||||
? i18n.t('unsave')
|
||||
: i18n.t('save')
|
||||
cv.saved ? i18n.t('unsave') : i18n.t('save')
|
||||
}
|
||||
>
|
||||
{this.state.saveLoading ? (
|
||||
|
@ -360,7 +344,7 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
|
|||
) : (
|
||||
<svg
|
||||
class={`icon icon-inline ${
|
||||
node.comment.saved && 'text-warning'
|
||||
cv.saved && 'text-warning'
|
||||
}`}
|
||||
>
|
||||
<use xlinkHref="#icon-star"></use>
|
||||
|
@ -398,14 +382,14 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
|
|||
this.handleDeleteClick
|
||||
)}
|
||||
data-tippy-content={
|
||||
!node.comment.deleted
|
||||
!cv.comment.deleted
|
||||
? i18n.t('delete')
|
||||
: i18n.t('restore')
|
||||
}
|
||||
>
|
||||
<svg
|
||||
class={`icon icon-inline ${
|
||||
node.comment.deleted && 'text-danger'
|
||||
cv.comment.deleted && 'text-danger'
|
||||
}`}
|
||||
>
|
||||
<use xlinkHref="#icon-trash"></use>
|
||||
|
@ -416,7 +400,7 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
|
|||
{/* Admins and mods can remove comments */}
|
||||
{(this.canMod || this.canAdmin) && (
|
||||
<>
|
||||
{!node.comment.removed ? (
|
||||
{!cv.comment.removed ? (
|
||||
<button
|
||||
class="btn btn-link btn-animate text-muted"
|
||||
onClick={linkEvent(
|
||||
|
@ -443,7 +427,7 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
|
|||
{this.canMod && (
|
||||
<>
|
||||
{!this.isMod &&
|
||||
(!node.comment.banned_from_community ? (
|
||||
(!cv.creator_banned_from_community ? (
|
||||
<button
|
||||
class="btn btn-link btn-animate text-muted"
|
||||
onClick={linkEvent(
|
||||
|
@ -464,8 +448,8 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
|
|||
{i18n.t('unban')}
|
||||
</button>
|
||||
))}
|
||||
{!node.comment.banned_from_community &&
|
||||
node.comment.creator_local &&
|
||||
{!cv.creator_banned_from_community &&
|
||||
cv.creator.local &&
|
||||
(!this.state.showConfirmAppointAsMod ? (
|
||||
<button
|
||||
class="btn btn-link btn-animate text-muted"
|
||||
|
@ -508,7 +492,7 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
|
|||
{/* Community creators and admins can transfer community to another mod */}
|
||||
{(this.amCommunityCreator || this.canAdmin) &&
|
||||
this.isMod &&
|
||||
node.comment.creator_local &&
|
||||
cv.creator.local &&
|
||||
(!this.state.showConfirmTransferCommunity ? (
|
||||
<button
|
||||
class="btn btn-link btn-animate text-muted"
|
||||
|
@ -549,7 +533,7 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
|
|||
{this.canAdmin && (
|
||||
<>
|
||||
{!this.isAdmin &&
|
||||
(!node.comment.banned ? (
|
||||
(!cv.creator.banned ? (
|
||||
<button
|
||||
class="btn btn-link btn-animate text-muted"
|
||||
onClick={linkEvent(
|
||||
|
@ -570,8 +554,8 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
|
|||
{i18n.t('unban_from_site')}
|
||||
</button>
|
||||
))}
|
||||
{!node.comment.banned &&
|
||||
node.comment.creator_local &&
|
||||
{!cv.creator.banned &&
|
||||
cv.creator.local &&
|
||||
(!this.state.showConfirmAppointAsAdmin ? (
|
||||
<button
|
||||
class="btn btn-link btn-animate text-muted"
|
||||
|
@ -614,7 +598,7 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
|
|||
{/* Site Creator can transfer to another admin */}
|
||||
{this.amSiteCreator &&
|
||||
this.isAdmin &&
|
||||
node.comment.creator_local &&
|
||||
cv.creator.local &&
|
||||
(!this.state.showConfirmTransferSite ? (
|
||||
<button
|
||||
class="btn btn-link btn-animate text-muted"
|
||||
|
@ -711,7 +695,7 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
|
|||
{/* </div> */}
|
||||
<div class="form-group row">
|
||||
<button type="submit" class="btn btn-secondary">
|
||||
{i18n.t('ban')} {node.comment.creator_name}
|
||||
{i18n.t('ban')} {cv.creator.name}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
|
@ -743,11 +727,11 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
|
|||
}
|
||||
|
||||
get linkBtn() {
|
||||
let node = this.props.node;
|
||||
let cv = this.props.node.comment_view;
|
||||
return (
|
||||
<Link
|
||||
className="btn btn-link btn-animate text-muted"
|
||||
to={`/post/${node.comment.post_id}/comment/${node.comment.id}`}
|
||||
to={`/post/${cv.post.id}/comment/${cv.comment.id}`}
|
||||
title={this.props.showContext ? i18n.t('show_context') : i18n.t('link')}
|
||||
>
|
||||
<svg class="icon icon-inline">
|
||||
|
@ -768,7 +752,7 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
|
|||
get myComment(): boolean {
|
||||
return (
|
||||
UserService.Instance.user &&
|
||||
this.props.node.comment.creator_id == UserService.Instance.user.id
|
||||
this.props.node.comment_view.creator.id == UserService.Instance.user.id
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -776,8 +760,8 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
|
|||
return (
|
||||
this.props.moderators &&
|
||||
isMod(
|
||||
this.props.moderators.map(m => m.user_id),
|
||||
this.props.node.comment.creator_id
|
||||
this.props.moderators.map(m => m.moderator.id),
|
||||
this.props.node.comment_view.creator.id
|
||||
)
|
||||
);
|
||||
}
|
||||
|
@ -786,26 +770,26 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
|
|||
return (
|
||||
this.props.admins &&
|
||||
isMod(
|
||||
this.props.admins.map(a => a.id),
|
||||
this.props.node.comment.creator_id
|
||||
this.props.admins.map(a => a.user.id),
|
||||
this.props.node.comment_view.creator.id
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
get isPostCreator(): boolean {
|
||||
return this.props.node.comment.creator_id == this.props.postCreatorId;
|
||||
return this.props.node.comment_view.creator.id == this.props.postCreatorId;
|
||||
}
|
||||
|
||||
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));
|
||||
.map(a => a.user.id)
|
||||
.concat(this.props.moderators.map(m => m.moderator.id));
|
||||
|
||||
return canMod(
|
||||
UserService.Instance.user,
|
||||
adminsThenMods,
|
||||
this.props.node.comment.creator_id
|
||||
this.props.node.comment_view.creator.id
|
||||
);
|
||||
} else {
|
||||
return false;
|
||||
|
@ -817,8 +801,8 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
|
|||
this.props.admins &&
|
||||
canMod(
|
||||
UserService.Instance.user,
|
||||
this.props.admins.map(a => a.id),
|
||||
this.props.node.comment.creator_id
|
||||
this.props.admins.map(a => a.user.id),
|
||||
this.props.node.comment_view.creator.id
|
||||
)
|
||||
);
|
||||
}
|
||||
|
@ -827,8 +811,8 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
|
|||
return (
|
||||
this.props.moderators &&
|
||||
UserService.Instance.user &&
|
||||
this.props.node.comment.creator_id != UserService.Instance.user.id &&
|
||||
UserService.Instance.user.id == this.props.moderators[0].user_id
|
||||
this.props.node.comment_view.creator.id != UserService.Instance.user.id &&
|
||||
UserService.Instance.user.id == this.props.moderators[0].moderator.id
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -836,18 +820,18 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
|
|||
return (
|
||||
this.props.admins &&
|
||||
UserService.Instance.user &&
|
||||
this.props.node.comment.creator_id != UserService.Instance.user.id &&
|
||||
UserService.Instance.user.id == this.props.admins[0].id
|
||||
this.props.node.comment_view.creator.id != UserService.Instance.user.id &&
|
||||
UserService.Instance.user.id == this.props.admins[0].user.id
|
||||
);
|
||||
}
|
||||
|
||||
get commentUnlessRemoved(): string {
|
||||
let node = this.props.node;
|
||||
return node.comment.removed
|
||||
let comment = this.props.node.comment_view.comment;
|
||||
return comment.removed
|
||||
? `*${i18n.t('removed')}*`
|
||||
: node.comment.deleted
|
||||
: comment.deleted
|
||||
? `*${i18n.t('deleted')}*`
|
||||
: node.comment.content;
|
||||
: comment.content;
|
||||
}
|
||||
|
||||
handleReplyClick(i: CommentNode) {
|
||||
|
@ -861,25 +845,25 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
|
|||
}
|
||||
|
||||
handleDeleteClick(i: CommentNode) {
|
||||
let deleteForm: DeleteCommentForm = {
|
||||
edit_id: i.props.node.comment.id,
|
||||
deleted: !i.props.node.comment.deleted,
|
||||
auth: null,
|
||||
let comment = i.props.node.comment_view.comment;
|
||||
let deleteForm: DeleteComment = {
|
||||
edit_id: comment.id,
|
||||
deleted: !comment.deleted,
|
||||
auth: UserService.Instance.authField(),
|
||||
};
|
||||
WebSocketService.Instance.deleteComment(deleteForm);
|
||||
WebSocketService.Instance.client.deleteComment(deleteForm);
|
||||
}
|
||||
|
||||
handleSaveCommentClick(i: CommentNode) {
|
||||
let saved =
|
||||
i.props.node.comment.saved == undefined
|
||||
? true
|
||||
: !i.props.node.comment.saved;
|
||||
let form: SaveCommentForm = {
|
||||
comment_id: i.props.node.comment.id,
|
||||
save: saved,
|
||||
let cv = i.props.node.comment_view;
|
||||
let save = cv.saved == undefined ? true : !cv.saved;
|
||||
let form: SaveComment = {
|
||||
comment_id: cv.comment.id,
|
||||
save,
|
||||
auth: UserService.Instance.authField(),
|
||||
};
|
||||
|
||||
WebSocketService.Instance.saveComment(form);
|
||||
WebSocketService.Instance.client.saveComment(form);
|
||||
|
||||
i.state.saveLoading = true;
|
||||
i.setState(this.state);
|
||||
|
@ -908,12 +892,13 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
|
|||
|
||||
this.state.my_vote = new_vote;
|
||||
|
||||
let form: CommentLikeForm = {
|
||||
comment_id: i.comment.id,
|
||||
let form: CreateCommentLike = {
|
||||
comment_id: i.comment_view.comment.id,
|
||||
score: this.state.my_vote,
|
||||
auth: UserService.Instance.authField(),
|
||||
};
|
||||
|
||||
WebSocketService.Instance.likeComment(form);
|
||||
WebSocketService.Instance.client.likeComment(form);
|
||||
this.setState(this.state);
|
||||
setupTippy();
|
||||
}
|
||||
|
@ -935,12 +920,13 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
|
|||
|
||||
this.state.my_vote = new_vote;
|
||||
|
||||
let form: CommentLikeForm = {
|
||||
comment_id: i.comment.id,
|
||||
let form: CreateCommentLike = {
|
||||
comment_id: i.comment_view.comment.id,
|
||||
score: this.state.my_vote,
|
||||
auth: UserService.Instance.authField(),
|
||||
};
|
||||
|
||||
WebSocketService.Instance.likeComment(form);
|
||||
WebSocketService.Instance.client.likeComment(form);
|
||||
this.setState(this.state);
|
||||
setupTippy();
|
||||
}
|
||||
|
@ -961,34 +947,40 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
|
|||
}
|
||||
|
||||
handleModRemoveSubmit(i: CommentNode) {
|
||||
event.preventDefault();
|
||||
let form: RemoveCommentForm = {
|
||||
edit_id: i.props.node.comment.id,
|
||||
removed: !i.props.node.comment.removed,
|
||||
let comment = i.props.node.comment_view.comment;
|
||||
let form: RemoveComment = {
|
||||
edit_id: comment.id,
|
||||
removed: !comment.removed,
|
||||
reason: i.state.removeReason,
|
||||
auth: null,
|
||||
auth: UserService.Instance.authField(),
|
||||
};
|
||||
WebSocketService.Instance.removeComment(form);
|
||||
WebSocketService.Instance.client.removeComment(form);
|
||||
|
||||
i.state.showRemoveDialog = false;
|
||||
i.setState(i.state);
|
||||
}
|
||||
|
||||
isUserMentionType(
|
||||
item: CommentView | UserMentionView
|
||||
): item is UserMentionView {
|
||||
return (item as UserMentionView).user_mention.id !== undefined;
|
||||
}
|
||||
|
||||
handleMarkRead(i: CommentNode) {
|
||||
// if it has a user_mention_id field, then its a mention
|
||||
if (i.props.node.comment.user_mention_id) {
|
||||
let form: MarkUserMentionAsReadForm = {
|
||||
user_mention_id: i.props.node.comment.user_mention_id,
|
||||
read: !i.props.node.comment.read,
|
||||
if (i.isUserMentionType(i.props.node.comment_view)) {
|
||||
let form: MarkUserMentionAsRead = {
|
||||
user_mention_id: i.props.node.comment_view.user_mention.id,
|
||||
read: !i.props.node.comment_view.user_mention.read,
|
||||
auth: UserService.Instance.authField(),
|
||||
};
|
||||
WebSocketService.Instance.markUserMentionAsRead(form);
|
||||
WebSocketService.Instance.client.markUserMentionAsRead(form);
|
||||
} else {
|
||||
let form: MarkCommentAsReadForm = {
|
||||
edit_id: i.props.node.comment.id,
|
||||
read: !i.props.node.comment.read,
|
||||
auth: null,
|
||||
let form: MarkCommentAsRead = {
|
||||
comment_id: i.props.node.comment_view.comment.id,
|
||||
read: !i.props.node.comment_view.comment.read,
|
||||
auth: UserService.Instance.authField(),
|
||||
};
|
||||
WebSocketService.Instance.markCommentAsRead(form);
|
||||
WebSocketService.Instance.client.markCommentAsRead(form);
|
||||
}
|
||||
|
||||
i.state.readLoading = true;
|
||||
|
@ -1030,37 +1022,39 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
|
|||
}
|
||||
|
||||
handleModBanBothSubmit(i: CommentNode) {
|
||||
event.preventDefault();
|
||||
let cv = i.props.node.comment_view;
|
||||
|
||||
if (i.state.banType == BanType.Community) {
|
||||
// If its an unban, restore all their data
|
||||
let ban = !i.props.node.comment.banned_from_community;
|
||||
let ban = !cv.creator_banned_from_community;
|
||||
if (ban == false) {
|
||||
i.state.removeData = false;
|
||||
}
|
||||
let form: BanFromCommunityForm = {
|
||||
user_id: i.props.node.comment.creator_id,
|
||||
community_id: i.props.node.comment.community_id,
|
||||
let form: BanFromCommunity = {
|
||||
user_id: cv.creator.id,
|
||||
community_id: cv.community.id,
|
||||
ban,
|
||||
remove_data: i.state.removeData,
|
||||
reason: i.state.banReason,
|
||||
expires: getUnixTime(i.state.banExpires),
|
||||
auth: UserService.Instance.authField(),
|
||||
};
|
||||
WebSocketService.Instance.banFromCommunity(form);
|
||||
WebSocketService.Instance.client.banFromCommunity(form);
|
||||
} else {
|
||||
// If its an unban, restore all their data
|
||||
let ban = !i.props.node.comment.banned;
|
||||
let ban = !cv.creator.banned;
|
||||
if (ban == false) {
|
||||
i.state.removeData = false;
|
||||
}
|
||||
let form: BanUserForm = {
|
||||
user_id: i.props.node.comment.creator_id,
|
||||
let form: BanUser = {
|
||||
user_id: cv.creator.id,
|
||||
ban,
|
||||
remove_data: i.state.removeData,
|
||||
reason: i.state.banReason,
|
||||
expires: getUnixTime(i.state.banExpires),
|
||||
auth: UserService.Instance.authField(),
|
||||
};
|
||||
WebSocketService.Instance.banUser(form);
|
||||
WebSocketService.Instance.client.banUser(form);
|
||||
}
|
||||
|
||||
i.state.showBanDialog = false;
|
||||
|
@ -1078,12 +1072,14 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
|
|||
}
|
||||
|
||||
handleAddModToCommunity(i: CommentNode) {
|
||||
let form: AddModToCommunityForm = {
|
||||
user_id: i.props.node.comment.creator_id,
|
||||
community_id: i.props.node.comment.community_id,
|
||||
let cv = i.props.node.comment_view;
|
||||
let form: AddModToCommunity = {
|
||||
user_id: cv.creator.id,
|
||||
community_id: cv.community.id,
|
||||
added: !i.isMod,
|
||||
auth: UserService.Instance.authField(),
|
||||
};
|
||||
WebSocketService.Instance.addModToCommunity(form);
|
||||
WebSocketService.Instance.client.addModToCommunity(form);
|
||||
i.state.showConfirmAppointAsMod = false;
|
||||
i.setState(i.state);
|
||||
}
|
||||
|
@ -1099,11 +1095,12 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
|
|||
}
|
||||
|
||||
handleAddAdmin(i: CommentNode) {
|
||||
let form: AddAdminForm = {
|
||||
user_id: i.props.node.comment.creator_id,
|
||||
let form: AddAdmin = {
|
||||
user_id: i.props.node.comment_view.creator.id,
|
||||
added: !i.isAdmin,
|
||||
auth: UserService.Instance.authField(),
|
||||
};
|
||||
WebSocketService.Instance.addAdmin(form);
|
||||
WebSocketService.Instance.client.addAdmin(form);
|
||||
i.state.showConfirmAppointAsAdmin = false;
|
||||
i.setState(i.state);
|
||||
}
|
||||
|
@ -1119,11 +1116,13 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
|
|||
}
|
||||
|
||||
handleTransferCommunity(i: CommentNode) {
|
||||
let form: TransferCommunityForm = {
|
||||
community_id: i.props.node.comment.community_id,
|
||||
user_id: i.props.node.comment.creator_id,
|
||||
let cv = i.props.node.comment_view;
|
||||
let form: TransferCommunity = {
|
||||
community_id: cv.community.id,
|
||||
user_id: cv.creator.id,
|
||||
auth: UserService.Instance.authField(),
|
||||
};
|
||||
WebSocketService.Instance.transferCommunity(form);
|
||||
WebSocketService.Instance.client.transferCommunity(form);
|
||||
i.state.showConfirmTransferCommunity = false;
|
||||
i.setState(i.state);
|
||||
}
|
||||
|
@ -1139,17 +1138,18 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
|
|||
}
|
||||
|
||||
handleTransferSite(i: CommentNode) {
|
||||
let form: TransferSiteForm = {
|
||||
user_id: i.props.node.comment.creator_id,
|
||||
let form: TransferSite = {
|
||||
user_id: i.props.node.comment_view.creator.id,
|
||||
auth: UserService.Instance.authField(),
|
||||
};
|
||||
WebSocketService.Instance.transferSite(form);
|
||||
WebSocketService.Instance.client.transferSite(form);
|
||||
i.state.showConfirmTransferSite = false;
|
||||
i.setState(i.state);
|
||||
}
|
||||
|
||||
get isCommentNew(): boolean {
|
||||
let now = moment.utc().subtract(10, 'minutes');
|
||||
let then = moment.utc(this.props.node.comment.published);
|
||||
let then = moment.utc(this.props.node.comment_view.comment.published);
|
||||
return now.isBefore(then);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
import { Component } from 'inferno';
|
||||
import { CommentSortType } from '../interfaces';
|
||||
import { CommentSortType, CommentNode as CommentNodeI } from '../interfaces';
|
||||
import {
|
||||
CommentNode as CommentNodeI,
|
||||
CommunityUser,
|
||||
UserView,
|
||||
CommunityModeratorView,
|
||||
UserViewSafe,
|
||||
SortType,
|
||||
} from 'lemmy-js-client';
|
||||
import { commentSort, commentSortSortType } from '../utils';
|
||||
|
@ -13,8 +12,8 @@ interface CommentNodesState {}
|
|||
|
||||
interface CommentNodesProps {
|
||||
nodes: CommentNodeI[];
|
||||
moderators?: CommunityUser[];
|
||||
admins?: UserView[];
|
||||
moderators?: CommunityModeratorView[];
|
||||
admins?: UserViewSafe[];
|
||||
postCreatorId?: number;
|
||||
noBorder?: boolean;
|
||||
noIndent?: boolean;
|
||||
|
@ -41,7 +40,7 @@ export class CommentNodes extends Component<
|
|||
<div className="comments">
|
||||
{this.sorter().map(node => (
|
||||
<CommentNode
|
||||
key={node.comment.id}
|
||||
key={node.comment_view.comment.id}
|
||||
node={node}
|
||||
noBorder={this.props.noBorder}
|
||||
noIndent={this.props.noIndent}
|
||||
|
|
|
@ -3,24 +3,23 @@ import { HtmlTags } from './html-tags';
|
|||
import { Subscription } from 'rxjs';
|
||||
import {
|
||||
UserOperation,
|
||||
Community,
|
||||
CommunityView,
|
||||
ListCommunitiesResponse,
|
||||
CommunityResponse,
|
||||
FollowCommunityForm,
|
||||
ListCommunitiesForm,
|
||||
FollowCommunity,
|
||||
ListCommunities,
|
||||
SortType,
|
||||
WebSocketJsonResponse,
|
||||
Site,
|
||||
SiteView,
|
||||
} from 'lemmy-js-client';
|
||||
import { WebSocketService } from '../services';
|
||||
import { UserService, WebSocketService } from '../services';
|
||||
import {
|
||||
wsJsonToRes,
|
||||
toast,
|
||||
getPageFromProps,
|
||||
isBrowser,
|
||||
setAuth,
|
||||
setIsoData,
|
||||
wsSubscribe,
|
||||
wsUserOp,
|
||||
} from '../utils';
|
||||
import { CommunityLink } from './community-link';
|
||||
import { i18n } from '../i18next';
|
||||
|
@ -29,10 +28,10 @@ import { InitialFetchRequest } from 'shared/interfaces';
|
|||
const communityLimit = 100;
|
||||
|
||||
interface CommunitiesState {
|
||||
communities: Community[];
|
||||
communities: CommunityView[];
|
||||
page: number;
|
||||
loading: boolean;
|
||||
site: Site;
|
||||
site_view: SiteView;
|
||||
}
|
||||
|
||||
interface CommunitiesProps {
|
||||
|
@ -46,7 +45,7 @@ export class Communities extends Component<any, CommunitiesState> {
|
|||
communities: [],
|
||||
loading: true,
|
||||
page: getPageFromProps(this.props),
|
||||
site: this.isoData.site.site,
|
||||
site_view: this.isoData.site_res.site_view,
|
||||
};
|
||||
|
||||
constructor(props: any, context: any) {
|
||||
|
@ -60,7 +59,7 @@ export class Communities extends Component<any, CommunitiesState> {
|
|||
if (this.isoData.path == this.context.router.route.match.url) {
|
||||
this.state.communities = this.isoData.routeData[0].communities;
|
||||
this.state.communities.sort(
|
||||
(a, b) => b.number_of_subscribers - a.number_of_subscribers
|
||||
(a, b) => b.counts.subscribers - a.counts.subscribers
|
||||
);
|
||||
this.state.loading = false;
|
||||
} else {
|
||||
|
@ -88,7 +87,7 @@ export class Communities extends Component<any, CommunitiesState> {
|
|||
}
|
||||
|
||||
get documentTitle(): string {
|
||||
return `${i18n.t('communities')} - ${this.state.site.name}`;
|
||||
return `${i18n.t('communities')} - ${this.state.site_view.site.name}`;
|
||||
}
|
||||
|
||||
render() {
|
||||
|
@ -124,27 +123,25 @@ export class Communities extends Component<any, CommunitiesState> {
|
|||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{this.state.communities.map(community => (
|
||||
{this.state.communities.map(cv => (
|
||||
<tr>
|
||||
<td>
|
||||
<CommunityLink community={community} />
|
||||
<CommunityLink community={cv.community} />
|
||||
</td>
|
||||
<td>{community.category_name}</td>
|
||||
<td class="text-right">
|
||||
{community.number_of_subscribers}
|
||||
<td>{cv.category.name}</td>
|
||||
<td class="text-right">{cv.counts.subscribers}</td>
|
||||
<td class="text-right d-none d-lg-table-cell">
|
||||
{cv.counts.posts}
|
||||
</td>
|
||||
<td class="text-right d-none d-lg-table-cell">
|
||||
{community.number_of_posts}
|
||||
</td>
|
||||
<td class="text-right d-none d-lg-table-cell">
|
||||
{community.number_of_comments}
|
||||
{cv.counts.comments}
|
||||
</td>
|
||||
<td class="text-right">
|
||||
{community.subscribed ? (
|
||||
{cv.subscribed ? (
|
||||
<span
|
||||
class="pointer btn-link"
|
||||
onClick={linkEvent(
|
||||
community.id,
|
||||
cv.community.id,
|
||||
this.handleUnsubscribe
|
||||
)}
|
||||
>
|
||||
|
@ -154,7 +151,7 @@ export class Communities extends Component<any, CommunitiesState> {
|
|||
<span
|
||||
class="pointer btn-link"
|
||||
onClick={linkEvent(
|
||||
community.id,
|
||||
cv.community.id,
|
||||
this.handleSubscribe
|
||||
)}
|
||||
>
|
||||
|
@ -212,64 +209,68 @@ export class Communities extends Component<any, CommunitiesState> {
|
|||
}
|
||||
|
||||
handleUnsubscribe(communityId: number) {
|
||||
let form: FollowCommunityForm = {
|
||||
let form: FollowCommunity = {
|
||||
community_id: communityId,
|
||||
follow: false,
|
||||
auth: UserService.Instance.authField(),
|
||||
};
|
||||
WebSocketService.Instance.followCommunity(form);
|
||||
WebSocketService.Instance.client.followCommunity(form);
|
||||
}
|
||||
|
||||
handleSubscribe(communityId: number) {
|
||||
let form: FollowCommunityForm = {
|
||||
let form: FollowCommunity = {
|
||||
community_id: communityId,
|
||||
follow: true,
|
||||
auth: UserService.Instance.authField(),
|
||||
};
|
||||
WebSocketService.Instance.followCommunity(form);
|
||||
WebSocketService.Instance.client.followCommunity(form);
|
||||
}
|
||||
|
||||
refetch() {
|
||||
let listCommunitiesForm: ListCommunitiesForm = {
|
||||
let listCommunitiesForm: ListCommunities = {
|
||||
sort: SortType.TopAll,
|
||||
limit: communityLimit,
|
||||
page: this.state.page,
|
||||
auth: UserService.Instance.authField(false),
|
||||
};
|
||||
|
||||
WebSocketService.Instance.listCommunities(listCommunitiesForm);
|
||||
WebSocketService.Instance.client.listCommunities(listCommunitiesForm);
|
||||
}
|
||||
|
||||
static fetchInitialData(req: InitialFetchRequest): Promise<any>[] {
|
||||
let pathSplit = req.path.split('/');
|
||||
let page = pathSplit[3] ? Number(pathSplit[3]) : 1;
|
||||
let listCommunitiesForm: ListCommunitiesForm = {
|
||||
let listCommunitiesForm: ListCommunities = {
|
||||
sort: SortType.TopAll,
|
||||
limit: communityLimit,
|
||||
page,
|
||||
auth: req.auth,
|
||||
};
|
||||
setAuth(listCommunitiesForm, req.auth);
|
||||
|
||||
return [req.client.listCommunities(listCommunitiesForm)];
|
||||
}
|
||||
|
||||
parseMessage(msg: WebSocketJsonResponse) {
|
||||
console.log(msg);
|
||||
let res = wsJsonToRes(msg);
|
||||
parseMessage(msg: any) {
|
||||
let op = wsUserOp(msg);
|
||||
if (msg.error) {
|
||||
toast(i18n.t(msg.error), 'danger');
|
||||
return;
|
||||
} else if (res.op == UserOperation.ListCommunities) {
|
||||
let data = res.data as ListCommunitiesResponse;
|
||||
} else if (op == UserOperation.ListCommunities) {
|
||||
let data = wsJsonToRes<ListCommunitiesResponse>(msg).data;
|
||||
this.state.communities = data.communities;
|
||||
this.state.communities.sort(
|
||||
(a, b) => b.number_of_subscribers - a.number_of_subscribers
|
||||
(a, b) => b.counts.subscribers - a.counts.subscribers
|
||||
);
|
||||
this.state.loading = false;
|
||||
window.scrollTo(0, 0);
|
||||
this.setState(this.state);
|
||||
} else if (res.op == UserOperation.FollowCommunity) {
|
||||
let data = res.data as CommunityResponse;
|
||||
let found = this.state.communities.find(c => c.id == data.community.id);
|
||||
found.subscribed = data.community.subscribed;
|
||||
found.number_of_subscribers = data.community.number_of_subscribers;
|
||||
} else if (op == UserOperation.FollowCommunity) {
|
||||
let data = wsJsonToRes<CommunityResponse>(msg).data;
|
||||
let found = this.state.communities.find(
|
||||
c => c.community.id == data.community_view.community.id
|
||||
);
|
||||
found.subscribed = data.community_view.subscribed;
|
||||
found.counts.subscribers = data.community_view.counts.subscribers;
|
||||
this.setState(this.state);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,20 +2,21 @@ import { Component, linkEvent } from 'inferno';
|
|||
import { Prompt } from 'inferno-router';
|
||||
import { Subscription } from 'rxjs';
|
||||
import {
|
||||
CommunityForm as CommunityFormI,
|
||||
EditCommunity,
|
||||
CreateCommunity,
|
||||
UserOperation,
|
||||
Category,
|
||||
CommunityResponse,
|
||||
WebSocketJsonResponse,
|
||||
Community,
|
||||
CommunityView,
|
||||
} from 'lemmy-js-client';
|
||||
import { WebSocketService } from '../services';
|
||||
import { UserService, WebSocketService } from '../services';
|
||||
import {
|
||||
wsJsonToRes,
|
||||
capitalizeFirstLetter,
|
||||
toast,
|
||||
randomStr,
|
||||
wsSubscribe,
|
||||
wsUserOp,
|
||||
} from '../utils';
|
||||
import { i18n } from '../i18next';
|
||||
|
||||
|
@ -23,16 +24,16 @@ import { MarkdownTextArea } from './markdown-textarea';
|
|||
import { ImageUploadForm } from './image-upload-form';
|
||||
|
||||
interface CommunityFormProps {
|
||||
community?: Community; // If a community is given, that means this is an edit
|
||||
community_view?: CommunityView; // If a community is given, that means this is an edit
|
||||
categories: Category[];
|
||||
onCancel?(): any;
|
||||
onCreate?(community: Community): any;
|
||||
onEdit?(community: Community): any;
|
||||
onCreate?(community: CommunityView): any;
|
||||
onEdit?(community: CommunityView): any;
|
||||
enableNsfw: boolean;
|
||||
}
|
||||
|
||||
interface CommunityFormState {
|
||||
communityForm: CommunityFormI;
|
||||
communityForm: CreateCommunity;
|
||||
loading: boolean;
|
||||
}
|
||||
|
||||
|
@ -51,6 +52,7 @@ export class CommunityForm extends Component<
|
|||
nsfw: false,
|
||||
icon: null,
|
||||
banner: null,
|
||||
auth: UserService.Instance.authField(),
|
||||
},
|
||||
loading: false,
|
||||
};
|
||||
|
@ -70,17 +72,17 @@ export class CommunityForm extends Component<
|
|||
this.handleBannerUpload = this.handleBannerUpload.bind(this);
|
||||
this.handleBannerRemove = this.handleBannerRemove.bind(this);
|
||||
|
||||
if (this.props.community) {
|
||||
let cv = this.props.community_view;
|
||||
if (cv) {
|
||||
this.state.communityForm = {
|
||||
name: this.props.community.name,
|
||||
title: this.props.community.title,
|
||||
category_id: this.props.community.category_id,
|
||||
description: this.props.community.description,
|
||||
edit_id: this.props.community.id,
|
||||
nsfw: this.props.community.nsfw,
|
||||
icon: this.props.community.icon,
|
||||
banner: this.props.community.banner,
|
||||
auth: null,
|
||||
name: cv.community.name,
|
||||
title: cv.community.title,
|
||||
category_id: cv.category.id,
|
||||
description: cv.community.description,
|
||||
nsfw: cv.community.nsfw,
|
||||
icon: cv.community.icon,
|
||||
banner: cv.community.banner,
|
||||
auth: UserService.Instance.authField(),
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -88,6 +90,7 @@ export class CommunityForm extends Component<
|
|||
this.subscription = wsSubscribe(this.parseMessage);
|
||||
}
|
||||
|
||||
// TODO this should be checked out
|
||||
componentDidUpdate() {
|
||||
if (
|
||||
!this.state.loading &&
|
||||
|
@ -119,7 +122,7 @@ export class CommunityForm extends Component<
|
|||
message={i18n.t('block_leaving')}
|
||||
/>
|
||||
<form onSubmit={linkEvent(this, this.handleCreateCommunitySubmit)}>
|
||||
{!this.props.community && (
|
||||
{!this.props.community_view && (
|
||||
<div class="form-group row">
|
||||
<label class="col-12 col-form-label" htmlFor="community-name">
|
||||
{i18n.t('name')}
|
||||
|
@ -250,13 +253,13 @@ export class CommunityForm extends Component<
|
|||
<svg class="icon icon-spinner spin">
|
||||
<use xlinkHref="#icon-spinner"></use>
|
||||
</svg>
|
||||
) : this.props.community ? (
|
||||
) : this.props.community_view ? (
|
||||
capitalizeFirstLetter(i18n.t('save'))
|
||||
) : (
|
||||
capitalizeFirstLetter(i18n.t('create'))
|
||||
)}
|
||||
</button>
|
||||
{this.props.community && (
|
||||
{this.props.community_view && (
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-secondary"
|
||||
|
@ -275,10 +278,14 @@ export class CommunityForm extends Component<
|
|||
handleCreateCommunitySubmit(i: CommunityForm, event: any) {
|
||||
event.preventDefault();
|
||||
i.state.loading = true;
|
||||
if (i.props.community) {
|
||||
WebSocketService.Instance.editCommunity(i.state.communityForm);
|
||||
if (i.props.community_view) {
|
||||
let form: EditCommunity = {
|
||||
...i.state.communityForm,
|
||||
edit_id: i.props.community_view.community.id,
|
||||
};
|
||||
WebSocketService.Instance.client.editCommunity(form);
|
||||
} else {
|
||||
WebSocketService.Instance.createCommunity(i.state.communityForm);
|
||||
WebSocketService.Instance.client.createCommunity(i.state.communityForm);
|
||||
}
|
||||
i.setState(i.state);
|
||||
}
|
||||
|
@ -332,22 +339,21 @@ export class CommunityForm extends Component<
|
|||
this.setState(this.state);
|
||||
}
|
||||
|
||||
parseMessage(msg: WebSocketJsonResponse) {
|
||||
let res = wsJsonToRes(msg);
|
||||
console.log(msg);
|
||||
parseMessage(msg: any) {
|
||||
let op = wsUserOp(msg);
|
||||
if (msg.error) {
|
||||
toast(i18n.t(msg.error), 'danger');
|
||||
this.state.loading = false;
|
||||
this.setState(this.state);
|
||||
return;
|
||||
} else if (res.op == UserOperation.CreateCommunity) {
|
||||
let data = res.data as CommunityResponse;
|
||||
} else if (op == UserOperation.CreateCommunity) {
|
||||
let data = wsJsonToRes<CommunityResponse>(msg).data;
|
||||
this.state.loading = false;
|
||||
this.props.onCreate(data.community);
|
||||
} else if (res.op == UserOperation.EditCommunity) {
|
||||
let data = res.data as CommunityResponse;
|
||||
this.props.onCreate(data.community_view);
|
||||
} else if (op == UserOperation.EditCommunity) {
|
||||
let data = wsJsonToRes<CommunityResponse>(msg).data;
|
||||
this.state.loading = false;
|
||||
this.props.onEdit(data.community);
|
||||
this.props.onEdit(data.community_view);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,19 +1,12 @@
|
|||
import { Component } from 'inferno';
|
||||
import { Link } from 'inferno-router';
|
||||
import { Community } from 'lemmy-js-client';
|
||||
import { CommunitySafe } from 'lemmy-js-client';
|
||||
import { hostname, showAvatars } from '../utils';
|
||||
import { PictrsImage } from './pictrs-image';
|
||||
|
||||
interface CommunityOther {
|
||||
name: string;
|
||||
id?: number; // Necessary if its federated
|
||||
icon?: string;
|
||||
local?: boolean;
|
||||
actor_id?: string;
|
||||
}
|
||||
|
||||
interface CommunityLinkProps {
|
||||
community: Community | CommunityOther;
|
||||
// TODO figure this out better
|
||||
community: CommunitySafe;
|
||||
realLink?: boolean;
|
||||
useApubName?: boolean;
|
||||
muted?: boolean;
|
||||
|
|
|
@ -6,19 +6,18 @@ import {
|
|||
GetCommunityResponse,
|
||||
CommunityResponse,
|
||||
SortType,
|
||||
Post,
|
||||
GetPostsForm,
|
||||
GetCommunityForm,
|
||||
PostView,
|
||||
GetPosts,
|
||||
GetCommunity,
|
||||
ListingType,
|
||||
GetPostsResponse,
|
||||
PostResponse,
|
||||
AddModToCommunityResponse,
|
||||
BanFromCommunityResponse,
|
||||
Comment,
|
||||
GetCommentsForm,
|
||||
CommentView,
|
||||
GetComments,
|
||||
GetCommentsResponse,
|
||||
CommentResponse,
|
||||
WebSocketJsonResponse,
|
||||
GetSiteResponse,
|
||||
Category,
|
||||
ListCategoriesResponse,
|
||||
|
@ -50,8 +49,8 @@ import {
|
|||
setIsoData,
|
||||
wsSubscribe,
|
||||
isBrowser,
|
||||
setAuth,
|
||||
communityRSSUrl,
|
||||
wsUserOp,
|
||||
} from '../utils';
|
||||
import { i18n } from '../i18next';
|
||||
|
||||
|
@ -63,8 +62,8 @@ interface State {
|
|||
communityLoading: boolean;
|
||||
postsLoading: boolean;
|
||||
commentsLoading: boolean;
|
||||
posts: Post[];
|
||||
comments: Comment[];
|
||||
posts: PostView[];
|
||||
comments: CommentView[];
|
||||
dataType: DataType;
|
||||
sort: SortType;
|
||||
page: number;
|
||||
|
@ -98,7 +97,7 @@ export class Community extends Component<any, State> {
|
|||
dataType: getDataTypeFromProps(this.props),
|
||||
sort: getSortTypeFromProps(this.props),
|
||||
page: getPageFromProps(this.props),
|
||||
siteRes: this.isoData.site,
|
||||
siteRes: this.isoData.site_res,
|
||||
categories: [],
|
||||
};
|
||||
|
||||
|
@ -127,17 +126,18 @@ export class Community extends Component<any, State> {
|
|||
} else {
|
||||
this.fetchCommunity();
|
||||
this.fetchData();
|
||||
WebSocketService.Instance.listCategories();
|
||||
WebSocketService.Instance.client.listCategories();
|
||||
}
|
||||
setupTippy();
|
||||
}
|
||||
|
||||
fetchCommunity() {
|
||||
let form: GetCommunityForm = {
|
||||
let form: GetCommunity = {
|
||||
id: this.state.communityId ? this.state.communityId : null,
|
||||
name: this.state.communityName ? this.state.communityName : null,
|
||||
auth: UserService.Instance.authField(false),
|
||||
};
|
||||
WebSocketService.Instance.getCommunity(form);
|
||||
WebSocketService.Instance.client.getCommunity(form);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
|
@ -169,8 +169,8 @@ export class Community extends Component<any, State> {
|
|||
id = Number(idOrName);
|
||||
}
|
||||
|
||||
let communityForm: GetCommunityForm = id ? { id } : { name: name_ };
|
||||
setAuth(communityForm, req.auth);
|
||||
let communityForm: GetCommunity = id ? { id } : { name: name_ };
|
||||
communityForm.auth = req.auth;
|
||||
promises.push(req.client.getCommunity(communityForm));
|
||||
|
||||
let dataType: DataType = pathSplit[4]
|
||||
|
@ -186,24 +186,24 @@ export class Community extends Component<any, State> {
|
|||
let page = pathSplit[8] ? Number(pathSplit[8]) : 1;
|
||||
|
||||
if (dataType == DataType.Post) {
|
||||
let getPostsForm: GetPostsForm = {
|
||||
let getPostsForm: GetPosts = {
|
||||
page,
|
||||
limit: fetchLimit,
|
||||
sort,
|
||||
type_: ListingType.Community,
|
||||
auth: req.auth,
|
||||
};
|
||||
this.setIdOrName(getPostsForm, id, name_);
|
||||
setAuth(getPostsForm, req.auth);
|
||||
promises.push(req.client.getPosts(getPostsForm));
|
||||
} else {
|
||||
let getCommentsForm: GetCommentsForm = {
|
||||
let getCommentsForm: GetComments = {
|
||||
page,
|
||||
limit: fetchLimit,
|
||||
sort,
|
||||
type_: ListingType.Community,
|
||||
auth: req.auth,
|
||||
};
|
||||
this.setIdOrName(getCommentsForm, id, name_);
|
||||
setAuth(getCommentsForm, req.auth);
|
||||
promises.push(req.client.getComments(getCommentsForm));
|
||||
}
|
||||
|
||||
|
@ -232,10 +232,11 @@ export class Community extends Component<any, State> {
|
|||
}
|
||||
|
||||
get documentTitle(): string {
|
||||
return `${this.state.communityRes.community.title} - ${this.state.siteRes.site.name}`;
|
||||
return `${this.state.communityRes.community_view.community.title} - ${this.state.siteRes.site_view.site.name}`;
|
||||
}
|
||||
|
||||
render() {
|
||||
let cv = this.state.communityRes.community_view;
|
||||
return (
|
||||
<div class="container">
|
||||
{this.state.communityLoading ? (
|
||||
|
@ -250,8 +251,8 @@ export class Community extends Component<any, State> {
|
|||
<HtmlTags
|
||||
title={this.documentTitle}
|
||||
path={this.context.router.route.match.url}
|
||||
description={this.state.communityRes.community.description}
|
||||
image={this.state.communityRes.community.icon}
|
||||
description={cv.community.description}
|
||||
image={cv.community.icon}
|
||||
/>
|
||||
{this.communityInfo()}
|
||||
{this.selects()}
|
||||
|
@ -260,11 +261,11 @@ export class Community extends Component<any, State> {
|
|||
</div>
|
||||
<div class="col-12 col-md-4">
|
||||
<Sidebar
|
||||
community={this.state.communityRes.community}
|
||||
community_view={cv}
|
||||
moderators={this.state.communityRes.moderators}
|
||||
admins={this.state.siteRes.admins}
|
||||
online={this.state.communityRes.online}
|
||||
enableNsfw={this.state.siteRes.site.enable_nsfw}
|
||||
enableNsfw={this.state.siteRes.site_view.site.enable_nsfw}
|
||||
categories={this.state.categories}
|
||||
/>
|
||||
</div>
|
||||
|
@ -275,6 +276,7 @@ export class Community extends Component<any, State> {
|
|||
}
|
||||
|
||||
listings() {
|
||||
let site = this.state.siteRes.site_view.site;
|
||||
return this.state.dataType == DataType.Post ? (
|
||||
this.state.postsLoading ? (
|
||||
<h5>
|
||||
|
@ -287,8 +289,8 @@ export class Community extends Component<any, State> {
|
|||
posts={this.state.posts}
|
||||
removeDuplicates
|
||||
sort={this.state.sort}
|
||||
enableDownvotes={this.state.siteRes.site.enable_downvotes}
|
||||
enableNsfw={this.state.siteRes.site.enable_nsfw}
|
||||
enableDownvotes={site.enable_downvotes}
|
||||
enableNsfw={site.enable_nsfw}
|
||||
/>
|
||||
)
|
||||
) : this.state.commentsLoading ? (
|
||||
|
@ -303,21 +305,19 @@ export class Community extends Component<any, State> {
|
|||
noIndent
|
||||
sortType={this.state.sort}
|
||||
showContext
|
||||
enableDownvotes={this.state.siteRes.site.enable_downvotes}
|
||||
enableDownvotes={site.enable_downvotes}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
communityInfo() {
|
||||
let community = this.state.communityRes.community_view.community;
|
||||
return (
|
||||
<div>
|
||||
<BannerIconHeader
|
||||
banner={this.state.communityRes.community.banner}
|
||||
icon={this.state.communityRes.community.icon}
|
||||
/>
|
||||
<h5 class="mb-0">{this.state.communityRes.community.title}</h5>
|
||||
<BannerIconHeader banner={community.banner} icon={community.icon} />
|
||||
<h5 class="mb-0">{community.title}</h5>
|
||||
<CommunityLink
|
||||
community={this.state.communityRes.community}
|
||||
community={community}
|
||||
realLink
|
||||
useApubName
|
||||
muted
|
||||
|
@ -342,7 +342,7 @@ export class Community extends Component<any, State> {
|
|||
</span>
|
||||
<a
|
||||
href={communityRSSUrl(
|
||||
this.state.communityRes.community.actor_id,
|
||||
this.state.communityRes.community_view.community.actor_id,
|
||||
this.state.sort
|
||||
)}
|
||||
target="_blank"
|
||||
|
@ -405,137 +405,141 @@ export class Community extends Component<any, State> {
|
|||
const sortStr = paramUpdates.sort || this.state.sort;
|
||||
const page = paramUpdates.page || this.state.page;
|
||||
this.props.history.push(
|
||||
`/c/${this.state.communityRes.community.name}/data_type/${dataTypeStr}/sort/${sortStr}/page/${page}`
|
||||
`/c/${this.state.communityRes.community_view.community.name}/data_type/${dataTypeStr}/sort/${sortStr}/page/${page}`
|
||||
);
|
||||
}
|
||||
|
||||
fetchData() {
|
||||
if (this.state.dataType == DataType.Post) {
|
||||
let getPostsForm: GetPostsForm = {
|
||||
let form: GetPosts = {
|
||||
page: this.state.page,
|
||||
limit: fetchLimit,
|
||||
sort: this.state.sort,
|
||||
type_: ListingType.Community,
|
||||
community_id: this.state.communityId,
|
||||
community_name: this.state.communityName,
|
||||
auth: UserService.Instance.authField(false),
|
||||
};
|
||||
WebSocketService.Instance.getPosts(getPostsForm);
|
||||
WebSocketService.Instance.client.getPosts(form);
|
||||
} else {
|
||||
let getCommentsForm: GetCommentsForm = {
|
||||
let form: GetComments = {
|
||||
page: this.state.page,
|
||||
limit: fetchLimit,
|
||||
sort: this.state.sort,
|
||||
type_: ListingType.Community,
|
||||
community_id: this.state.communityId,
|
||||
community_name: this.state.communityName,
|
||||
auth: UserService.Instance.authField(false),
|
||||
};
|
||||
WebSocketService.Instance.getComments(getCommentsForm);
|
||||
WebSocketService.Instance.client.getComments(form);
|
||||
}
|
||||
}
|
||||
|
||||
parseMessage(msg: WebSocketJsonResponse) {
|
||||
console.log(msg);
|
||||
let res = wsJsonToRes(msg);
|
||||
parseMessage(msg: any) {
|
||||
let op = wsUserOp(msg);
|
||||
if (msg.error) {
|
||||
toast(i18n.t(msg.error), 'danger');
|
||||
this.context.router.history.push('/');
|
||||
return;
|
||||
} else if (msg.reconnect) {
|
||||
WebSocketService.Instance.communityJoin({
|
||||
community_id: this.state.communityRes.community.id,
|
||||
WebSocketService.Instance.client.communityJoin({
|
||||
community_id: this.state.communityRes.community_view.community.id,
|
||||
});
|
||||
this.fetchData();
|
||||
} else if (res.op == UserOperation.GetCommunity) {
|
||||
let data = res.data as GetCommunityResponse;
|
||||
} else if (op == UserOperation.GetCommunity) {
|
||||
let data = wsJsonToRes<GetCommunityResponse>(msg).data;
|
||||
this.state.communityRes = data;
|
||||
this.state.communityLoading = false;
|
||||
this.setState(this.state);
|
||||
WebSocketService.Instance.communityJoin({
|
||||
community_id: data.community.id,
|
||||
// TODO why is there no auth in this form?
|
||||
WebSocketService.Instance.client.communityJoin({
|
||||
community_id: data.community_view.community.id,
|
||||
});
|
||||
} else if (
|
||||
res.op == UserOperation.EditCommunity ||
|
||||
res.op == UserOperation.DeleteCommunity ||
|
||||
res.op == UserOperation.RemoveCommunity
|
||||
op == UserOperation.EditCommunity ||
|
||||
op == UserOperation.DeleteCommunity ||
|
||||
op == UserOperation.RemoveCommunity
|
||||
) {
|
||||
let data = res.data as CommunityResponse;
|
||||
this.state.communityRes.community = data.community;
|
||||
let data = wsJsonToRes<CommunityResponse>(msg).data;
|
||||
this.state.communityRes.community_view = data.community_view;
|
||||
this.setState(this.state);
|
||||
} else if (res.op == UserOperation.FollowCommunity) {
|
||||
let data = res.data as CommunityResponse;
|
||||
this.state.communityRes.community.subscribed = data.community.subscribed;
|
||||
this.state.communityRes.community.number_of_subscribers =
|
||||
data.community.number_of_subscribers;
|
||||
} else if (op == UserOperation.FollowCommunity) {
|
||||
let data = wsJsonToRes<CommunityResponse>(msg).data;
|
||||
this.state.communityRes.community_view.subscribed =
|
||||
data.community_view.subscribed;
|
||||
this.state.communityRes.community_view.counts.subscribers =
|
||||
data.community_view.counts.subscribers;
|
||||
this.setState(this.state);
|
||||
} else if (res.op == UserOperation.GetPosts) {
|
||||
let data = res.data as GetPostsResponse;
|
||||
} else if (op == UserOperation.GetPosts) {
|
||||
let data = wsJsonToRes<GetPostsResponse>(msg).data;
|
||||
this.state.posts = data.posts;
|
||||
this.state.postsLoading = false;
|
||||
this.setState(this.state);
|
||||
setupTippy();
|
||||
} else if (
|
||||
res.op == UserOperation.EditPost ||
|
||||
res.op == UserOperation.DeletePost ||
|
||||
res.op == UserOperation.RemovePost ||
|
||||
res.op == UserOperation.LockPost ||
|
||||
res.op == UserOperation.StickyPost ||
|
||||
res.op == UserOperation.SavePost
|
||||
op == UserOperation.EditPost ||
|
||||
op == UserOperation.DeletePost ||
|
||||
op == UserOperation.RemovePost ||
|
||||
op == UserOperation.LockPost ||
|
||||
op == UserOperation.StickyPost ||
|
||||
op == UserOperation.SavePost
|
||||
) {
|
||||
let data = res.data as PostResponse;
|
||||
editPostFindRes(data, this.state.posts);
|
||||
let data = wsJsonToRes<PostResponse>(msg).data;
|
||||
editPostFindRes(data.post_view, this.state.posts);
|
||||
this.setState(this.state);
|
||||
} else if (res.op == UserOperation.CreatePost) {
|
||||
let data = res.data as PostResponse;
|
||||
this.state.posts.unshift(data.post);
|
||||
notifyPost(data.post, this.context.router);
|
||||
} else if (op == UserOperation.CreatePost) {
|
||||
let data = wsJsonToRes<PostResponse>(msg).data;
|
||||
this.state.posts.unshift(data.post_view);
|
||||
notifyPost(data.post_view, this.context.router);
|
||||
this.setState(this.state);
|
||||
} else if (res.op == UserOperation.CreatePostLike) {
|
||||
let data = res.data as PostResponse;
|
||||
createPostLikeFindRes(data, this.state.posts);
|
||||
} else if (op == UserOperation.CreatePostLike) {
|
||||
let data = wsJsonToRes<PostResponse>(msg).data;
|
||||
createPostLikeFindRes(data.post_view, this.state.posts);
|
||||
this.setState(this.state);
|
||||
} else if (res.op == UserOperation.AddModToCommunity) {
|
||||
let data = res.data as AddModToCommunityResponse;
|
||||
} else if (op == UserOperation.AddModToCommunity) {
|
||||
let data = wsJsonToRes<AddModToCommunityResponse>(msg).data;
|
||||
this.state.communityRes.moderators = data.moderators;
|
||||
this.setState(this.state);
|
||||
} else if (res.op == UserOperation.BanFromCommunity) {
|
||||
let data = res.data as BanFromCommunityResponse;
|
||||
} else if (op == UserOperation.BanFromCommunity) {
|
||||
let data = wsJsonToRes<BanFromCommunityResponse>(msg).data;
|
||||
|
||||
// TODO this might be incorrect
|
||||
this.state.posts
|
||||
.filter(p => p.creator_id == data.user.id)
|
||||
.forEach(p => (p.banned = data.banned));
|
||||
.filter(p => p.creator.id == data.user_view.user.id)
|
||||
.forEach(p => (p.creator_banned_from_community = data.banned));
|
||||
|
||||
this.setState(this.state);
|
||||
} else if (res.op == UserOperation.GetComments) {
|
||||
let data = res.data as GetCommentsResponse;
|
||||
} else if (op == UserOperation.GetComments) {
|
||||
let data = wsJsonToRes<GetCommentsResponse>(msg).data;
|
||||
this.state.comments = data.comments;
|
||||
this.state.commentsLoading = false;
|
||||
this.setState(this.state);
|
||||
} else if (
|
||||
res.op == UserOperation.EditComment ||
|
||||
res.op == UserOperation.DeleteComment ||
|
||||
res.op == UserOperation.RemoveComment
|
||||
op == UserOperation.EditComment ||
|
||||
op == UserOperation.DeleteComment ||
|
||||
op == UserOperation.RemoveComment
|
||||
) {
|
||||
let data = res.data as CommentResponse;
|
||||
editCommentRes(data, this.state.comments);
|
||||
let data = wsJsonToRes<CommentResponse>(msg).data;
|
||||
editCommentRes(data.comment_view, this.state.comments);
|
||||
this.setState(this.state);
|
||||
} else if (res.op == UserOperation.CreateComment) {
|
||||
let data = res.data as CommentResponse;
|
||||
} else if (op == UserOperation.CreateComment) {
|
||||
let data = wsJsonToRes<CommentResponse>(msg).data;
|
||||
|
||||
// Necessary since it might be a user reply
|
||||
if (data.recipient_ids.length == 0) {
|
||||
this.state.comments.unshift(data.comment);
|
||||
this.state.comments.unshift(data.comment_view);
|
||||
this.setState(this.state);
|
||||
}
|
||||
} else if (res.op == UserOperation.SaveComment) {
|
||||
let data = res.data as CommentResponse;
|
||||
saveCommentRes(data, this.state.comments);
|
||||
} else if (op == UserOperation.SaveComment) {
|
||||
let data = wsJsonToRes<CommentResponse>(msg).data;
|
||||
saveCommentRes(data.comment_view, this.state.comments);
|
||||
this.setState(this.state);
|
||||
} else if (res.op == UserOperation.CreateCommentLike) {
|
||||
let data = res.data as CommentResponse;
|
||||
createCommentLikeRes(data, this.state.comments);
|
||||
} else if (op == UserOperation.CreateCommentLike) {
|
||||
let data = wsJsonToRes<CommentResponse>(msg).data;
|
||||
createCommentLikeRes(data.comment_view, this.state.comments);
|
||||
this.setState(this.state);
|
||||
} else if (res.op == UserOperation.ListCategories) {
|
||||
let data = res.data as ListCategoriesResponse;
|
||||
} else if (op == UserOperation.ListCategories) {
|
||||
let data = wsJsonToRes<ListCategoriesResponse>(msg).data;
|
||||
this.state.categories = data.categories;
|
||||
this.setState(this.state);
|
||||
}
|
||||
|
|
|
@ -3,10 +3,9 @@ import { Subscription } from 'rxjs';
|
|||
import { CommunityForm } from './community-form';
|
||||
import { HtmlTags } from './html-tags';
|
||||
import {
|
||||
Community,
|
||||
CommunityView,
|
||||
UserOperation,
|
||||
WebSocketJsonResponse,
|
||||
Site,
|
||||
SiteView,
|
||||
ListCategoriesResponse,
|
||||
Category,
|
||||
} from 'lemmy-js-client';
|
||||
|
@ -16,13 +15,14 @@ import {
|
|||
wsJsonToRes,
|
||||
wsSubscribe,
|
||||
isBrowser,
|
||||
wsUserOp,
|
||||
} from '../utils';
|
||||
import { WebSocketService, UserService } from '../services';
|
||||
import { i18n } from '../i18next';
|
||||
import { InitialFetchRequest } from 'shared/interfaces';
|
||||
|
||||
interface CreateCommunityState {
|
||||
site: Site;
|
||||
site_view: SiteView;
|
||||
categories: Category[];
|
||||
loading: boolean;
|
||||
}
|
||||
|
@ -31,7 +31,7 @@ export class CreateCommunity extends Component<any, CreateCommunityState> {
|
|||
private isoData = setIsoData(this.context);
|
||||
private subscription: Subscription;
|
||||
private emptyState: CreateCommunityState = {
|
||||
site: this.isoData.site.site,
|
||||
site_view: this.isoData.site_res.site_view,
|
||||
categories: [],
|
||||
loading: true,
|
||||
};
|
||||
|
@ -53,7 +53,7 @@ export class CreateCommunity extends Component<any, CreateCommunityState> {
|
|||
this.state.categories = this.isoData.routeData[0].categories;
|
||||
this.state.loading = false;
|
||||
} else {
|
||||
WebSocketService.Instance.listCategories();
|
||||
WebSocketService.Instance.client.listCategories();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -64,7 +64,7 @@ export class CreateCommunity extends Component<any, CreateCommunityState> {
|
|||
}
|
||||
|
||||
get documentTitle(): string {
|
||||
return `${i18n.t('create_community')} - ${this.state.site.name}`;
|
||||
return `${i18n.t('create_community')} - ${this.state.site_view.site.name}`;
|
||||
}
|
||||
|
||||
render() {
|
||||
|
@ -87,7 +87,7 @@ export class CreateCommunity extends Component<any, CreateCommunityState> {
|
|||
<CommunityForm
|
||||
categories={this.state.categories}
|
||||
onCreate={this.handleCommunityCreate}
|
||||
enableNsfw={this.state.site.enable_nsfw}
|
||||
enableNsfw={this.state.site_view.site.enable_nsfw}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -96,22 +96,21 @@ export class CreateCommunity extends Component<any, CreateCommunityState> {
|
|||
);
|
||||
}
|
||||
|
||||
handleCommunityCreate(community: Community) {
|
||||
this.props.history.push(`/c/${community.name}`);
|
||||
handleCommunityCreate(cv: CommunityView) {
|
||||
this.props.history.push(`/c/${cv.community.name}`);
|
||||
}
|
||||
|
||||
static fetchInitialData(req: InitialFetchRequest): Promise<any>[] {
|
||||
return [req.client.listCategories()];
|
||||
}
|
||||
|
||||
parseMessage(msg: WebSocketJsonResponse) {
|
||||
console.log(msg);
|
||||
let res = wsJsonToRes(msg);
|
||||
parseMessage(msg: any) {
|
||||
let op = wsUserOp(msg);
|
||||
if (msg.error) {
|
||||
// Toast errors are already handled by community-form
|
||||
return;
|
||||
} else if (res.op == UserOperation.ListCategories) {
|
||||
let data = res.data as ListCategoriesResponse;
|
||||
} else if (op == UserOperation.ListCategories) {
|
||||
let data = wsJsonToRes<ListCategoriesResponse>(msg).data;
|
||||
this.state.categories = data.categories;
|
||||
this.state.loading = false;
|
||||
this.setState(this.state);
|
||||
|
|
|
@ -4,29 +4,28 @@ import { PostForm } from './post-form';
|
|||
import { HtmlTags } from './html-tags';
|
||||
import {
|
||||
isBrowser,
|
||||
setAuth,
|
||||
setIsoData,
|
||||
toast,
|
||||
wsJsonToRes,
|
||||
wsSubscribe,
|
||||
wsUserOp,
|
||||
} from '../utils';
|
||||
import { UserService, WebSocketService } from '../services';
|
||||
import {
|
||||
UserOperation,
|
||||
PostFormParams,
|
||||
WebSocketJsonResponse,
|
||||
ListCommunitiesResponse,
|
||||
Community,
|
||||
Site,
|
||||
ListCommunitiesForm,
|
||||
CommunityView,
|
||||
SiteView,
|
||||
ListCommunities,
|
||||
SortType,
|
||||
PostView,
|
||||
} from 'lemmy-js-client';
|
||||
import { i18n } from '../i18next';
|
||||
import { InitialFetchRequest } from 'shared/interfaces';
|
||||
import { InitialFetchRequest, PostFormParams } from 'shared/interfaces';
|
||||
|
||||
interface CreatePostState {
|
||||
site: Site;
|
||||
communities: Community[];
|
||||
site_view: SiteView;
|
||||
communities: CommunityView[];
|
||||
loading: boolean;
|
||||
}
|
||||
|
||||
|
@ -34,7 +33,7 @@ export class CreatePost extends Component<any, CreatePostState> {
|
|||
private isoData = setIsoData(this.context);
|
||||
private subscription: Subscription;
|
||||
private emptyState: CreatePostState = {
|
||||
site: this.isoData.site.site,
|
||||
site_view: this.isoData.site_res.site_view,
|
||||
communities: [],
|
||||
loading: true,
|
||||
};
|
||||
|
@ -62,11 +61,12 @@ export class CreatePost extends Component<any, CreatePostState> {
|
|||
}
|
||||
|
||||
refetch() {
|
||||
let listCommunitiesForm: ListCommunitiesForm = {
|
||||
let listCommunitiesForm: ListCommunities = {
|
||||
sort: SortType.TopAll,
|
||||
limit: 9999,
|
||||
auth: UserService.Instance.authField(false),
|
||||
};
|
||||
WebSocketService.Instance.listCommunities(listCommunitiesForm);
|
||||
WebSocketService.Instance.client.listCommunities(listCommunitiesForm);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
|
@ -76,7 +76,7 @@ export class CreatePost extends Component<any, CreatePostState> {
|
|||
}
|
||||
|
||||
get documentTitle(): string {
|
||||
return `${i18n.t('create_post')} - ${this.state.site.name}`;
|
||||
return `${i18n.t('create_post')} - ${this.state.site_view.site.name}`;
|
||||
}
|
||||
|
||||
render() {
|
||||
|
@ -100,8 +100,8 @@ export class CreatePost extends Component<any, CreatePostState> {
|
|||
communities={this.state.communities}
|
||||
onCreate={this.handlePostCreate}
|
||||
params={this.params}
|
||||
enableDownvotes={this.state.site.enable_downvotes}
|
||||
enableNsfw={this.state.site.enable_nsfw}
|
||||
enableDownvotes={this.state.site_view.site.enable_downvotes}
|
||||
enableNsfw={this.state.site_view.site.enable_nsfw}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -149,27 +149,26 @@ export class CreatePost extends Component<any, CreatePostState> {
|
|||
return null;
|
||||
}
|
||||
|
||||
handlePostCreate(id: number) {
|
||||
this.props.history.push(`/post/${id}`);
|
||||
handlePostCreate(post_view: PostView) {
|
||||
this.props.history.push(`/post/${post_view.post.id}`);
|
||||
}
|
||||
|
||||
static fetchInitialData(req: InitialFetchRequest): Promise<any>[] {
|
||||
let listCommunitiesForm: ListCommunitiesForm = {
|
||||
let listCommunitiesForm: ListCommunities = {
|
||||
sort: SortType.TopAll,
|
||||
limit: 9999,
|
||||
auth: req.auth,
|
||||
};
|
||||
setAuth(listCommunitiesForm, req.auth);
|
||||
return [req.client.listCommunities(listCommunitiesForm)];
|
||||
}
|
||||
|
||||
parseMessage(msg: WebSocketJsonResponse) {
|
||||
console.log(msg);
|
||||
let res = wsJsonToRes(msg);
|
||||
parseMessage(msg: any) {
|
||||
let op = wsUserOp(msg);
|
||||
if (msg.error) {
|
||||
toast(i18n.t(msg.error), 'danger');
|
||||
return;
|
||||
} else if (res.op == UserOperation.ListCommunities) {
|
||||
let data = res.data as ListCommunitiesResponse;
|
||||
} else if (op == UserOperation.ListCommunities) {
|
||||
let data = wsJsonToRes<ListCommunitiesResponse>(msg).data;
|
||||
this.state.communities = data.communities;
|
||||
this.state.loading = false;
|
||||
this.setState(this.state);
|
||||
|
|
|
@ -4,22 +4,21 @@ import { PrivateMessageForm } from './private-message-form';
|
|||
import { HtmlTags } from './html-tags';
|
||||
import { UserService, WebSocketService } from '../services';
|
||||
import {
|
||||
Site,
|
||||
WebSocketJsonResponse,
|
||||
SiteView,
|
||||
UserOperation,
|
||||
UserDetailsResponse,
|
||||
UserView,
|
||||
GetUserDetailsResponse,
|
||||
UserViewSafe,
|
||||
SortType,
|
||||
GetUserDetailsForm,
|
||||
GetUserDetails,
|
||||
} from 'lemmy-js-client';
|
||||
import {
|
||||
getRecipientIdFromProps,
|
||||
isBrowser,
|
||||
setAuth,
|
||||
setIsoData,
|
||||
toast,
|
||||
wsJsonToRes,
|
||||
wsSubscribe,
|
||||
wsUserOp,
|
||||
} from '../utils';
|
||||
import { i18n } from '../i18next';
|
||||
import { InitialFetchRequest } from 'shared/interfaces';
|
||||
|
@ -27,8 +26,8 @@ import { InitialFetchRequest } from 'shared/interfaces';
|
|||
interface CreatePrivateMessageProps {}
|
||||
|
||||
interface CreatePrivateMessageState {
|
||||
site: Site;
|
||||
recipient: UserView;
|
||||
site_view: SiteView;
|
||||
recipient: UserViewSafe;
|
||||
recipient_id: number;
|
||||
loading: boolean;
|
||||
}
|
||||
|
@ -40,7 +39,7 @@ export class CreatePrivateMessage extends Component<
|
|||
private isoData = setIsoData(this.context);
|
||||
private subscription: Subscription;
|
||||
private emptyState: CreatePrivateMessageState = {
|
||||
site: this.isoData.site.site,
|
||||
site_view: this.isoData.site_res.site_view,
|
||||
recipient: undefined,
|
||||
recipient_id: getRecipientIdFromProps(this.props),
|
||||
loading: true,
|
||||
|
@ -70,27 +69,30 @@ export class CreatePrivateMessage extends Component<
|
|||
}
|
||||
|
||||
fetchUserDetails() {
|
||||
let form: GetUserDetailsForm = {
|
||||
let form: GetUserDetails = {
|
||||
user_id: this.state.recipient_id,
|
||||
sort: SortType.New,
|
||||
saved_only: false,
|
||||
auth: UserService.Instance.authField(false),
|
||||
};
|
||||
WebSocketService.Instance.getUserDetails(form);
|
||||
WebSocketService.Instance.client.getUserDetails(form);
|
||||
}
|
||||
|
||||
static fetchInitialData(req: InitialFetchRequest): Promise<any>[] {
|
||||
let user_id = Number(req.path.split('/').pop());
|
||||
let form: GetUserDetailsForm = {
|
||||
let form: GetUserDetails = {
|
||||
user_id,
|
||||
sort: SortType.New,
|
||||
saved_only: false,
|
||||
auth: req.auth,
|
||||
};
|
||||
setAuth(form, req.auth);
|
||||
return [req.client.getUserDetails(form)];
|
||||
}
|
||||
|
||||
get documentTitle(): string {
|
||||
return `${i18n.t('create_private_message')} - ${this.state.site.name}`;
|
||||
return `${i18n.t('create_private_message')} - ${
|
||||
this.state.site_view.site.name
|
||||
}`;
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
|
@ -118,7 +120,7 @@ export class CreatePrivateMessage extends Component<
|
|||
<h5>{i18n.t('create_private_message')}</h5>
|
||||
<PrivateMessageForm
|
||||
onCreate={this.handlePrivateMessageCreate}
|
||||
recipient={this.state.recipient}
|
||||
recipient={this.state.recipient.user}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -134,16 +136,16 @@ export class CreatePrivateMessage extends Component<
|
|||
this.context.router.history.push(`/`);
|
||||
}
|
||||
|
||||
parseMessage(msg: WebSocketJsonResponse) {
|
||||
let res = wsJsonToRes(msg);
|
||||
parseMessage(msg: any) {
|
||||
let op = wsUserOp(msg);
|
||||
if (msg.error) {
|
||||
toast(i18n.t(msg.error), 'danger');
|
||||
this.state.loading = false;
|
||||
this.setState(this.state);
|
||||
return;
|
||||
} else if (res.op == UserOperation.GetUserDetails) {
|
||||
let data = res.data as UserDetailsResponse;
|
||||
this.state.recipient = data.user;
|
||||
} else if (op == UserOperation.GetUserDetails) {
|
||||
let data = wsJsonToRes<GetUserDetailsResponse>(msg).data;
|
||||
this.state.recipient = data.user_view;
|
||||
this.state.loading = false;
|
||||
this.setState(this.state);
|
||||
}
|
||||
|
|
|
@ -2,26 +2,25 @@ import { Component, linkEvent } from 'inferno';
|
|||
import { Subscription } from 'rxjs';
|
||||
import {
|
||||
UserOperation,
|
||||
Comment,
|
||||
CommentView,
|
||||
SortType,
|
||||
GetRepliesForm,
|
||||
GetReplies,
|
||||
GetRepliesResponse,
|
||||
GetUserMentionsForm,
|
||||
GetUserMentions,
|
||||
GetUserMentionsResponse,
|
||||
UserMentionResponse,
|
||||
CommentResponse,
|
||||
WebSocketJsonResponse,
|
||||
PrivateMessage as PrivateMessageI,
|
||||
GetPrivateMessagesForm,
|
||||
PrivateMessageView,
|
||||
GetPrivateMessages,
|
||||
PrivateMessagesResponse,
|
||||
PrivateMessageResponse,
|
||||
Site,
|
||||
SiteView,
|
||||
UserMentionView,
|
||||
} from 'lemmy-js-client';
|
||||
import { WebSocketService, UserService } from '../services';
|
||||
import {
|
||||
wsJsonToRes,
|
||||
fetchLimit,
|
||||
isCommentType,
|
||||
toast,
|
||||
editCommentRes,
|
||||
saveCommentRes,
|
||||
|
@ -30,8 +29,8 @@ import {
|
|||
setupTippy,
|
||||
setIsoData,
|
||||
wsSubscribe,
|
||||
setAuth,
|
||||
isBrowser,
|
||||
wsUserOp,
|
||||
} from '../utils';
|
||||
import { CommentNodes } from './comment-nodes';
|
||||
import { PrivateMessage } from './private-message';
|
||||
|
@ -52,17 +51,27 @@ enum MessageType {
|
|||
Messages,
|
||||
}
|
||||
|
||||
type ReplyType = Comment | PrivateMessageI;
|
||||
enum ReplyEnum {
|
||||
Reply,
|
||||
Mention,
|
||||
Message,
|
||||
}
|
||||
type ReplyType = {
|
||||
id: number;
|
||||
type_: ReplyEnum;
|
||||
view: CommentView | PrivateMessageView | UserMentionView;
|
||||
published: string;
|
||||
};
|
||||
|
||||
interface InboxState {
|
||||
unreadOrAll: UnreadOrAll;
|
||||
messageType: MessageType;
|
||||
replies: Comment[];
|
||||
mentions: Comment[];
|
||||
messages: PrivateMessageI[];
|
||||
replies: CommentView[];
|
||||
mentions: UserMentionView[];
|
||||
messages: PrivateMessageView[];
|
||||
sort: SortType;
|
||||
page: number;
|
||||
site: Site;
|
||||
site_view: SiteView;
|
||||
loading: boolean;
|
||||
}
|
||||
|
||||
|
@ -77,7 +86,7 @@ export class Inbox extends Component<any, InboxState> {
|
|||
messages: [],
|
||||
sort: SortType.New,
|
||||
page: 1,
|
||||
site: this.isoData.site.site,
|
||||
site_view: this.isoData.site_res.site_view,
|
||||
loading: true,
|
||||
};
|
||||
|
||||
|
@ -115,7 +124,7 @@ export class Inbox extends Component<any, InboxState> {
|
|||
|
||||
get documentTitle(): string {
|
||||
return `@${UserService.Instance.user.name} ${i18n.t('inbox')} - ${
|
||||
this.state.site.name
|
||||
this.state.site_view.site.name
|
||||
}`;
|
||||
}
|
||||
|
||||
|
@ -288,33 +297,71 @@ export class Inbox extends Component<any, InboxState> {
|
|||
}
|
||||
|
||||
combined(): ReplyType[] {
|
||||
return [
|
||||
...this.state.replies,
|
||||
...this.state.mentions,
|
||||
...this.state.messages,
|
||||
].sort((a, b) => b.published.localeCompare(a.published));
|
||||
let id = 0;
|
||||
let replies: ReplyType[] = this.state.replies.map(r => ({
|
||||
id: id++,
|
||||
type_: ReplyEnum.Reply,
|
||||
view: r,
|
||||
published: r.comment.published,
|
||||
}));
|
||||
let mentions: ReplyType[] = this.state.mentions.map(r => ({
|
||||
id: id++,
|
||||
type_: ReplyEnum.Mention,
|
||||
view: r,
|
||||
published: r.comment.published,
|
||||
}));
|
||||
let messages: ReplyType[] = this.state.messages.map(r => ({
|
||||
id: id++,
|
||||
type_: ReplyEnum.Message,
|
||||
view: r,
|
||||
published: r.private_message.published,
|
||||
}));
|
||||
|
||||
return [...replies, ...mentions, ...messages].sort((a, b) =>
|
||||
b.published.localeCompare(a.published)
|
||||
);
|
||||
}
|
||||
|
||||
renderReplyType(i: ReplyType) {
|
||||
switch (i.type_) {
|
||||
case ReplyEnum.Reply:
|
||||
return (
|
||||
<CommentNodes
|
||||
key={i.id}
|
||||
nodes={[{ comment_view: i.view as CommentView }]}
|
||||
noIndent
|
||||
markable
|
||||
showCommunity
|
||||
showContext
|
||||
enableDownvotes={this.state.site_view.site.enable_downvotes}
|
||||
/>
|
||||
);
|
||||
case ReplyEnum.Mention:
|
||||
return (
|
||||
<CommentNodes
|
||||
key={i.id}
|
||||
nodes={[{ comment_view: i.view as UserMentionView }]}
|
||||
noIndent
|
||||
markable
|
||||
showCommunity
|
||||
showContext
|
||||
enableDownvotes={this.state.site_view.site.enable_downvotes}
|
||||
/>
|
||||
);
|
||||
case ReplyEnum.Message:
|
||||
return (
|
||||
<PrivateMessage
|
||||
key={i.id}
|
||||
private_message_view={i.view as PrivateMessageView}
|
||||
/>
|
||||
);
|
||||
default:
|
||||
return <div />;
|
||||
}
|
||||
}
|
||||
|
||||
all() {
|
||||
return (
|
||||
<div>
|
||||
{this.combined().map(i =>
|
||||
isCommentType(i) ? (
|
||||
<CommentNodes
|
||||
key={i.id}
|
||||
nodes={[{ comment: i }]}
|
||||
noIndent
|
||||
markable
|
||||
showCommunity
|
||||
showContext
|
||||
enableDownvotes={this.state.site.enable_downvotes}
|
||||
/>
|
||||
) : (
|
||||
<PrivateMessage key={i.id} privateMessage={i} />
|
||||
)
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
return <div>{this.combined().map(i => this.renderReplyType(i))}</div>;
|
||||
}
|
||||
|
||||
replies() {
|
||||
|
@ -326,7 +373,7 @@ export class Inbox extends Component<any, InboxState> {
|
|||
markable
|
||||
showCommunity
|
||||
showContext
|
||||
enableDownvotes={this.state.site.enable_downvotes}
|
||||
enableDownvotes={this.state.site_view.site.enable_downvotes}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
@ -335,15 +382,15 @@ export class Inbox extends Component<any, InboxState> {
|
|||
mentions() {
|
||||
return (
|
||||
<div>
|
||||
{this.state.mentions.map(mention => (
|
||||
{this.state.mentions.map(umv => (
|
||||
<CommentNodes
|
||||
key={mention.id}
|
||||
nodes={[{ comment: mention }]}
|
||||
key={umv.user_mention.id}
|
||||
nodes={[{ comment_view: umv }]}
|
||||
noIndent
|
||||
markable
|
||||
showCommunity
|
||||
showContext
|
||||
enableDownvotes={this.state.site.enable_downvotes}
|
||||
enableDownvotes={this.state.site_view.site.enable_downvotes}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
|
@ -353,8 +400,11 @@ export class Inbox extends Component<any, InboxState> {
|
|||
messages() {
|
||||
return (
|
||||
<div>
|
||||
{this.state.messages.map(message => (
|
||||
<PrivateMessage key={message.id} privateMessage={message} />
|
||||
{this.state.messages.map(pmv => (
|
||||
<PrivateMessage
|
||||
key={pmv.private_message.id}
|
||||
private_message_view={pmv}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
|
@ -413,58 +463,61 @@ export class Inbox extends Component<any, InboxState> {
|
|||
let promises: Promise<any>[] = [];
|
||||
|
||||
// It can be /u/me, or /username/1
|
||||
let repliesForm: GetRepliesForm = {
|
||||
let repliesForm: GetReplies = {
|
||||
sort: SortType.New,
|
||||
unread_only: true,
|
||||
page: 1,
|
||||
limit: fetchLimit,
|
||||
auth: req.auth,
|
||||
};
|
||||
setAuth(repliesForm, req.auth);
|
||||
promises.push(req.client.getReplies(repliesForm));
|
||||
|
||||
let userMentionsForm: GetUserMentionsForm = {
|
||||
let userMentionsForm: GetUserMentions = {
|
||||
sort: SortType.New,
|
||||
unread_only: true,
|
||||
page: 1,
|
||||
limit: fetchLimit,
|
||||
auth: req.auth,
|
||||
};
|
||||
setAuth(userMentionsForm, req.auth);
|
||||
promises.push(req.client.getUserMentions(userMentionsForm));
|
||||
|
||||
let privateMessagesForm: GetPrivateMessagesForm = {
|
||||
let privateMessagesForm: GetPrivateMessages = {
|
||||
unread_only: true,
|
||||
page: 1,
|
||||
limit: fetchLimit,
|
||||
auth: req.auth,
|
||||
};
|
||||
setAuth(privateMessagesForm, req.auth);
|
||||
promises.push(req.client.getPrivateMessages(privateMessagesForm));
|
||||
|
||||
return promises;
|
||||
}
|
||||
|
||||
refetch() {
|
||||
let repliesForm: GetRepliesForm = {
|
||||
let repliesForm: GetReplies = {
|
||||
sort: this.state.sort,
|
||||
unread_only: this.state.unreadOrAll == UnreadOrAll.Unread,
|
||||
page: this.state.page,
|
||||
limit: fetchLimit,
|
||||
auth: UserService.Instance.authField(),
|
||||
};
|
||||
WebSocketService.Instance.getReplies(repliesForm);
|
||||
WebSocketService.Instance.client.getReplies(repliesForm);
|
||||
|
||||
let userMentionsForm: GetUserMentionsForm = {
|
||||
let userMentionsForm: GetUserMentions = {
|
||||
sort: this.state.sort,
|
||||
unread_only: this.state.unreadOrAll == UnreadOrAll.Unread,
|
||||
page: this.state.page,
|
||||
limit: fetchLimit,
|
||||
auth: UserService.Instance.authField(),
|
||||
};
|
||||
WebSocketService.Instance.getUserMentions(userMentionsForm);
|
||||
WebSocketService.Instance.client.getUserMentions(userMentionsForm);
|
||||
|
||||
let privateMessagesForm: GetPrivateMessagesForm = {
|
||||
let privateMessagesForm: GetPrivateMessages = {
|
||||
unread_only: this.state.unreadOrAll == UnreadOrAll.Unread,
|
||||
page: this.state.page,
|
||||
limit: fetchLimit,
|
||||
auth: UserService.Instance.authField(),
|
||||
};
|
||||
WebSocketService.Instance.getPrivateMessages(privateMessagesForm);
|
||||
WebSocketService.Instance.client.getPrivateMessages(privateMessagesForm);
|
||||
}
|
||||
|
||||
handleSortChange(val: SortType) {
|
||||
|
@ -475,7 +528,9 @@ export class Inbox extends Component<any, InboxState> {
|
|||
}
|
||||
|
||||
markAllAsRead(i: Inbox) {
|
||||
WebSocketService.Instance.markAllAsRead();
|
||||
WebSocketService.Instance.client.markAllAsRead({
|
||||
auth: UserService.Instance.authField(),
|
||||
});
|
||||
i.state.replies = [];
|
||||
i.state.mentions = [];
|
||||
i.state.messages = [];
|
||||
|
@ -484,148 +539,182 @@ export class Inbox extends Component<any, InboxState> {
|
|||
i.setState(i.state);
|
||||
}
|
||||
|
||||
parseMessage(msg: WebSocketJsonResponse) {
|
||||
console.log(msg);
|
||||
let res = wsJsonToRes(msg);
|
||||
parseMessage(msg: any) {
|
||||
let op = wsUserOp(msg);
|
||||
if (msg.error) {
|
||||
toast(i18n.t(msg.error), 'danger');
|
||||
return;
|
||||
} else if (msg.reconnect) {
|
||||
this.refetch();
|
||||
} else if (res.op == UserOperation.GetReplies) {
|
||||
let data = res.data as GetRepliesResponse;
|
||||
} else if (op == UserOperation.GetReplies) {
|
||||
let data = wsJsonToRes<GetRepliesResponse>(msg).data;
|
||||
this.state.replies = data.replies;
|
||||
this.state.loading = false;
|
||||
this.sendUnreadCount();
|
||||
window.scrollTo(0, 0);
|
||||
this.setState(this.state);
|
||||
setupTippy();
|
||||
} else if (res.op == UserOperation.GetUserMentions) {
|
||||
let data = res.data as GetUserMentionsResponse;
|
||||
} else if (op == UserOperation.GetUserMentions) {
|
||||
let data = wsJsonToRes<GetUserMentionsResponse>(msg).data;
|
||||
this.state.mentions = data.mentions;
|
||||
this.sendUnreadCount();
|
||||
window.scrollTo(0, 0);
|
||||
this.setState(this.state);
|
||||
setupTippy();
|
||||
} else if (res.op == UserOperation.GetPrivateMessages) {
|
||||
let data = res.data as PrivateMessagesResponse;
|
||||
this.state.messages = data.messages;
|
||||
} else if (op == UserOperation.GetPrivateMessages) {
|
||||
let data = wsJsonToRes<PrivateMessagesResponse>(msg).data;
|
||||
this.state.messages = data.private_messages;
|
||||
this.sendUnreadCount();
|
||||
window.scrollTo(0, 0);
|
||||
this.setState(this.state);
|
||||
setupTippy();
|
||||
} else if (res.op == UserOperation.EditPrivateMessage) {
|
||||
let data = res.data as PrivateMessageResponse;
|
||||
let found: PrivateMessageI = this.state.messages.find(
|
||||
m => m.id === data.message.id
|
||||
} else if (op == UserOperation.EditPrivateMessage) {
|
||||
let data = wsJsonToRes<PrivateMessageResponse>(msg).data;
|
||||
let found: PrivateMessageView = this.state.messages.find(
|
||||
m =>
|
||||
m.private_message.id === data.private_message_view.private_message.id
|
||||
);
|
||||
if (found) {
|
||||
found.content = data.message.content;
|
||||
found.updated = data.message.updated;
|
||||
found.private_message.content =
|
||||
data.private_message_view.private_message.content;
|
||||
found.private_message.updated =
|
||||
data.private_message_view.private_message.updated;
|
||||
}
|
||||
this.setState(this.state);
|
||||
} else if (res.op == UserOperation.DeletePrivateMessage) {
|
||||
let data = res.data as PrivateMessageResponse;
|
||||
let found: PrivateMessageI = this.state.messages.find(
|
||||
m => m.id === data.message.id
|
||||
} else if (op == UserOperation.DeletePrivateMessage) {
|
||||
let data = wsJsonToRes<PrivateMessageResponse>(msg).data;
|
||||
let found: PrivateMessageView = this.state.messages.find(
|
||||
m =>
|
||||
m.private_message.id === data.private_message_view.private_message.id
|
||||
);
|
||||
if (found) {
|
||||
found.deleted = data.message.deleted;
|
||||
found.updated = data.message.updated;
|
||||
found.private_message.deleted =
|
||||
data.private_message_view.private_message.deleted;
|
||||
found.private_message.updated =
|
||||
data.private_message_view.private_message.updated;
|
||||
}
|
||||
this.setState(this.state);
|
||||
} else if (res.op == UserOperation.MarkPrivateMessageAsRead) {
|
||||
let data = res.data as PrivateMessageResponse;
|
||||
let found: PrivateMessageI = this.state.messages.find(
|
||||
m => m.id === data.message.id
|
||||
} else if (op == UserOperation.MarkPrivateMessageAsRead) {
|
||||
let data = wsJsonToRes<PrivateMessageResponse>(msg).data;
|
||||
let found: PrivateMessageView = this.state.messages.find(
|
||||
m =>
|
||||
m.private_message.id === data.private_message_view.private_message.id
|
||||
);
|
||||
|
||||
if (found) {
|
||||
found.updated = data.message.updated;
|
||||
found.private_message.updated =
|
||||
data.private_message_view.private_message.updated;
|
||||
|
||||
// If youre in the unread view, just remove it from the list
|
||||
if (this.state.unreadOrAll == UnreadOrAll.Unread && data.message.read) {
|
||||
if (
|
||||
this.state.unreadOrAll == UnreadOrAll.Unread &&
|
||||
data.private_message_view.private_message.read
|
||||
) {
|
||||
this.state.messages = this.state.messages.filter(
|
||||
r => r.id !== data.message.id
|
||||
r =>
|
||||
r.private_message.id !==
|
||||
data.private_message_view.private_message.id
|
||||
);
|
||||
} else {
|
||||
let found = this.state.messages.find(c => c.id == data.message.id);
|
||||
found.read = data.message.read;
|
||||
let found = this.state.messages.find(
|
||||
c =>
|
||||
c.private_message.id ==
|
||||
data.private_message_view.private_message.id
|
||||
);
|
||||
found.private_message.read =
|
||||
data.private_message_view.private_message.read;
|
||||
}
|
||||
}
|
||||
this.sendUnreadCount();
|
||||
this.setState(this.state);
|
||||
} else if (res.op == UserOperation.MarkAllAsRead) {
|
||||
} else if (op == UserOperation.MarkAllAsRead) {
|
||||
// Moved to be instant
|
||||
} else if (
|
||||
res.op == UserOperation.EditComment ||
|
||||
res.op == UserOperation.DeleteComment ||
|
||||
res.op == UserOperation.RemoveComment
|
||||
op == UserOperation.EditComment ||
|
||||
op == UserOperation.DeleteComment ||
|
||||
op == UserOperation.RemoveComment
|
||||
) {
|
||||
let data = res.data as CommentResponse;
|
||||
editCommentRes(data, this.state.replies);
|
||||
let data = wsJsonToRes<CommentResponse>(msg).data;
|
||||
editCommentRes(data.comment_view, this.state.replies);
|
||||
this.setState(this.state);
|
||||
} else if (res.op == UserOperation.MarkCommentAsRead) {
|
||||
let data = res.data as CommentResponse;
|
||||
} else if (op == UserOperation.MarkCommentAsRead) {
|
||||
let data = wsJsonToRes<CommentResponse>(msg).data;
|
||||
|
||||
// If youre in the unread view, just remove it from the list
|
||||
if (this.state.unreadOrAll == UnreadOrAll.Unread && data.comment.read) {
|
||||
if (
|
||||
this.state.unreadOrAll == UnreadOrAll.Unread &&
|
||||
data.comment_view.comment.read
|
||||
) {
|
||||
this.state.replies = this.state.replies.filter(
|
||||
r => r.id !== data.comment.id
|
||||
r => r.comment.id !== data.comment_view.comment.id
|
||||
);
|
||||
} else {
|
||||
let found = this.state.replies.find(c => c.id == data.comment.id);
|
||||
found.read = data.comment.read;
|
||||
let found = this.state.replies.find(
|
||||
c => c.comment.id == data.comment_view.comment.id
|
||||
);
|
||||
found.comment.read = data.comment_view.comment.read;
|
||||
}
|
||||
this.sendUnreadCount();
|
||||
this.setState(this.state);
|
||||
setupTippy();
|
||||
} else if (res.op == UserOperation.MarkUserMentionAsRead) {
|
||||
let data = res.data as UserMentionResponse;
|
||||
} else if (op == UserOperation.MarkUserMentionAsRead) {
|
||||
let data = wsJsonToRes<UserMentionResponse>(msg).data;
|
||||
|
||||
let found = this.state.mentions.find(c => c.id == data.mention.id);
|
||||
found.content = data.mention.content;
|
||||
found.updated = data.mention.updated;
|
||||
found.removed = data.mention.removed;
|
||||
found.deleted = data.mention.deleted;
|
||||
found.upvotes = data.mention.upvotes;
|
||||
found.downvotes = data.mention.downvotes;
|
||||
found.score = data.mention.score;
|
||||
// TODO this might not be correct, it might need to use the comment id
|
||||
let found = this.state.mentions.find(
|
||||
c => c.user_mention.id == data.user_mention_view.user_mention.id
|
||||
);
|
||||
found.comment.content = data.user_mention_view.comment.content;
|
||||
found.comment.updated = data.user_mention_view.comment.updated;
|
||||
found.comment.removed = data.user_mention_view.comment.removed;
|
||||
found.comment.deleted = data.user_mention_view.comment.deleted;
|
||||
found.counts.upvotes = data.user_mention_view.counts.upvotes;
|
||||
found.counts.downvotes = data.user_mention_view.counts.downvotes;
|
||||
found.counts.score = data.user_mention_view.counts.score;
|
||||
|
||||
// If youre in the unread view, just remove it from the list
|
||||
if (this.state.unreadOrAll == UnreadOrAll.Unread && data.mention.read) {
|
||||
if (
|
||||
this.state.unreadOrAll == UnreadOrAll.Unread &&
|
||||
data.user_mention_view.user_mention.read
|
||||
) {
|
||||
this.state.mentions = this.state.mentions.filter(
|
||||
r => r.id !== data.mention.id
|
||||
r => r.user_mention.id !== data.user_mention_view.user_mention.id
|
||||
);
|
||||
} else {
|
||||
let found = this.state.mentions.find(c => c.id == data.mention.id);
|
||||
found.read = data.mention.read;
|
||||
let found = this.state.mentions.find(
|
||||
c => c.user_mention.id == data.user_mention_view.user_mention.id
|
||||
);
|
||||
// TODO test to make sure these mentions are getting marked as read
|
||||
found.user_mention.read = data.user_mention_view.user_mention.read;
|
||||
}
|
||||
this.sendUnreadCount();
|
||||
this.setState(this.state);
|
||||
} else if (res.op == UserOperation.CreateComment) {
|
||||
let data = res.data as CommentResponse;
|
||||
} else if (op == UserOperation.CreateComment) {
|
||||
let data = wsJsonToRes<CommentResponse>(msg).data;
|
||||
|
||||
if (data.recipient_ids.includes(UserService.Instance.user.id)) {
|
||||
this.state.replies.unshift(data.comment);
|
||||
this.state.replies.unshift(data.comment_view);
|
||||
this.setState(this.state);
|
||||
} else if (data.comment.creator_id == UserService.Instance.user.id) {
|
||||
} else if (data.comment_view.creator.id == UserService.Instance.user.id) {
|
||||
// TODO this seems wrong, you should be using form_id
|
||||
toast(i18n.t('reply_sent'));
|
||||
}
|
||||
} else if (res.op == UserOperation.CreatePrivateMessage) {
|
||||
let data = res.data as PrivateMessageResponse;
|
||||
if (data.message.recipient_id == UserService.Instance.user.id) {
|
||||
this.state.messages.unshift(data.message);
|
||||
} else if (op == UserOperation.CreatePrivateMessage) {
|
||||
let data = wsJsonToRes<PrivateMessageResponse>(msg).data;
|
||||
if (
|
||||
data.private_message_view.recipient.id == UserService.Instance.user.id
|
||||
) {
|
||||
this.state.messages.unshift(data.private_message_view);
|
||||
this.setState(this.state);
|
||||
}
|
||||
} else if (res.op == UserOperation.SaveComment) {
|
||||
let data = res.data as CommentResponse;
|
||||
saveCommentRes(data, this.state.replies);
|
||||
} else if (op == UserOperation.SaveComment) {
|
||||
let data = wsJsonToRes<CommentResponse>(msg).data;
|
||||
saveCommentRes(data.comment_view, this.state.replies);
|
||||
this.setState(this.state);
|
||||
setupTippy();
|
||||
} else if (res.op == UserOperation.CreateCommentLike) {
|
||||
let data = res.data as CommentResponse;
|
||||
createCommentLikeRes(data, this.state.replies);
|
||||
} else if (op == UserOperation.CreateCommentLike) {
|
||||
let data = wsJsonToRes<CommentResponse>(msg).data;
|
||||
createCommentLikeRes(data.comment_view, this.state.replies);
|
||||
this.setState(this.state);
|
||||
}
|
||||
}
|
||||
|
@ -636,13 +725,14 @@ export class Inbox extends Component<any, InboxState> {
|
|||
|
||||
unreadCount(): number {
|
||||
return (
|
||||
this.state.replies.filter(r => !r.read).length +
|
||||
this.state.mentions.filter(r => !r.read).length +
|
||||
this.state.replies.filter(r => !r.comment.read).length +
|
||||
this.state.mentions.filter(r => !r.user_mention.read).length +
|
||||
this.state.messages.filter(
|
||||
r =>
|
||||
UserService.Instance.user &&
|
||||
!r.read &&
|
||||
r.creator_id !== UserService.Instance.user.id
|
||||
!r.private_message.read &&
|
||||
// TODO also seems very strang and wrong
|
||||
r.creator.id !== UserService.Instance.user.id
|
||||
).length
|
||||
);
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ interface InstancesState {
|
|||
export class Instances extends Component<any, InstancesState> {
|
||||
private isoData = setIsoData(this.context);
|
||||
private emptyState: InstancesState = {
|
||||
siteRes: this.isoData.site,
|
||||
siteRes: this.isoData.site_res,
|
||||
};
|
||||
|
||||
constructor(props: any, context: any) {
|
||||
|
@ -20,7 +20,7 @@ export class Instances extends Component<any, InstancesState> {
|
|||
}
|
||||
|
||||
get documentTitle(): string {
|
||||
return `${i18n.t('instances')} - ${this.state.siteRes.site.name}`;
|
||||
return `${i18n.t('instances')} - ${this.state.siteRes.site_view.site.name}`;
|
||||
}
|
||||
|
||||
render() {
|
||||
|
|
|
@ -1,15 +1,14 @@
|
|||
import { Component, linkEvent } from 'inferno';
|
||||
import { Subscription } from 'rxjs';
|
||||
import {
|
||||
LoginForm,
|
||||
RegisterForm,
|
||||
Login as LoginForm,
|
||||
Register,
|
||||
LoginResponse,
|
||||
UserOperation,
|
||||
PasswordResetForm,
|
||||
PasswordReset,
|
||||
GetSiteResponse,
|
||||
GetCaptchaResponse,
|
||||
WebSocketJsonResponse,
|
||||
Site,
|
||||
SiteView,
|
||||
} from 'lemmy-js-client';
|
||||
import { WebSocketService, UserService } from '../services';
|
||||
import {
|
||||
|
@ -19,18 +18,19 @@ import {
|
|||
wsSubscribe,
|
||||
isBrowser,
|
||||
setIsoData,
|
||||
wsUserOp,
|
||||
} from '../utils';
|
||||
import { i18n } from '../i18next';
|
||||
import { HtmlTags } from './html-tags';
|
||||
|
||||
interface State {
|
||||
loginForm: LoginForm;
|
||||
registerForm: RegisterForm;
|
||||
registerForm: Register;
|
||||
loginLoading: boolean;
|
||||
registerLoading: boolean;
|
||||
captcha: GetCaptchaResponse;
|
||||
captchaPlaying: boolean;
|
||||
site: Site;
|
||||
site_view: SiteView;
|
||||
}
|
||||
|
||||
export class Login extends Component<any, State> {
|
||||
|
@ -55,7 +55,7 @@ export class Login extends Component<any, State> {
|
|||
registerLoading: false,
|
||||
captcha: undefined,
|
||||
captchaPlaying: false,
|
||||
site: this.isoData.site.site,
|
||||
site_view: this.isoData.site_res.site_view,
|
||||
};
|
||||
|
||||
constructor(props: any, context: any) {
|
||||
|
@ -67,7 +67,7 @@ export class Login extends Component<any, State> {
|
|||
this.subscription = wsSubscribe(this.parseMessage);
|
||||
|
||||
if (isBrowser()) {
|
||||
WebSocketService.Instance.getCaptcha();
|
||||
WebSocketService.Instance.client.getCaptcha();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -78,7 +78,7 @@ export class Login extends Component<any, State> {
|
|||
}
|
||||
|
||||
get documentTitle(): string {
|
||||
return `${i18n.t('login')} - ${this.state.site.name}`;
|
||||
return `${i18n.t('login')} - ${this.state.site_view.site.name}`;
|
||||
}
|
||||
|
||||
render() {
|
||||
|
@ -280,7 +280,7 @@ export class Login extends Component<any, State> {
|
|||
</div>
|
||||
</div>
|
||||
)}
|
||||
{this.state.site.enable_nsfw && (
|
||||
{this.state.site_view.site.enable_nsfw && (
|
||||
<div class="form-group row">
|
||||
<div class="col-sm-10">
|
||||
<div class="form-check">
|
||||
|
@ -349,7 +349,7 @@ export class Login extends Component<any, State> {
|
|||
event.preventDefault();
|
||||
i.state.loginLoading = true;
|
||||
i.setState(i.state);
|
||||
WebSocketService.Instance.login(i.state.loginForm);
|
||||
WebSocketService.Instance.client.login(i.state.loginForm);
|
||||
}
|
||||
|
||||
handleLoginUsernameChange(i: Login, event: any) {
|
||||
|
@ -366,7 +366,7 @@ export class Login extends Component<any, State> {
|
|||
event.preventDefault();
|
||||
i.state.registerLoading = true;
|
||||
i.setState(i.state);
|
||||
WebSocketService.Instance.register(i.state.registerForm);
|
||||
WebSocketService.Instance.client.register(i.state.registerForm);
|
||||
}
|
||||
|
||||
handleRegisterUsernameChange(i: Login, event: any) {
|
||||
|
@ -404,15 +404,15 @@ export class Login extends Component<any, State> {
|
|||
|
||||
handleRegenCaptcha(_i: Login, event: any) {
|
||||
event.preventDefault();
|
||||
WebSocketService.Instance.getCaptcha();
|
||||
WebSocketService.Instance.client.getCaptcha();
|
||||
}
|
||||
|
||||
handlePasswordReset(i: Login, event: any) {
|
||||
event.preventDefault();
|
||||
let resetForm: PasswordResetForm = {
|
||||
let resetForm: PasswordReset = {
|
||||
email: i.state.loginForm.username_or_email,
|
||||
};
|
||||
WebSocketService.Instance.passwordReset(resetForm);
|
||||
WebSocketService.Instance.client.passwordReset(resetForm);
|
||||
}
|
||||
|
||||
handleCaptchaPlay(i: Login, event: any) {
|
||||
|
@ -432,44 +432,48 @@ export class Login extends Component<any, State> {
|
|||
return `data:image/png;base64,${this.state.captcha.ok.png}`;
|
||||
}
|
||||
|
||||
parseMessage(msg: WebSocketJsonResponse) {
|
||||
let res = wsJsonToRes(msg);
|
||||
parseMessage(msg: any) {
|
||||
let op = wsUserOp(msg);
|
||||
if (msg.error) {
|
||||
toast(i18n.t(msg.error), 'danger');
|
||||
this.state = this.emptyState;
|
||||
this.state.registerForm.captcha_answer = undefined;
|
||||
// Refetch another captcha
|
||||
WebSocketService.Instance.getCaptcha();
|
||||
WebSocketService.Instance.client.getCaptcha();
|
||||
this.setState(this.state);
|
||||
return;
|
||||
} else {
|
||||
if (res.op == UserOperation.Login) {
|
||||
let data = res.data as LoginResponse;
|
||||
if (op == UserOperation.Login) {
|
||||
let data = wsJsonToRes<LoginResponse>(msg).data;
|
||||
this.state = this.emptyState;
|
||||
this.setState(this.state);
|
||||
UserService.Instance.login(data);
|
||||
WebSocketService.Instance.userJoin();
|
||||
WebSocketService.Instance.client.userJoin({
|
||||
auth: UserService.Instance.authField(),
|
||||
});
|
||||
toast(i18n.t('logged_in'));
|
||||
this.props.history.push('/');
|
||||
} else if (res.op == UserOperation.Register) {
|
||||
let data = res.data as LoginResponse;
|
||||
} else if (op == UserOperation.Register) {
|
||||
let data = wsJsonToRes<LoginResponse>(msg).data;
|
||||
this.state = this.emptyState;
|
||||
this.setState(this.state);
|
||||
UserService.Instance.login(data);
|
||||
WebSocketService.Instance.userJoin();
|
||||
WebSocketService.Instance.client.userJoin({
|
||||
auth: UserService.Instance.authField(),
|
||||
});
|
||||
this.props.history.push('/communities');
|
||||
} else if (res.op == UserOperation.GetCaptcha) {
|
||||
let data = res.data as GetCaptchaResponse;
|
||||
} else if (op == UserOperation.GetCaptcha) {
|
||||
let data = wsJsonToRes<GetCaptchaResponse>(msg).data;
|
||||
if (data.ok) {
|
||||
this.state.captcha = data;
|
||||
this.state.registerForm.captcha_uuid = data.ok.uuid;
|
||||
this.setState(this.state);
|
||||
}
|
||||
} else if (res.op == UserOperation.PasswordReset) {
|
||||
} else if (op == UserOperation.PasswordReset) {
|
||||
toast(i18n.t('reset_password_mail_sent'));
|
||||
} else if (res.op == UserOperation.GetSite) {
|
||||
let data = res.data as GetSiteResponse;
|
||||
this.state.site = data.site;
|
||||
} else if (op == UserOperation.GetSite) {
|
||||
let data = wsJsonToRes<GetSiteResponse>(msg).data;
|
||||
this.state.site_view = data.site_view;
|
||||
this.setState(this.state);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,26 +3,25 @@ import { Link } from 'inferno-router';
|
|||
import { Subscription } from 'rxjs';
|
||||
import {
|
||||
UserOperation,
|
||||
CommunityUser,
|
||||
CommunityFollowerView,
|
||||
GetFollowedCommunitiesResponse,
|
||||
ListCommunitiesForm,
|
||||
ListCommunities,
|
||||
ListCommunitiesResponse,
|
||||
Community,
|
||||
CommunityView,
|
||||
SortType,
|
||||
GetSiteResponse,
|
||||
ListingType,
|
||||
SiteResponse,
|
||||
GetPostsResponse,
|
||||
PostResponse,
|
||||
Post,
|
||||
GetPostsForm,
|
||||
Comment,
|
||||
GetCommentsForm,
|
||||
PostView,
|
||||
GetPosts,
|
||||
CommentView,
|
||||
GetComments,
|
||||
GetCommentsResponse,
|
||||
CommentResponse,
|
||||
AddAdminResponse,
|
||||
BanUserResponse,
|
||||
WebSocketJsonResponse,
|
||||
} from 'lemmy-js-client';
|
||||
import { DataType, InitialFetchRequest } from '../interfaces';
|
||||
import { WebSocketService, UserService } from '../services';
|
||||
|
@ -55,20 +54,20 @@ import {
|
|||
setIsoData,
|
||||
wsSubscribe,
|
||||
isBrowser,
|
||||
setAuth,
|
||||
wsUserOp,
|
||||
} from '../utils';
|
||||
import { i18n } from '../i18next';
|
||||
import { T } from 'inferno-i18next';
|
||||
import { HtmlTags } from './html-tags';
|
||||
|
||||
interface MainState {
|
||||
subscribedCommunities: CommunityUser[];
|
||||
trendingCommunities: Community[];
|
||||
subscribedCommunities: CommunityFollowerView[];
|
||||
trendingCommunities: CommunityView[];
|
||||
siteRes: GetSiteResponse;
|
||||
showEditSite: boolean;
|
||||
loading: boolean;
|
||||
posts: Post[];
|
||||
comments: Comment[];
|
||||
posts: PostView[];
|
||||
comments: CommentView[];
|
||||
listingType: ListingType;
|
||||
dataType: DataType;
|
||||
sort: SortType;
|
||||
|
@ -95,7 +94,7 @@ export class Main extends Component<any, MainState> {
|
|||
private emptyState: MainState = {
|
||||
subscribedCommunities: [],
|
||||
trendingCommunities: [],
|
||||
siteRes: this.isoData.site,
|
||||
siteRes: this.isoData.site_res,
|
||||
showEditSite: false,
|
||||
loading: true,
|
||||
posts: [],
|
||||
|
@ -134,7 +133,9 @@ export class Main extends Component<any, MainState> {
|
|||
this.fetchTrendingCommunities();
|
||||
this.fetchData();
|
||||
if (UserService.Instance.user) {
|
||||
WebSocketService.Instance.getFollowedCommunities();
|
||||
WebSocketService.Instance.client.getFollowedCommunities({
|
||||
auth: UserService.Instance.authField(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -142,20 +143,21 @@ export class Main extends Component<any, MainState> {
|
|||
}
|
||||
|
||||
fetchTrendingCommunities() {
|
||||
let listCommunitiesForm: ListCommunitiesForm = {
|
||||
let listCommunitiesForm: ListCommunities = {
|
||||
sort: SortType.Hot,
|
||||
limit: 6,
|
||||
auth: UserService.Instance.authField(false),
|
||||
};
|
||||
WebSocketService.Instance.listCommunities(listCommunitiesForm);
|
||||
WebSocketService.Instance.client.listCommunities(listCommunitiesForm);
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
// This means it hasn't been set up yet
|
||||
if (!this.state.siteRes.site) {
|
||||
if (!this.state.siteRes.site_view) {
|
||||
this.context.router.history.push('/setup');
|
||||
}
|
||||
|
||||
WebSocketService.Instance.communityJoin({ community_id: 0 });
|
||||
WebSocketService.Instance.client.communityJoin({ community_id: 0 });
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
|
@ -199,26 +201,26 @@ export class Main extends Component<any, MainState> {
|
|||
let promises: Promise<any>[] = [];
|
||||
|
||||
if (dataType == DataType.Post) {
|
||||
let getPostsForm: GetPostsForm = {
|
||||
let getPostsForm: GetPosts = {
|
||||
page,
|
||||
limit: fetchLimit,
|
||||
sort,
|
||||
type_,
|
||||
auth: req.auth,
|
||||
};
|
||||
setAuth(getPostsForm, req.auth);
|
||||
promises.push(req.client.getPosts(getPostsForm));
|
||||
} else {
|
||||
let getCommentsForm: GetCommentsForm = {
|
||||
let getCommentsForm: GetComments = {
|
||||
page,
|
||||
limit: fetchLimit,
|
||||
sort,
|
||||
type_,
|
||||
auth: req.auth,
|
||||
};
|
||||
setAuth(getCommentsForm, req.auth);
|
||||
promises.push(req.client.getComments(getCommentsForm));
|
||||
}
|
||||
|
||||
let trendingCommunitiesForm: ListCommunitiesForm = {
|
||||
let trendingCommunitiesForm: ListCommunities = {
|
||||
sort: SortType.Hot,
|
||||
limit: 6,
|
||||
};
|
||||
|
@ -245,7 +247,9 @@ export class Main extends Component<any, MainState> {
|
|||
|
||||
get documentTitle(): string {
|
||||
return `${
|
||||
this.state.siteRes.site ? this.state.siteRes.site.name : 'Lemmy'
|
||||
this.state.siteRes.site_view
|
||||
? this.state.siteRes.site_view.site.name
|
||||
: 'Lemmy'
|
||||
}`;
|
||||
}
|
||||
|
||||
|
@ -256,7 +260,7 @@ export class Main extends Component<any, MainState> {
|
|||
title={this.documentTitle}
|
||||
path={this.context.router.route.match.url}
|
||||
/>
|
||||
{this.state.siteRes.site && (
|
||||
{this.state.siteRes.site_view.site && (
|
||||
<div class="row">
|
||||
<main role="main" class="col-12 col-md-8">
|
||||
{this.posts()}
|
||||
|
@ -316,9 +320,9 @@ export class Main extends Component<any, MainState> {
|
|||
</T>
|
||||
</h5>
|
||||
<ul class="list-inline">
|
||||
{this.state.trendingCommunities.map(community => (
|
||||
{this.state.trendingCommunities.map(cv => (
|
||||
<li class="list-inline-item d-inline">
|
||||
<CommunityLink community={community} />
|
||||
<CommunityLink community={cv.community} />
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
|
@ -338,17 +342,9 @@ export class Main extends Component<any, MainState> {
|
|||
</T>
|
||||
</h5>
|
||||
<ul class="list-inline mb-0">
|
||||
{this.state.subscribedCommunities.map(community => (
|
||||
{this.state.subscribedCommunities.map(cfv => (
|
||||
<li class="list-inline-item d-inline">
|
||||
<CommunityLink
|
||||
community={{
|
||||
name: community.community_name,
|
||||
id: community.community_id,
|
||||
local: community.community_local,
|
||||
actor_id: community.community_actor_id,
|
||||
icon: community.community_icon,
|
||||
}}
|
||||
/>
|
||||
<CommunityLink community={cfv.community} />
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
|
@ -357,6 +353,7 @@ export class Main extends Component<any, MainState> {
|
|||
}
|
||||
|
||||
sidebar() {
|
||||
let site = this.state.siteRes.site_view.site;
|
||||
return (
|
||||
<div>
|
||||
{!this.state.showEditSite ? (
|
||||
|
@ -365,14 +362,11 @@ export class Main extends Component<any, MainState> {
|
|||
{this.siteName()}
|
||||
{this.adminButtons()}
|
||||
</div>
|
||||
<BannerIconHeader banner={this.state.siteRes.site.banner} />
|
||||
<BannerIconHeader banner={site.banner} />
|
||||
{this.siteInfo()}
|
||||
</div>
|
||||
) : (
|
||||
<SiteForm
|
||||
site={this.state.siteRes.site}
|
||||
onCancel={this.handleEditCancel}
|
||||
/>
|
||||
<SiteForm site={site} onCancel={this.handleEditCancel} />
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
|
@ -391,7 +385,8 @@ export class Main extends Component<any, MainState> {
|
|||
siteInfo() {
|
||||
return (
|
||||
<div>
|
||||
{this.state.siteRes.site.description && this.siteDescription()}
|
||||
{this.state.siteRes.site_view.site.description &&
|
||||
this.siteDescription()}
|
||||
{this.badges()}
|
||||
{this.admins()}
|
||||
</div>
|
||||
|
@ -406,18 +401,9 @@ export class Main extends Component<any, MainState> {
|
|||
return (
|
||||
<ul class="mt-1 list-inline small mb-0">
|
||||
<li class="list-inline-item">{i18n.t('admins')}:</li>
|
||||
{this.state.siteRes.admins.map(admin => (
|
||||
{this.state.siteRes.admins.map(av => (
|
||||
<li class="list-inline-item">
|
||||
<UserListing
|
||||
user={{
|
||||
name: admin.name,
|
||||
preferred_username: admin.preferred_username,
|
||||
avatar: admin.avatar,
|
||||
local: admin.local,
|
||||
actor_id: admin.actor_id,
|
||||
id: admin.id,
|
||||
}}
|
||||
/>
|
||||
<UserListing user={av.user} />
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
|
@ -425,6 +411,7 @@ export class Main extends Component<any, MainState> {
|
|||
}
|
||||
|
||||
badges() {
|
||||
let site_view = this.state.siteRes.site_view;
|
||||
return (
|
||||
<ul class="my-2 list-inline">
|
||||
<li className="list-inline-item badge badge-secondary">
|
||||
|
@ -432,22 +419,22 @@ export class Main extends Component<any, MainState> {
|
|||
</li>
|
||||
<li className="list-inline-item badge badge-secondary">
|
||||
{i18n.t('number_of_users', {
|
||||
count: this.state.siteRes.site.number_of_users,
|
||||
count: site_view.counts.users,
|
||||
})}
|
||||
</li>
|
||||
<li className="list-inline-item badge badge-secondary">
|
||||
{i18n.t('number_of_communities', {
|
||||
count: this.state.siteRes.site.number_of_communities,
|
||||
count: site_view.counts.communities,
|
||||
})}
|
||||
</li>
|
||||
<li className="list-inline-item badge badge-secondary">
|
||||
{i18n.t('number_of_posts', {
|
||||
count: this.state.siteRes.site.number_of_posts,
|
||||
count: site_view.counts.posts,
|
||||
})}
|
||||
</li>
|
||||
<li className="list-inline-item badge badge-secondary">
|
||||
{i18n.t('number_of_comments', {
|
||||
count: this.state.siteRes.site.number_of_comments,
|
||||
count: site_view.counts.comments,
|
||||
})}
|
||||
</li>
|
||||
<li className="list-inline-item">
|
||||
|
@ -483,7 +470,9 @@ export class Main extends Component<any, MainState> {
|
|||
return (
|
||||
<div
|
||||
className="md-div"
|
||||
dangerouslySetInnerHTML={mdToHtml(this.state.siteRes.site.description)}
|
||||
dangerouslySetInnerHTML={mdToHtml(
|
||||
this.state.siteRes.site_view.site.description
|
||||
)}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
@ -509,14 +498,15 @@ export class Main extends Component<any, MainState> {
|
|||
}
|
||||
|
||||
listings() {
|
||||
let site = this.state.siteRes.site_view.site;
|
||||
return this.state.dataType == DataType.Post ? (
|
||||
<PostListings
|
||||
posts={this.state.posts}
|
||||
showCommunity
|
||||
removeDuplicates
|
||||
sort={this.state.sort}
|
||||
enableDownvotes={this.state.siteRes.site.enable_downvotes}
|
||||
enableNsfw={this.state.siteRes.site.enable_nsfw}
|
||||
enableDownvotes={site.enable_downvotes}
|
||||
enableNsfw={site.enable_nsfw}
|
||||
/>
|
||||
) : (
|
||||
<CommentNodes
|
||||
|
@ -525,7 +515,7 @@ export class Main extends Component<any, MainState> {
|
|||
showCommunity
|
||||
sortType={this.state.sort}
|
||||
showContext
|
||||
enableDownvotes={this.state.siteRes.site.enable_downvotes}
|
||||
enableDownvotes={site.enable_downvotes}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
@ -615,8 +605,8 @@ export class Main extends Component<any, MainState> {
|
|||
|
||||
get showLocal(): boolean {
|
||||
return (
|
||||
this.isoData.site.federated_instances !== null &&
|
||||
this.isoData.site.federated_instances.length > 0
|
||||
this.isoData.site_res.federated_instances !== null &&
|
||||
this.isoData.site_res.federated_instances.length > 0
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -624,7 +614,7 @@ export class Main extends Component<any, MainState> {
|
|||
return (
|
||||
UserService.Instance.user &&
|
||||
this.state.siteRes.admins
|
||||
.map(a => a.id)
|
||||
.map(a => a.user.id)
|
||||
.includes(UserService.Instance.user.id)
|
||||
);
|
||||
}
|
||||
|
@ -666,69 +656,70 @@ export class Main extends Component<any, MainState> {
|
|||
|
||||
fetchData() {
|
||||
if (this.state.dataType == DataType.Post) {
|
||||
let getPostsForm: GetPostsForm = {
|
||||
let getPostsForm: GetPosts = {
|
||||
page: this.state.page,
|
||||
limit: fetchLimit,
|
||||
sort: this.state.sort,
|
||||
type_: this.state.listingType,
|
||||
auth: UserService.Instance.authField(false),
|
||||
};
|
||||
WebSocketService.Instance.getPosts(getPostsForm);
|
||||
WebSocketService.Instance.client.getPosts(getPostsForm);
|
||||
} else {
|
||||
let getCommentsForm: GetCommentsForm = {
|
||||
let getCommentsForm: GetComments = {
|
||||
page: this.state.page,
|
||||
limit: fetchLimit,
|
||||
sort: this.state.sort,
|
||||
type_: this.state.listingType,
|
||||
auth: UserService.Instance.authField(false),
|
||||
};
|
||||
WebSocketService.Instance.getComments(getCommentsForm);
|
||||
WebSocketService.Instance.client.getComments(getCommentsForm);
|
||||
}
|
||||
}
|
||||
|
||||
parseMessage(msg: WebSocketJsonResponse) {
|
||||
console.log(msg);
|
||||
let res = wsJsonToRes(msg);
|
||||
parseMessage(msg: any) {
|
||||
let op = wsUserOp(msg);
|
||||
if (msg.error) {
|
||||
toast(i18n.t(msg.error), 'danger');
|
||||
return;
|
||||
} else if (msg.reconnect) {
|
||||
WebSocketService.Instance.communityJoin({ community_id: 0 });
|
||||
WebSocketService.Instance.client.communityJoin({ community_id: 0 });
|
||||
this.fetchData();
|
||||
} else if (res.op == UserOperation.GetFollowedCommunities) {
|
||||
let data = res.data as GetFollowedCommunitiesResponse;
|
||||
} else if (op == UserOperation.GetFollowedCommunities) {
|
||||
let data = wsJsonToRes<GetFollowedCommunitiesResponse>(msg).data;
|
||||
this.state.subscribedCommunities = data.communities;
|
||||
this.setState(this.state);
|
||||
} else if (res.op == UserOperation.ListCommunities) {
|
||||
let data = res.data as ListCommunitiesResponse;
|
||||
} else if (op == UserOperation.ListCommunities) {
|
||||
let data = wsJsonToRes<ListCommunitiesResponse>(msg).data;
|
||||
this.state.trendingCommunities = data.communities;
|
||||
this.setState(this.state);
|
||||
} else if (res.op == UserOperation.EditSite) {
|
||||
let data = res.data as SiteResponse;
|
||||
this.state.siteRes.site = data.site;
|
||||
} else if (op == UserOperation.EditSite) {
|
||||
let data = wsJsonToRes<SiteResponse>(msg).data;
|
||||
this.state.siteRes.site_view = data.site_view;
|
||||
this.state.showEditSite = false;
|
||||
this.setState(this.state);
|
||||
toast(i18n.t('site_saved'));
|
||||
} else if (res.op == UserOperation.GetPosts) {
|
||||
let data = res.data as GetPostsResponse;
|
||||
} else if (op == UserOperation.GetPosts) {
|
||||
let data = wsJsonToRes<GetPostsResponse>(msg).data;
|
||||
this.state.posts = data.posts;
|
||||
this.state.loading = false;
|
||||
this.setState(this.state);
|
||||
setupTippy();
|
||||
} else if (res.op == UserOperation.CreatePost) {
|
||||
let data = res.data as PostResponse;
|
||||
} else if (op == UserOperation.CreatePost) {
|
||||
let data = wsJsonToRes<PostResponse>(msg).data;
|
||||
|
||||
// If you're on subscribed, only push it if you're subscribed.
|
||||
if (this.state.listingType == ListingType.Subscribed) {
|
||||
if (
|
||||
this.state.subscribedCommunities
|
||||
.map(c => c.community_id)
|
||||
.includes(data.post.community_id)
|
||||
.map(c => c.community.id)
|
||||
.includes(data.post_view.community.id)
|
||||
) {
|
||||
this.state.posts.unshift(data.post);
|
||||
notifyPost(data.post, this.context.router);
|
||||
this.state.posts.unshift(data.post_view);
|
||||
notifyPost(data.post_view, this.context.router);
|
||||
}
|
||||
} else {
|
||||
// NSFW posts
|
||||
let nsfw = data.post.nsfw || data.post.community_nsfw;
|
||||
let nsfw = data.post_view.post.nsfw || data.post_view.community.nsfw;
|
||||
|
||||
// Don't push the post if its nsfw, and don't have that setting on
|
||||
if (
|
||||
|
@ -737,63 +728,65 @@ export class Main extends Component<any, MainState> {
|
|||
UserService.Instance.user &&
|
||||
UserService.Instance.user.show_nsfw)
|
||||
) {
|
||||
this.state.posts.unshift(data.post);
|
||||
notifyPost(data.post, this.context.router);
|
||||
this.state.posts.unshift(data.post_view);
|
||||
notifyPost(data.post_view, this.context.router);
|
||||
}
|
||||
}
|
||||
this.setState(this.state);
|
||||
} else if (
|
||||
res.op == UserOperation.EditPost ||
|
||||
res.op == UserOperation.DeletePost ||
|
||||
res.op == UserOperation.RemovePost ||
|
||||
res.op == UserOperation.LockPost ||
|
||||
res.op == UserOperation.StickyPost ||
|
||||
res.op == UserOperation.SavePost
|
||||
op == UserOperation.EditPost ||
|
||||
op == UserOperation.DeletePost ||
|
||||
op == UserOperation.RemovePost ||
|
||||
op == UserOperation.LockPost ||
|
||||
op == UserOperation.StickyPost ||
|
||||
op == UserOperation.SavePost
|
||||
) {
|
||||
let data = res.data as PostResponse;
|
||||
editPostFindRes(data, this.state.posts);
|
||||
let data = wsJsonToRes<PostResponse>(msg).data;
|
||||
editPostFindRes(data.post_view, this.state.posts);
|
||||
this.setState(this.state);
|
||||
} else if (res.op == UserOperation.CreatePostLike) {
|
||||
let data = res.data as PostResponse;
|
||||
createPostLikeFindRes(data, this.state.posts);
|
||||
} else if (op == UserOperation.CreatePostLike) {
|
||||
let data = wsJsonToRes<PostResponse>(msg).data;
|
||||
createPostLikeFindRes(data.post_view, this.state.posts);
|
||||
this.setState(this.state);
|
||||
} else if (res.op == UserOperation.AddAdmin) {
|
||||
let data = res.data as AddAdminResponse;
|
||||
} else if (op == UserOperation.AddAdmin) {
|
||||
let data = wsJsonToRes<AddAdminResponse>(msg).data;
|
||||
this.state.siteRes.admins = data.admins;
|
||||
this.setState(this.state);
|
||||
} else if (res.op == UserOperation.BanUser) {
|
||||
let data = res.data as BanUserResponse;
|
||||
let found = this.state.siteRes.banned.find(u => (u.id = data.user.id));
|
||||
} else if (op == UserOperation.BanUser) {
|
||||
let data = wsJsonToRes<BanUserResponse>(msg).data;
|
||||
let found = this.state.siteRes.banned.find(
|
||||
u => (u.user.id = data.user_view.user.id)
|
||||
);
|
||||
|
||||
// Remove the banned if its found in the list, and the action is an unban
|
||||
if (found && !data.banned) {
|
||||
this.state.siteRes.banned = this.state.siteRes.banned.filter(
|
||||
i => i.id !== data.user.id
|
||||
i => i.user.id !== data.user_view.user.id
|
||||
);
|
||||
} else {
|
||||
this.state.siteRes.banned.push(data.user);
|
||||
this.state.siteRes.banned.push(data.user_view);
|
||||
}
|
||||
|
||||
this.state.posts
|
||||
.filter(p => p.creator_id == data.user.id)
|
||||
.forEach(p => (p.banned = data.banned));
|
||||
.filter(p => p.creator.id == data.user_view.user.id)
|
||||
.forEach(p => (p.creator.banned = data.banned));
|
||||
|
||||
this.setState(this.state);
|
||||
} else if (res.op == UserOperation.GetComments) {
|
||||
let data = res.data as GetCommentsResponse;
|
||||
} else if (op == UserOperation.GetComments) {
|
||||
let data = wsJsonToRes<GetCommentsResponse>(msg).data;
|
||||
this.state.comments = data.comments;
|
||||
this.state.loading = false;
|
||||
this.setState(this.state);
|
||||
} else if (
|
||||
res.op == UserOperation.EditComment ||
|
||||
res.op == UserOperation.DeleteComment ||
|
||||
res.op == UserOperation.RemoveComment
|
||||
op == UserOperation.EditComment ||
|
||||
op == UserOperation.DeleteComment ||
|
||||
op == UserOperation.RemoveComment
|
||||
) {
|
||||
let data = res.data as CommentResponse;
|
||||
editCommentRes(data, this.state.comments);
|
||||
let data = wsJsonToRes<CommentResponse>(msg).data;
|
||||
editCommentRes(data.comment_view, this.state.comments);
|
||||
this.setState(this.state);
|
||||
} else if (res.op == UserOperation.CreateComment) {
|
||||
let data = res.data as CommentResponse;
|
||||
} else if (op == UserOperation.CreateComment) {
|
||||
let data = wsJsonToRes<CommentResponse>(msg).data;
|
||||
|
||||
// Necessary since it might be a user reply
|
||||
if (data.recipient_ids.length == 0) {
|
||||
|
@ -801,23 +794,23 @@ export class Main extends Component<any, MainState> {
|
|||
if (this.state.listingType == ListingType.Subscribed) {
|
||||
if (
|
||||
this.state.subscribedCommunities
|
||||
.map(c => c.community_id)
|
||||
.includes(data.comment.community_id)
|
||||
.map(c => c.community.id)
|
||||
.includes(data.comment_view.community.id)
|
||||
) {
|
||||
this.state.comments.unshift(data.comment);
|
||||
this.state.comments.unshift(data.comment_view);
|
||||
}
|
||||
} else {
|
||||
this.state.comments.unshift(data.comment);
|
||||
this.state.comments.unshift(data.comment_view);
|
||||
}
|
||||
this.setState(this.state);
|
||||
}
|
||||
} else if (res.op == UserOperation.SaveComment) {
|
||||
let data = res.data as CommentResponse;
|
||||
saveCommentRes(data, this.state.comments);
|
||||
} else if (op == UserOperation.SaveComment) {
|
||||
let data = wsJsonToRes<CommentResponse>(msg).data;
|
||||
saveCommentRes(data.comment_view, this.state.comments);
|
||||
this.setState(this.state);
|
||||
} else if (res.op == UserOperation.CreateCommentLike) {
|
||||
let data = res.data as CommentResponse;
|
||||
createCommentLikeRes(data, this.state.comments);
|
||||
} else if (op == UserOperation.CreateCommentLike) {
|
||||
let data = wsJsonToRes<CommentResponse>(msg).data;
|
||||
createCommentLikeRes(data.comment_view, this.state.comments);
|
||||
this.setState(this.state);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,51 +3,71 @@ import { Link } from 'inferno-router';
|
|||
import { Subscription } from 'rxjs';
|
||||
import {
|
||||
UserOperation,
|
||||
GetModlogForm,
|
||||
GetModlog,
|
||||
GetModlogResponse,
|
||||
ModRemovePost,
|
||||
ModLockPost,
|
||||
ModStickyPost,
|
||||
ModRemoveComment,
|
||||
ModRemoveCommunity,
|
||||
ModBanFromCommunity,
|
||||
ModBan,
|
||||
ModAddCommunity,
|
||||
ModAdd,
|
||||
WebSocketJsonResponse,
|
||||
Site,
|
||||
SiteView,
|
||||
ModRemovePostView,
|
||||
ModLockPostView,
|
||||
ModStickyPostView,
|
||||
ModRemoveCommentView,
|
||||
ModRemoveCommunityView,
|
||||
ModBanFromCommunityView,
|
||||
ModBanView,
|
||||
ModAddCommunityView,
|
||||
ModAddView,
|
||||
} from 'lemmy-js-client';
|
||||
import { WebSocketService } from '../services';
|
||||
import {
|
||||
wsJsonToRes,
|
||||
addTypeInfo,
|
||||
fetchLimit,
|
||||
toast,
|
||||
setIsoData,
|
||||
wsSubscribe,
|
||||
isBrowser,
|
||||
wsUserOp,
|
||||
} from '../utils';
|
||||
import { MomentTime } from './moment-time';
|
||||
import { HtmlTags } from './html-tags';
|
||||
import moment from 'moment';
|
||||
import { i18n } from '../i18next';
|
||||
import { InitialFetchRequest } from 'shared/interfaces';
|
||||
import { UserListing } from './user-listing';
|
||||
import { CommunityLink } from './community-link';
|
||||
|
||||
enum ModlogEnum {
|
||||
ModRemovePost,
|
||||
ModLockPost,
|
||||
ModStickyPost,
|
||||
ModRemoveComment,
|
||||
ModRemoveCommunity,
|
||||
ModBanFromCommunity,
|
||||
ModAddCommunity,
|
||||
ModAdd,
|
||||
ModBan,
|
||||
}
|
||||
|
||||
type ModlogType = {
|
||||
id: number;
|
||||
type_: ModlogEnum;
|
||||
view:
|
||||
| ModRemovePostView
|
||||
| ModLockPostView
|
||||
| ModStickyPostView
|
||||
| ModRemoveCommentView
|
||||
| ModRemoveCommunityView
|
||||
| ModBanFromCommunityView
|
||||
| ModBanView
|
||||
| ModAddCommunityView
|
||||
| ModAddView;
|
||||
when_: string;
|
||||
};
|
||||
|
||||
interface ModlogState {
|
||||
combined: {
|
||||
type_: string;
|
||||
data:
|
||||
| ModRemovePost
|
||||
| ModLockPost
|
||||
| ModStickyPost
|
||||
| ModRemoveCommunity
|
||||
| ModAdd
|
||||
| ModBan;
|
||||
}[];
|
||||
res: GetModlogResponse;
|
||||
communityId?: number;
|
||||
communityName?: string;
|
||||
page: number;
|
||||
site: Site;
|
||||
site_view: SiteView;
|
||||
loading: boolean;
|
||||
}
|
||||
|
||||
|
@ -55,10 +75,20 @@ export class Modlog extends Component<any, ModlogState> {
|
|||
private isoData = setIsoData(this.context);
|
||||
private subscription: Subscription;
|
||||
private emptyState: ModlogState = {
|
||||
combined: [],
|
||||
res: {
|
||||
removed_posts: [],
|
||||
locked_posts: [],
|
||||
stickied_posts: [],
|
||||
removed_comments: [],
|
||||
removed_communities: [],
|
||||
banned_from_community: [],
|
||||
banned: [],
|
||||
added_to_community: [],
|
||||
added: [],
|
||||
},
|
||||
page: 1,
|
||||
loading: true,
|
||||
site: this.isoData.site.site,
|
||||
site_view: this.isoData.site_res.site_view,
|
||||
};
|
||||
|
||||
constructor(props: any, context: any) {
|
||||
|
@ -75,7 +105,7 @@ export class Modlog extends Component<any, ModlogState> {
|
|||
// Only fetch the data if coming from another route
|
||||
if (this.isoData.path == this.context.router.route.match.url) {
|
||||
let data = this.isoData.routeData[0];
|
||||
this.setCombined(data);
|
||||
this.state.res = data;
|
||||
this.state.loading = false;
|
||||
} else {
|
||||
this.refetch();
|
||||
|
@ -88,264 +118,233 @@ export class Modlog extends Component<any, ModlogState> {
|
|||
}
|
||||
}
|
||||
|
||||
setCombined(res: GetModlogResponse) {
|
||||
let removed_posts = addTypeInfo(res.removed_posts, 'removed_posts');
|
||||
let locked_posts = addTypeInfo(res.locked_posts, 'locked_posts');
|
||||
let stickied_posts = addTypeInfo(res.stickied_posts, 'stickied_posts');
|
||||
let removed_comments = addTypeInfo(
|
||||
res.removed_comments,
|
||||
'removed_comments'
|
||||
);
|
||||
let removed_communities = addTypeInfo(
|
||||
res.removed_communities,
|
||||
'removed_communities'
|
||||
);
|
||||
let banned_from_community = addTypeInfo(
|
||||
res.banned_from_community,
|
||||
'banned_from_community'
|
||||
);
|
||||
let added_to_community = addTypeInfo(
|
||||
res.added_to_community,
|
||||
'added_to_community'
|
||||
);
|
||||
let added = addTypeInfo(res.added, 'added');
|
||||
let banned = addTypeInfo(res.banned, 'banned');
|
||||
this.state.combined = [];
|
||||
buildCombined(res: GetModlogResponse): ModlogType[] {
|
||||
let removed_posts: ModlogType[] = res.removed_posts.map(r => ({
|
||||
id: r.mod_remove_post.id,
|
||||
type_: ModlogEnum.ModRemovePost,
|
||||
view: r,
|
||||
when_: r.mod_remove_post.when_,
|
||||
}));
|
||||
|
||||
this.state.combined.push(...removed_posts);
|
||||
this.state.combined.push(...locked_posts);
|
||||
this.state.combined.push(...stickied_posts);
|
||||
this.state.combined.push(...removed_comments);
|
||||
this.state.combined.push(...removed_communities);
|
||||
this.state.combined.push(...banned_from_community);
|
||||
this.state.combined.push(...added_to_community);
|
||||
this.state.combined.push(...added);
|
||||
this.state.combined.push(...banned);
|
||||
let locked_posts: ModlogType[] = res.locked_posts.map(r => ({
|
||||
id: r.mod_lock_post.id,
|
||||
type_: ModlogEnum.ModLockPost,
|
||||
view: r,
|
||||
when_: r.mod_lock_post.when_,
|
||||
}));
|
||||
|
||||
if (this.state.communityId && this.state.combined.length > 0) {
|
||||
this.state.communityName = (this.state.combined[0]
|
||||
.data as ModRemovePost).community_name;
|
||||
let stickied_posts: ModlogType[] = res.stickied_posts.map(r => ({
|
||||
id: r.mod_sticky_post.id,
|
||||
type_: ModlogEnum.ModStickyPost,
|
||||
view: r,
|
||||
when_: r.mod_sticky_post.when_,
|
||||
}));
|
||||
|
||||
let removed_comments: ModlogType[] = res.removed_comments.map(r => ({
|
||||
id: r.mod_remove_comment.id,
|
||||
type_: ModlogEnum.ModRemoveComment,
|
||||
view: r,
|
||||
when_: r.mod_remove_comment.when_,
|
||||
}));
|
||||
|
||||
let removed_communities: ModlogType[] = res.removed_communities.map(r => ({
|
||||
id: r.mod_remove_community.id,
|
||||
type_: ModlogEnum.ModRemoveCommunity,
|
||||
view: r,
|
||||
when_: r.mod_remove_community.when_,
|
||||
}));
|
||||
|
||||
let banned_from_community: ModlogType[] = res.banned_from_community.map(
|
||||
r => ({
|
||||
id: r.mod_ban_from_community.id,
|
||||
type_: ModlogEnum.ModBanFromCommunity,
|
||||
view: r,
|
||||
when_: r.mod_ban_from_community.when_,
|
||||
})
|
||||
);
|
||||
|
||||
let added_to_community: ModlogType[] = res.added_to_community.map(r => ({
|
||||
id: r.mod_add_community.id,
|
||||
type_: ModlogEnum.ModAddCommunity,
|
||||
view: r,
|
||||
when_: r.mod_add_community.when_,
|
||||
}));
|
||||
|
||||
let added: ModlogType[] = res.added.map(r => ({
|
||||
id: r.mod_add.id,
|
||||
type_: ModlogEnum.ModAdd,
|
||||
view: r,
|
||||
when_: r.mod_add.when_,
|
||||
}));
|
||||
|
||||
let banned: ModlogType[] = res.banned.map(r => ({
|
||||
id: r.mod_ban.id,
|
||||
type_: ModlogEnum.ModBan,
|
||||
view: r,
|
||||
when_: r.mod_ban.when_,
|
||||
}));
|
||||
|
||||
let combined: ModlogType[] = [];
|
||||
|
||||
combined.push(...removed_posts);
|
||||
combined.push(...locked_posts);
|
||||
combined.push(...stickied_posts);
|
||||
combined.push(...removed_comments);
|
||||
combined.push(...removed_communities);
|
||||
combined.push(...banned_from_community);
|
||||
combined.push(...added_to_community);
|
||||
combined.push(...added);
|
||||
combined.push(...banned);
|
||||
|
||||
if (this.state.communityId && combined.length > 0) {
|
||||
this.state.communityName = (combined[0]
|
||||
.view as ModRemovePostView).community.name;
|
||||
}
|
||||
|
||||
// Sort them by time
|
||||
this.state.combined.sort((a, b) =>
|
||||
b.data.when_.localeCompare(a.data.when_)
|
||||
);
|
||||
combined.sort((a, b) => b.when_.localeCompare(a.when_));
|
||||
|
||||
return combined;
|
||||
}
|
||||
|
||||
renderModlogType(i: ModlogType) {
|
||||
switch (i.type_) {
|
||||
case ModlogEnum.ModRemovePost:
|
||||
let mrpv = i.view as ModRemovePostView;
|
||||
return [
|
||||
mrpv.mod_remove_post.removed ? 'Removed ' : 'Restored ',
|
||||
<span>
|
||||
Post <Link to={`/post/${mrpv.post.id}`}>{mrpv.post.name}</Link>
|
||||
</span>,
|
||||
mrpv.mod_remove_post.reason &&
|
||||
` reason: ${mrpv.mod_remove_post.reason}`,
|
||||
];
|
||||
case ModlogEnum.ModLockPost:
|
||||
let mlpv = i.view as ModLockPostView;
|
||||
return [
|
||||
mlpv.mod_lock_post.locked ? 'Locked ' : 'Unlocked ',
|
||||
<span>
|
||||
Post <Link to={`/post/${mlpv.post.id}`}>{mlpv.post.name}</Link>
|
||||
</span>,
|
||||
];
|
||||
case ModlogEnum.ModStickyPost:
|
||||
let mspv = i.view as ModStickyPostView;
|
||||
return [
|
||||
mspv.mod_sticky_post.stickied ? 'Stickied ' : 'Unstickied ',
|
||||
<span>
|
||||
Post <Link to={`/post/${mspv.post.id}`}>{mspv.post.name}</Link>
|
||||
</span>,
|
||||
];
|
||||
case ModlogEnum.ModRemoveComment:
|
||||
let mrc = i.view as ModRemoveCommentView;
|
||||
return [
|
||||
mrc.mod_remove_comment.removed ? 'Removed ' : 'Restored ',
|
||||
<span>
|
||||
Comment{' '}
|
||||
<Link to={`/post/${mrc.post.id}/comment/${mrc.comment.id}`}>
|
||||
{mrc.comment.content}
|
||||
</Link>
|
||||
</span>,
|
||||
<span>
|
||||
{' '}
|
||||
by <UserListing user={mrc.commenter} />
|
||||
</span>,
|
||||
mrc.mod_remove_comment.reason &&
|
||||
` reason: ${mrc.mod_remove_comment.reason}`,
|
||||
];
|
||||
case ModlogEnum.ModRemoveCommunity:
|
||||
let mrco = i.view as ModRemoveCommunityView;
|
||||
return [
|
||||
mrco.mod_remove_community.removed ? 'Removed ' : 'Restored ',
|
||||
<span>
|
||||
Community <CommunityLink community={mrco.community} />
|
||||
</span>,
|
||||
mrco.mod_remove_community.reason &&
|
||||
` reason: ${mrco.mod_remove_community.reason}`,
|
||||
mrco.mod_remove_community.expires &&
|
||||
` expires: ${moment
|
||||
.utc(mrco.mod_remove_community.expires)
|
||||
.fromNow()}`,
|
||||
];
|
||||
case ModlogEnum.ModBanFromCommunity:
|
||||
let mbfc = i.view as ModBanFromCommunityView;
|
||||
return [
|
||||
<span>
|
||||
{mbfc.mod_ban_from_community.banned ? 'Banned ' : 'Unbanned '}{' '}
|
||||
</span>,
|
||||
<span>
|
||||
<UserListing user={mbfc.banned_user} />
|
||||
</span>,
|
||||
<span> from the community </span>,
|
||||
<span>
|
||||
<CommunityLink community={mbfc.community} />
|
||||
</span>,
|
||||
<div>
|
||||
{mbfc.mod_ban_from_community.reason &&
|
||||
` reason: ${mbfc.mod_ban_from_community.reason}`}
|
||||
</div>,
|
||||
<div>
|
||||
{mbfc.mod_ban_from_community.expires &&
|
||||
` expires: ${moment
|
||||
.utc(mbfc.mod_ban_from_community.expires)
|
||||
.fromNow()}`}
|
||||
</div>,
|
||||
];
|
||||
case ModlogEnum.ModAddCommunity:
|
||||
let mac = i.view as ModAddCommunityView;
|
||||
return [
|
||||
<span>
|
||||
{mac.mod_add_community.removed ? 'Removed ' : 'Appointed '}{' '}
|
||||
</span>,
|
||||
<span>
|
||||
<UserListing user={mac.modded_user} />
|
||||
</span>,
|
||||
<span> as a mod to the community </span>,
|
||||
<span>
|
||||
<CommunityLink community={mac.community} />
|
||||
</span>,
|
||||
];
|
||||
case ModlogEnum.ModBan:
|
||||
let mb = i.view as ModBanView;
|
||||
return [
|
||||
<span>{mb.mod_ban.banned ? 'Banned ' : 'Unbanned '} </span>,
|
||||
<span>
|
||||
<UserListing user={mb.banned_user} />
|
||||
</span>,
|
||||
<div>{mb.mod_ban.reason && ` reason: ${mb.mod_ban.reason}`}</div>,
|
||||
<div>
|
||||
{mb.mod_ban.expires &&
|
||||
` expires: ${moment.utc(mb.mod_ban.expires).fromNow()}`}
|
||||
</div>,
|
||||
];
|
||||
case ModlogEnum.ModAdd:
|
||||
let ma = i.view as ModAddView;
|
||||
return [
|
||||
<span>{ma.mod_add.removed ? 'Removed ' : 'Appointed '} </span>,
|
||||
<span>
|
||||
<UserListing user={ma.modded_user} />
|
||||
</span>,
|
||||
<span> as an admin </span>,
|
||||
];
|
||||
default:
|
||||
return <div />;
|
||||
}
|
||||
}
|
||||
|
||||
combined() {
|
||||
let combined = this.buildCombined(this.state.res);
|
||||
|
||||
return (
|
||||
<tbody>
|
||||
{this.state.combined.map(i => (
|
||||
{combined.map(i => (
|
||||
<tr>
|
||||
<td>
|
||||
<MomentTime data={i.data} />
|
||||
<MomentTime data={i} />
|
||||
</td>
|
||||
<td>
|
||||
<Link to={`/u/${i.data.mod_user_name}`}>
|
||||
{i.data.mod_user_name}
|
||||
</Link>
|
||||
</td>
|
||||
<td>
|
||||
{i.type_ == 'removed_posts' && (
|
||||
<>
|
||||
{(i.data as ModRemovePost).removed ? 'Removed' : 'Restored'}
|
||||
<span>
|
||||
{' '}
|
||||
Post{' '}
|
||||
<Link to={`/post/${(i.data as ModRemovePost).post_id}`}>
|
||||
{(i.data as ModRemovePost).post_name}
|
||||
</Link>
|
||||
</span>
|
||||
<div>
|
||||
{(i.data as ModRemovePost).reason &&
|
||||
` reason: ${(i.data as ModRemovePost).reason}`}
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
{i.type_ == 'locked_posts' && (
|
||||
<>
|
||||
{(i.data as ModLockPost).locked ? 'Locked' : 'Unlocked'}
|
||||
<span>
|
||||
{' '}
|
||||
Post{' '}
|
||||
<Link to={`/post/${(i.data as ModLockPost).post_id}`}>
|
||||
{(i.data as ModLockPost).post_name}
|
||||
</Link>
|
||||
</span>
|
||||
</>
|
||||
)}
|
||||
{i.type_ == 'stickied_posts' && (
|
||||
<>
|
||||
{(i.data as ModStickyPost).stickied
|
||||
? 'Stickied'
|
||||
: 'Unstickied'}
|
||||
<span>
|
||||
{' '}
|
||||
Post{' '}
|
||||
<Link to={`/post/${(i.data as ModStickyPost).post_id}`}>
|
||||
{(i.data as ModStickyPost).post_name}
|
||||
</Link>
|
||||
</span>
|
||||
</>
|
||||
)}
|
||||
{i.type_ == 'removed_comments' && (
|
||||
<>
|
||||
{(i.data as ModRemoveComment).removed
|
||||
? 'Removed'
|
||||
: 'Restored'}
|
||||
<span>
|
||||
{' '}
|
||||
Comment{' '}
|
||||
<Link
|
||||
to={`/post/${
|
||||
(i.data as ModRemoveComment).post_id
|
||||
}/comment/${(i.data as ModRemoveComment).comment_id}`}
|
||||
>
|
||||
{(i.data as ModRemoveComment).comment_content}
|
||||
</Link>
|
||||
</span>
|
||||
<span>
|
||||
{' '}
|
||||
by{' '}
|
||||
<Link
|
||||
to={`/u/${
|
||||
(i.data as ModRemoveComment).comment_user_name
|
||||
}`}
|
||||
>
|
||||
{(i.data as ModRemoveComment).comment_user_name}
|
||||
</Link>
|
||||
</span>
|
||||
<div>
|
||||
{(i.data as ModRemoveComment).reason &&
|
||||
` reason: ${(i.data as ModRemoveComment).reason}`}
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
{i.type_ == 'removed_communities' && (
|
||||
<>
|
||||
{(i.data as ModRemoveCommunity).removed
|
||||
? 'Removed'
|
||||
: 'Restored'}
|
||||
<span>
|
||||
{' '}
|
||||
Community{' '}
|
||||
<Link
|
||||
to={`/c/${(i.data as ModRemoveCommunity).community_name}`}
|
||||
>
|
||||
{(i.data as ModRemoveCommunity).community_name}
|
||||
</Link>
|
||||
</span>
|
||||
<div>
|
||||
{(i.data as ModRemoveCommunity).reason &&
|
||||
` reason: ${(i.data as ModRemoveCommunity).reason}`}
|
||||
</div>
|
||||
<div>
|
||||
{(i.data as ModRemoveCommunity).expires &&
|
||||
` expires: ${moment
|
||||
.utc((i.data as ModRemoveCommunity).expires)
|
||||
.fromNow()}`}
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
{i.type_ == 'banned_from_community' && (
|
||||
<>
|
||||
<span>
|
||||
{(i.data as ModBanFromCommunity).banned
|
||||
? 'Banned '
|
||||
: 'Unbanned '}{' '}
|
||||
</span>
|
||||
<span>
|
||||
<Link
|
||||
to={`/u/${
|
||||
(i.data as ModBanFromCommunity).other_user_name
|
||||
}`}
|
||||
>
|
||||
{(i.data as ModBanFromCommunity).other_user_name}
|
||||
</Link>
|
||||
</span>
|
||||
<span> from the community </span>
|
||||
<span>
|
||||
<Link
|
||||
to={`/c/${
|
||||
(i.data as ModBanFromCommunity).community_name
|
||||
}`}
|
||||
>
|
||||
{(i.data as ModBanFromCommunity).community_name}
|
||||
</Link>
|
||||
</span>
|
||||
<div>
|
||||
{(i.data as ModBanFromCommunity).reason &&
|
||||
` reason: ${(i.data as ModBanFromCommunity).reason}`}
|
||||
</div>
|
||||
<div>
|
||||
{(i.data as ModBanFromCommunity).expires &&
|
||||
` expires: ${moment
|
||||
.utc((i.data as ModBanFromCommunity).expires)
|
||||
.fromNow()}`}
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
{i.type_ == 'added_to_community' && (
|
||||
<>
|
||||
<span>
|
||||
{(i.data as ModAddCommunity).removed
|
||||
? 'Removed '
|
||||
: 'Appointed '}{' '}
|
||||
</span>
|
||||
<span>
|
||||
<Link
|
||||
to={`/u/${(i.data as ModAddCommunity).other_user_name}`}
|
||||
>
|
||||
{(i.data as ModAddCommunity).other_user_name}
|
||||
</Link>
|
||||
</span>
|
||||
<span> as a mod to the community </span>
|
||||
<span>
|
||||
<Link
|
||||
to={`/c/${(i.data as ModAddCommunity).community_name}`}
|
||||
>
|
||||
{(i.data as ModAddCommunity).community_name}
|
||||
</Link>
|
||||
</span>
|
||||
</>
|
||||
)}
|
||||
{i.type_ == 'banned' && (
|
||||
<>
|
||||
<span>
|
||||
{(i.data as ModBan).banned ? 'Banned ' : 'Unbanned '}{' '}
|
||||
</span>
|
||||
<span>
|
||||
<Link to={`/u/${(i.data as ModBan).other_user_name}`}>
|
||||
{(i.data as ModBan).other_user_name}
|
||||
</Link>
|
||||
</span>
|
||||
<div>
|
||||
{(i.data as ModBan).reason &&
|
||||
` reason: ${(i.data as ModBan).reason}`}
|
||||
</div>
|
||||
<div>
|
||||
{(i.data as ModBan).expires &&
|
||||
` expires: ${moment
|
||||
.utc((i.data as ModBan).expires)
|
||||
.fromNow()}`}
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
{i.type_ == 'added' && (
|
||||
<>
|
||||
<span>
|
||||
{(i.data as ModAdd).removed ? 'Removed ' : 'Appointed '}{' '}
|
||||
</span>
|
||||
<span>
|
||||
<Link to={`/u/${(i.data as ModAdd).other_user_name}`}>
|
||||
{(i.data as ModAdd).other_user_name}
|
||||
</Link>
|
||||
</span>
|
||||
<span> as an admin </span>
|
||||
</>
|
||||
)}
|
||||
<UserListing user={i.view.moderator} />
|
||||
</td>
|
||||
<td>{this.renderModlogType(i)}</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
|
@ -353,7 +352,7 @@ export class Modlog extends Component<any, ModlogState> {
|
|||
}
|
||||
|
||||
get documentTitle(): string {
|
||||
return `Modlog - ${this.state.site.name}`;
|
||||
return `Modlog - ${this.state.site_view.site.name}`;
|
||||
}
|
||||
|
||||
render() {
|
||||
|
@ -435,12 +434,12 @@ export class Modlog extends Component<any, ModlogState> {
|
|||
}
|
||||
|
||||
refetch() {
|
||||
let modlogForm: GetModlogForm = {
|
||||
let modlogForm: GetModlog = {
|
||||
community_id: this.state.communityId,
|
||||
page: this.state.page,
|
||||
limit: fetchLimit,
|
||||
};
|
||||
WebSocketService.Instance.getModlog(modlogForm);
|
||||
WebSocketService.Instance.client.getModlog(modlogForm);
|
||||
}
|
||||
|
||||
static fetchInitialData(req: InitialFetchRequest): Promise<any>[] {
|
||||
|
@ -448,7 +447,7 @@ export class Modlog extends Component<any, ModlogState> {
|
|||
let communityId = pathSplit[3];
|
||||
let promises: Promise<any>[] = [];
|
||||
|
||||
let modlogForm: GetModlogForm = {
|
||||
let modlogForm: GetModlog = {
|
||||
page: 1,
|
||||
limit: fetchLimit,
|
||||
};
|
||||
|
@ -461,17 +460,16 @@ export class Modlog extends Component<any, ModlogState> {
|
|||
return promises;
|
||||
}
|
||||
|
||||
parseMessage(msg: WebSocketJsonResponse) {
|
||||
console.log(msg);
|
||||
let res = wsJsonToRes(msg);
|
||||
parseMessage(msg: any) {
|
||||
let op = wsUserOp(msg);
|
||||
if (msg.error) {
|
||||
toast(i18n.t(msg.error), 'danger');
|
||||
return;
|
||||
} else if (res.op == UserOperation.GetModlog) {
|
||||
let data = res.data as GetModlogResponse;
|
||||
} else if (op == UserOperation.GetModlog) {
|
||||
let data = wsJsonToRes<GetModlogResponse>(msg).data;
|
||||
this.state.loading = false;
|
||||
window.scrollTo(0, 0);
|
||||
this.setCombined(data);
|
||||
this.state.res = data;
|
||||
this.setState(this.state);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,19 +4,18 @@ import { Subscription } from 'rxjs';
|
|||
import { WebSocketService, UserService } from '../services';
|
||||
import {
|
||||
UserOperation,
|
||||
GetRepliesForm,
|
||||
GetReplies,
|
||||
GetRepliesResponse,
|
||||
GetUserMentionsForm,
|
||||
GetUserMentions,
|
||||
GetUserMentionsResponse,
|
||||
GetPrivateMessagesForm,
|
||||
GetPrivateMessages,
|
||||
PrivateMessagesResponse,
|
||||
SortType,
|
||||
GetSiteResponse,
|
||||
Comment,
|
||||
CommentView,
|
||||
CommentResponse,
|
||||
PrivateMessage,
|
||||
PrivateMessageResponse,
|
||||
WebSocketJsonResponse,
|
||||
PrivateMessageView,
|
||||
} from 'lemmy-js-client';
|
||||
import {
|
||||
wsJsonToRes,
|
||||
|
@ -30,20 +29,21 @@ import {
|
|||
isBrowser,
|
||||
wsSubscribe,
|
||||
supportLemmyUrl,
|
||||
wsUserOp,
|
||||
} from '../utils';
|
||||
import { i18n } from '../i18next';
|
||||
import { PictrsImage } from './pictrs-image';
|
||||
|
||||
interface NavbarProps {
|
||||
site: GetSiteResponse;
|
||||
site_res: GetSiteResponse;
|
||||
}
|
||||
|
||||
interface NavbarState {
|
||||
isLoggedIn: boolean;
|
||||
expanded: boolean;
|
||||
replies: Comment[];
|
||||
mentions: Comment[];
|
||||
messages: PrivateMessage[];
|
||||
replies: CommentView[];
|
||||
mentions: CommentView[];
|
||||
messages: PrivateMessageView[];
|
||||
unreadCount: number;
|
||||
searchParam: string;
|
||||
toggleSearch: boolean;
|
||||
|
@ -56,7 +56,7 @@ export class Navbar extends Component<NavbarProps, NavbarState> {
|
|||
private unreadCountSub: Subscription;
|
||||
private searchTextField: RefObject<HTMLInputElement>;
|
||||
emptyState: NavbarState = {
|
||||
isLoggedIn: !!this.props.site.my_user,
|
||||
isLoggedIn: !!this.props.site_res.my_user,
|
||||
unreadCount: 0,
|
||||
replies: [],
|
||||
mentions: [],
|
||||
|
@ -88,7 +88,9 @@ export class Navbar extends Component<NavbarProps, NavbarState> {
|
|||
// i18n.changeLanguage('de');
|
||||
} else {
|
||||
this.requestNotificationPermission();
|
||||
WebSocketService.Instance.userJoin();
|
||||
WebSocketService.Instance.client.userJoin({
|
||||
auth: UserService.Instance.authField(),
|
||||
});
|
||||
this.fetchUnreads();
|
||||
}
|
||||
|
||||
|
@ -96,7 +98,7 @@ export class Navbar extends Component<NavbarProps, NavbarState> {
|
|||
// A login
|
||||
if (res !== undefined) {
|
||||
this.requestNotificationPermission();
|
||||
WebSocketService.Instance.getSite();
|
||||
WebSocketService.Instance.client.getSite();
|
||||
} else {
|
||||
this.setState({ isLoggedIn: false });
|
||||
}
|
||||
|
@ -165,20 +167,23 @@ export class Navbar extends Component<NavbarProps, NavbarState> {
|
|||
|
||||
// TODO class active corresponding to current page
|
||||
navbar() {
|
||||
let user = this.props.site.my_user;
|
||||
let user = this.props.site_res.my_user;
|
||||
return (
|
||||
<nav class="navbar navbar-expand-lg navbar-light shadow-sm p-0 px-3">
|
||||
<div class="container">
|
||||
{this.props.site.site && (
|
||||
{this.props.site_res.site_view && (
|
||||
<Link
|
||||
title={this.props.site.version}
|
||||
title={this.props.site_res.version}
|
||||
className="d-flex align-items-center navbar-brand mr-md-3"
|
||||
to="/"
|
||||
>
|
||||
{this.props.site.site.icon && showAvatars() && (
|
||||
<PictrsImage src={this.props.site.site.icon} icon />
|
||||
{this.props.site_res.site_view.site.icon && showAvatars() && (
|
||||
<PictrsImage
|
||||
src={this.props.site_res.site_view.site.icon}
|
||||
icon
|
||||
/>
|
||||
)}
|
||||
{this.props.site.site.name}
|
||||
{this.props.site_res.site_view.site.name}
|
||||
</Link>
|
||||
)}
|
||||
{this.state.isLoggedIn && (
|
||||
|
@ -362,8 +367,8 @@ export class Navbar extends Component<NavbarProps, NavbarState> {
|
|||
i.setState(i.state);
|
||||
}
|
||||
|
||||
parseMessage(msg: WebSocketJsonResponse) {
|
||||
let res = wsJsonToRes(msg);
|
||||
parseMessage(msg: any) {
|
||||
let op = wsUserOp(msg);
|
||||
if (msg.error) {
|
||||
if (msg.error == 'not_logged_in') {
|
||||
UserService.Instance.logout();
|
||||
|
@ -371,62 +376,68 @@ export class Navbar extends Component<NavbarProps, NavbarState> {
|
|||
}
|
||||
return;
|
||||
} else if (msg.reconnect) {
|
||||
WebSocketService.Instance.userJoin();
|
||||
WebSocketService.Instance.client.userJoin({
|
||||
auth: UserService.Instance.authField(),
|
||||
});
|
||||
this.fetchUnreads();
|
||||
} else if (res.op == UserOperation.GetReplies) {
|
||||
let data = res.data as GetRepliesResponse;
|
||||
let unreadReplies = data.replies.filter(r => !r.read);
|
||||
} 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.unreadCount = this.calculateUnreadCount();
|
||||
this.setState(this.state);
|
||||
this.sendUnreadCount();
|
||||
} else if (res.op == UserOperation.GetUserMentions) {
|
||||
let data = res.data as GetUserMentionsResponse;
|
||||
let unreadMentions = data.mentions.filter(r => !r.read);
|
||||
} else if (op == UserOperation.GetUserMentions) {
|
||||
let data = wsJsonToRes<GetUserMentionsResponse>(msg).data;
|
||||
let unreadMentions = data.mentions.filter(r => !r.comment.read);
|
||||
|
||||
this.state.mentions = unreadMentions;
|
||||
this.state.unreadCount = this.calculateUnreadCount();
|
||||
this.setState(this.state);
|
||||
this.sendUnreadCount();
|
||||
} else if (res.op == UserOperation.GetPrivateMessages) {
|
||||
let data = res.data as PrivateMessagesResponse;
|
||||
let unreadMessages = data.messages.filter(r => !r.read);
|
||||
} 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.unreadCount = this.calculateUnreadCount();
|
||||
this.setState(this.state);
|
||||
this.sendUnreadCount();
|
||||
} else if (res.op == UserOperation.GetSite) {
|
||||
} else if (op == UserOperation.GetSite) {
|
||||
// This is only called on a successful login
|
||||
let data = res.data as GetSiteResponse;
|
||||
let data = wsJsonToRes<GetSiteResponse>(msg).data;
|
||||
UserService.Instance.user = data.my_user;
|
||||
setTheme(UserService.Instance.user.theme);
|
||||
i18n.changeLanguage(getLanguage());
|
||||
this.state.isLoggedIn = true;
|
||||
this.setState(this.state);
|
||||
} else if (res.op == UserOperation.CreateComment) {
|
||||
let data = res.data as CommentResponse;
|
||||
} else if (op == UserOperation.CreateComment) {
|
||||
let data = wsJsonToRes<CommentResponse>(msg).data;
|
||||
|
||||
if (this.state.isLoggedIn) {
|
||||
if (data.recipient_ids.includes(UserService.Instance.user.id)) {
|
||||
this.state.replies.push(data.comment);
|
||||
this.state.replies.push(data.comment_view);
|
||||
this.state.unreadCount++;
|
||||
this.setState(this.state);
|
||||
this.sendUnreadCount();
|
||||
notifyComment(data.comment, this.context.router);
|
||||
notifyComment(data.comment_view, this.context.router);
|
||||
}
|
||||
}
|
||||
} else if (res.op == UserOperation.CreatePrivateMessage) {
|
||||
let data = res.data as PrivateMessageResponse;
|
||||
} else if (op == UserOperation.CreatePrivateMessage) {
|
||||
let data = wsJsonToRes<PrivateMessageResponse>(msg).data;
|
||||
|
||||
if (this.state.isLoggedIn) {
|
||||
if (data.message.recipient_id == UserService.Instance.user.id) {
|
||||
this.state.messages.push(data.message);
|
||||
if (
|
||||
data.private_message_view.recipient.id == UserService.Instance.user.id
|
||||
) {
|
||||
this.state.messages.push(data.private_message_view);
|
||||
this.state.unreadCount++;
|
||||
this.setState(this.state);
|
||||
this.sendUnreadCount();
|
||||
notifyPrivateMessage(data.message, this.context.router);
|
||||
notifyPrivateMessage(data.private_message_view, this.context.router);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -434,30 +445,33 @@ export class Navbar extends Component<NavbarProps, NavbarState> {
|
|||
|
||||
fetchUnreads() {
|
||||
console.log('Fetching unreads...');
|
||||
let repliesForm: GetRepliesForm = {
|
||||
let repliesForm: GetReplies = {
|
||||
sort: SortType.New,
|
||||
unread_only: true,
|
||||
page: 1,
|
||||
limit: fetchLimit,
|
||||
auth: UserService.Instance.authField(),
|
||||
};
|
||||
|
||||
let userMentionsForm: GetUserMentionsForm = {
|
||||
let userMentionsForm: GetUserMentions = {
|
||||
sort: SortType.New,
|
||||
unread_only: true,
|
||||
page: 1,
|
||||
limit: fetchLimit,
|
||||
auth: UserService.Instance.authField(),
|
||||
};
|
||||
|
||||
let privateMessagesForm: GetPrivateMessagesForm = {
|
||||
let privateMessagesForm: GetPrivateMessages = {
|
||||
unread_only: true,
|
||||
page: 1,
|
||||
limit: fetchLimit,
|
||||
auth: UserService.Instance.authField(),
|
||||
};
|
||||
|
||||
if (this.currentLocation !== '/inbox') {
|
||||
WebSocketService.Instance.getReplies(repliesForm);
|
||||
WebSocketService.Instance.getUserMentions(userMentionsForm);
|
||||
WebSocketService.Instance.getPrivateMessages(privateMessagesForm);
|
||||
WebSocketService.Instance.client.getReplies(repliesForm);
|
||||
WebSocketService.Instance.client.getUserMentions(userMentionsForm);
|
||||
WebSocketService.Instance.client.getPrivateMessages(privateMessagesForm);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -471,17 +485,17 @@ export class Navbar extends Component<NavbarProps, NavbarState> {
|
|||
|
||||
calculateUnreadCount(): number {
|
||||
return (
|
||||
this.state.replies.filter(r => !r.read).length +
|
||||
this.state.mentions.filter(r => !r.read).length +
|
||||
this.state.messages.filter(r => !r.read).length
|
||||
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.user &&
|
||||
this.props.site.admins
|
||||
.map(a => a.id)
|
||||
this.props.site_res.admins
|
||||
.map(a => a.user.id)
|
||||
.includes(UserService.Instance.user.id)
|
||||
);
|
||||
}
|
||||
|
|
|
@ -3,9 +3,8 @@ import { Subscription } from 'rxjs';
|
|||
import {
|
||||
UserOperation,
|
||||
LoginResponse,
|
||||
PasswordChangeForm,
|
||||
WebSocketJsonResponse,
|
||||
Site,
|
||||
PasswordChange as PasswordChangeForm,
|
||||
SiteView,
|
||||
} from 'lemmy-js-client';
|
||||
import { WebSocketService, UserService } from '../services';
|
||||
import {
|
||||
|
@ -15,6 +14,7 @@ import {
|
|||
setIsoData,
|
||||
isBrowser,
|
||||
wsSubscribe,
|
||||
wsUserOp,
|
||||
} from '../utils';
|
||||
import { i18n } from '../i18next';
|
||||
import { HtmlTags } from './html-tags';
|
||||
|
@ -22,7 +22,7 @@ import { HtmlTags } from './html-tags';
|
|||
interface State {
|
||||
passwordChangeForm: PasswordChangeForm;
|
||||
loading: boolean;
|
||||
site: Site;
|
||||
site_view: SiteView;
|
||||
}
|
||||
|
||||
export class PasswordChange extends Component<any, State> {
|
||||
|
@ -36,7 +36,7 @@ export class PasswordChange extends Component<any, State> {
|
|||
password_verify: undefined,
|
||||
},
|
||||
loading: false,
|
||||
site: this.isoData.site.site,
|
||||
site_view: this.isoData.site_res.site_view,
|
||||
};
|
||||
|
||||
constructor(props: any, context: any) {
|
||||
|
@ -55,7 +55,7 @@ export class PasswordChange extends Component<any, State> {
|
|||
}
|
||||
|
||||
get documentTitle(): string {
|
||||
return `${i18n.t('password_change')} - ${this.state.site.name}`;
|
||||
return `${i18n.t('password_change')} - ${this.state.site_view.site.name}`;
|
||||
}
|
||||
|
||||
render() {
|
||||
|
@ -138,18 +138,18 @@ export class PasswordChange extends Component<any, State> {
|
|||
i.state.loading = true;
|
||||
i.setState(i.state);
|
||||
|
||||
WebSocketService.Instance.passwordChange(i.state.passwordChangeForm);
|
||||
WebSocketService.Instance.client.passwordChange(i.state.passwordChangeForm);
|
||||
}
|
||||
|
||||
parseMessage(msg: WebSocketJsonResponse) {
|
||||
let res = wsJsonToRes(msg);
|
||||
parseMessage(msg: any) {
|
||||
let op = wsUserOp(msg);
|
||||
if (msg.error) {
|
||||
toast(i18n.t(msg.error), 'danger');
|
||||
this.state.loading = false;
|
||||
this.setState(this.state);
|
||||
return;
|
||||
} else if (res.op == UserOperation.PasswordChange) {
|
||||
let data = res.data as LoginResponse;
|
||||
} else if (op == UserOperation.PasswordChange) {
|
||||
let data = wsJsonToRes<LoginResponse>(msg).data;
|
||||
this.state = this.emptyState;
|
||||
this.setState(this.state);
|
||||
UserService.Instance.login(data);
|
||||
|
|
|
@ -4,19 +4,19 @@ import { PostListings } from './post-listings';
|
|||
import { MarkdownTextArea } from './markdown-textarea';
|
||||
import { Subscription } from 'rxjs';
|
||||
import {
|
||||
PostForm as PostFormI,
|
||||
PostFormParams,
|
||||
Post,
|
||||
CreatePost,
|
||||
EditPost,
|
||||
PostView,
|
||||
PostResponse,
|
||||
UserOperation,
|
||||
Community,
|
||||
CommunityView,
|
||||
SortType,
|
||||
SearchForm,
|
||||
Search,
|
||||
SearchType,
|
||||
SearchResponse,
|
||||
WebSocketJsonResponse,
|
||||
} from 'lemmy-js-client';
|
||||
import { WebSocketService, UserService } from '../services';
|
||||
import { PostFormParams } from '../interfaces';
|
||||
import {
|
||||
wsJsonToRes,
|
||||
getPageTitle,
|
||||
|
@ -33,6 +33,7 @@ import {
|
|||
validTitle,
|
||||
wsSubscribe,
|
||||
isBrowser,
|
||||
wsUserOp,
|
||||
} from '../utils';
|
||||
|
||||
var Choices;
|
||||
|
@ -46,24 +47,24 @@ import { pictrsUri } from '../env';
|
|||
const MAX_POST_TITLE_LENGTH = 200;
|
||||
|
||||
interface PostFormProps {
|
||||
post?: Post; // If a post is given, that means this is an edit
|
||||
communities?: Community[];
|
||||
post_view?: PostView; // If a post is given, that means this is an edit
|
||||
communities?: CommunityView[];
|
||||
params?: PostFormParams;
|
||||
onCancel?(): any;
|
||||
onCreate?(id: number): any;
|
||||
onEdit?(post: Post): any;
|
||||
onCreate?(post: PostView): any;
|
||||
onEdit?(post: PostView): any;
|
||||
enableNsfw: boolean;
|
||||
enableDownvotes: boolean;
|
||||
}
|
||||
|
||||
interface PostFormState {
|
||||
postForm: PostFormI;
|
||||
postForm: CreatePost;
|
||||
loading: boolean;
|
||||
imageLoading: boolean;
|
||||
previewMode: boolean;
|
||||
suggestedTitle: string;
|
||||
suggestedPosts: Post[];
|
||||
crossPosts: Post[];
|
||||
suggestedPosts: PostView[];
|
||||
crossPosts: PostView[];
|
||||
}
|
||||
|
||||
export class PostForm extends Component<PostFormProps, PostFormState> {
|
||||
|
@ -72,10 +73,10 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
|
|||
private choices: any;
|
||||
private emptyState: PostFormState = {
|
||||
postForm: {
|
||||
community_id: null,
|
||||
name: null,
|
||||
nsfw: false,
|
||||
auth: null,
|
||||
community_id: null,
|
||||
auth: UserService.Instance.authField(),
|
||||
},
|
||||
loading: false,
|
||||
imageLoading: false,
|
||||
|
@ -93,16 +94,15 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
|
|||
|
||||
this.state = this.emptyState;
|
||||
|
||||
if (this.props.post) {
|
||||
// Means its an edit
|
||||
if (this.props.post_view) {
|
||||
this.state.postForm = {
|
||||
body: this.props.post.body,
|
||||
// NOTE: debouncing breaks both these for some reason, unless you use defaultValue
|
||||
name: this.props.post.name,
|
||||
community_id: this.props.post.community_id,
|
||||
edit_id: this.props.post.id,
|
||||
url: this.props.post.url,
|
||||
nsfw: this.props.post.nsfw,
|
||||
auth: null,
|
||||
body: this.props.post_view.post.body,
|
||||
name: this.props.post_view.post.name,
|
||||
community_id: this.props.post_view.community.id,
|
||||
url: this.props.post_view.post.url,
|
||||
nsfw: this.props.post_view.post.nsfw,
|
||||
auth: UserService.Instance.authField(),
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -285,7 +285,7 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
|
|||
/>
|
||||
</div>
|
||||
</div>
|
||||
{!this.props.post && (
|
||||
{!this.props.post_view && (
|
||||
<div class="form-group row">
|
||||
<label class="col-sm-2 col-form-label" htmlFor="post-community">
|
||||
{i18n.t('community')}
|
||||
|
@ -298,11 +298,13 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
|
|||
onInput={linkEvent(this, this.handlePostCommunityChange)}
|
||||
>
|
||||
<option>{i18n.t('select_a_community')}</option>
|
||||
{this.props.communities.map(community => (
|
||||
<option value={community.id}>
|
||||
{community.local
|
||||
? community.name
|
||||
: `${hostname(community.actor_id)}/${community.name}`}
|
||||
{this.props.communities.map(cv => (
|
||||
<option value={cv.community.id}>
|
||||
{cv.community.local
|
||||
? cv.community.name
|
||||
: `${hostname(cv.community.actor_id)}/${
|
||||
cv.community.name
|
||||
}`}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
|
@ -340,13 +342,13 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
|
|||
<svg class="icon icon-spinner spin">
|
||||
<use xlinkHref="#icon-spinner"></use>
|
||||
</svg>
|
||||
) : this.props.post ? (
|
||||
) : this.props.post_view ? (
|
||||
capitalizeFirstLetter(i18n.t('save'))
|
||||
) : (
|
||||
capitalizeFirstLetter(i18n.t('create'))
|
||||
)}
|
||||
</button>
|
||||
{this.props.post && (
|
||||
{this.props.post_view && (
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-secondary"
|
||||
|
@ -370,10 +372,14 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
|
|||
i.state.postForm.url = undefined;
|
||||
}
|
||||
|
||||
if (i.props.post) {
|
||||
WebSocketService.Instance.editPost(i.state.postForm);
|
||||
if (i.props.post_view) {
|
||||
let form: EditPost = {
|
||||
...i.state.postForm,
|
||||
edit_id: i.props.post_view.post.id,
|
||||
};
|
||||
WebSocketService.Instance.client.editPost(form);
|
||||
} else {
|
||||
WebSocketService.Instance.createPost(i.state.postForm);
|
||||
WebSocketService.Instance.client.createPost(i.state.postForm);
|
||||
}
|
||||
i.state.loading = true;
|
||||
i.setState(i.state);
|
||||
|
@ -396,15 +402,16 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
|
|||
|
||||
fetchPageTitle() {
|
||||
if (validURL(this.state.postForm.url)) {
|
||||
let form: SearchForm = {
|
||||
let form: Search = {
|
||||
q: this.state.postForm.url,
|
||||
type_: SearchType.Url,
|
||||
sort: SortType.TopAll,
|
||||
page: 1,
|
||||
limit: 6,
|
||||
auth: UserService.Instance.authField(false),
|
||||
};
|
||||
|
||||
WebSocketService.Instance.search(form);
|
||||
WebSocketService.Instance.client.search(form);
|
||||
|
||||
// Fetch the page title
|
||||
getPageTitle(this.state.postForm.url).then(d => {
|
||||
|
@ -424,17 +431,18 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
|
|||
}
|
||||
|
||||
fetchSimilarPosts() {
|
||||
let form: SearchForm = {
|
||||
let form: Search = {
|
||||
q: this.state.postForm.name,
|
||||
type_: SearchType.Posts,
|
||||
sort: SortType.TopAll,
|
||||
community_id: this.state.postForm.community_id,
|
||||
page: 1,
|
||||
limit: 6,
|
||||
auth: UserService.Instance.authField(false),
|
||||
};
|
||||
|
||||
if (this.state.postForm.name !== '') {
|
||||
WebSocketService.Instance.search(form);
|
||||
WebSocketService.Instance.client.search(form);
|
||||
} else {
|
||||
this.state.suggestedPosts = [];
|
||||
}
|
||||
|
@ -570,16 +578,16 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
|
|||
}
|
||||
}
|
||||
|
||||
if (this.props.post) {
|
||||
this.state.postForm.community_id = this.props.post.community_id;
|
||||
if (this.props.post_view) {
|
||||
this.state.postForm.community_id = this.props.post_view.community.id;
|
||||
} else if (
|
||||
this.props.params &&
|
||||
(this.props.params.community_id || this.props.params.community_name)
|
||||
) {
|
||||
if (this.props.params.community_name) {
|
||||
let foundCommunityId = this.props.communities.find(
|
||||
r => r.name == this.props.params.community_name
|
||||
).id;
|
||||
r => r.community.name == this.props.params.community_name
|
||||
).community.id;
|
||||
this.state.postForm.community_id = foundCommunityId;
|
||||
} else if (this.props.params.community_id) {
|
||||
this.state.postForm.community_id = this.props.params.community_id;
|
||||
|
@ -596,27 +604,27 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
|
|||
}
|
||||
}
|
||||
|
||||
parseMessage(msg: WebSocketJsonResponse) {
|
||||
let res = wsJsonToRes(msg);
|
||||
parseMessage(msg: any) {
|
||||
let op = wsUserOp(msg);
|
||||
if (msg.error) {
|
||||
toast(i18n.t(msg.error), 'danger');
|
||||
this.state.loading = false;
|
||||
this.setState(this.state);
|
||||
return;
|
||||
} else if (res.op == UserOperation.CreatePost) {
|
||||
let data = res.data as PostResponse;
|
||||
if (data.post.creator_id == UserService.Instance.user.id) {
|
||||
} else if (op == UserOperation.CreatePost) {
|
||||
let data = wsJsonToRes<PostResponse>(msg).data;
|
||||
if (data.post_view.creator.id == UserService.Instance.user.id) {
|
||||
this.state.loading = false;
|
||||
this.props.onCreate(data.post.id);
|
||||
this.props.onCreate(data.post_view);
|
||||
}
|
||||
} else if (res.op == UserOperation.EditPost) {
|
||||
let data = res.data as PostResponse;
|
||||
if (data.post.creator_id == UserService.Instance.user.id) {
|
||||
} else if (op == UserOperation.EditPost) {
|
||||
let data = wsJsonToRes<PostResponse>(msg).data;
|
||||
if (data.post_view.creator.id == UserService.Instance.user.id) {
|
||||
this.state.loading = false;
|
||||
this.props.onEdit(data.post);
|
||||
this.props.onEdit(data.post_view);
|
||||
}
|
||||
} else if (res.op == UserOperation.Search) {
|
||||
let data = res.data as SearchResponse;
|
||||
} else if (op == UserOperation.Search) {
|
||||
let data = wsJsonToRes<SearchResponse>(msg).data;
|
||||
|
||||
if (data.type_ == SearchType[SearchType.Posts]) {
|
||||
this.state.suggestedPosts = data.posts;
|
||||
|
|
|
@ -2,21 +2,21 @@ import { Component, linkEvent } from 'inferno';
|
|||
import { Link } from 'inferno-router';
|
||||
import { WebSocketService, UserService } from '../services';
|
||||
import {
|
||||
Post,
|
||||
CreatePostLikeForm,
|
||||
DeletePostForm,
|
||||
RemovePostForm,
|
||||
LockPostForm,
|
||||
StickyPostForm,
|
||||
SavePostForm,
|
||||
CommunityUser,
|
||||
UserView,
|
||||
BanFromCommunityForm,
|
||||
BanUserForm,
|
||||
AddModToCommunityForm,
|
||||
AddAdminForm,
|
||||
TransferSiteForm,
|
||||
TransferCommunityForm,
|
||||
PostView,
|
||||
CreatePostLike,
|
||||
DeletePost,
|
||||
RemovePost,
|
||||
LockPost,
|
||||
StickyPost,
|
||||
SavePost,
|
||||
UserViewSafe,
|
||||
BanFromCommunity,
|
||||
BanUser,
|
||||
AddModToCommunity,
|
||||
AddAdmin,
|
||||
TransferSite,
|
||||
TransferCommunity,
|
||||
CommunityModeratorView,
|
||||
} from 'lemmy-js-client';
|
||||
import { BanType } from '../interfaces';
|
||||
import { MomentTime } from './moment-time';
|
||||
|
@ -62,11 +62,12 @@ interface PostListingState {
|
|||
}
|
||||
|
||||
interface PostListingProps {
|
||||
post: Post;
|
||||
post_view: PostView;
|
||||
duplicates?: PostView[];
|
||||
showCommunity?: boolean;
|
||||
showBody?: boolean;
|
||||
moderators?: CommunityUser[];
|
||||
admins?: UserView[];
|
||||
moderators?: CommunityModeratorView[];
|
||||
admins?: UserViewSafe[];
|
||||
enableDownvotes: boolean;
|
||||
enableNsfw: boolean;
|
||||
}
|
||||
|
@ -87,10 +88,10 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
|
|||
viewSource: false,
|
||||
showAdvanced: false,
|
||||
showMoreMobile: false,
|
||||
my_vote: this.props.post.my_vote,
|
||||
score: this.props.post.score,
|
||||
upvotes: this.props.post.upvotes,
|
||||
downvotes: this.props.post.downvotes,
|
||||
my_vote: this.props.post_view.my_vote,
|
||||
score: this.props.post_view.counts.score,
|
||||
upvotes: this.props.post_view.counts.upvotes,
|
||||
downvotes: this.props.post_view.counts.downvotes,
|
||||
};
|
||||
|
||||
constructor(props: any, context: any) {
|
||||
|
@ -104,11 +105,11 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
|
|||
}
|
||||
|
||||
componentWillReceiveProps(nextProps: PostListingProps) {
|
||||
this.state.my_vote = nextProps.post.my_vote;
|
||||
this.state.upvotes = nextProps.post.upvotes;
|
||||
this.state.downvotes = nextProps.post.downvotes;
|
||||
this.state.score = nextProps.post.score;
|
||||
if (this.props.post.id !== nextProps.post.id) {
|
||||
this.state.my_vote = nextProps.post_view.my_vote;
|
||||
this.state.upvotes = nextProps.post_view.counts.upvotes;
|
||||
this.state.downvotes = nextProps.post_view.counts.downvotes;
|
||||
this.state.score = nextProps.post_view.counts.score;
|
||||
if (this.props.post_view.post.id !== nextProps.post_view.post.id) {
|
||||
this.state.imageExpanded = false;
|
||||
}
|
||||
this.setState(this.state);
|
||||
|
@ -125,7 +126,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
|
|||
) : (
|
||||
<div class="col-12">
|
||||
<PostForm
|
||||
post={this.props.post}
|
||||
post_view={this.props.post_view}
|
||||
onEdit={this.handleEditPost}
|
||||
onCancel={this.handleEditCancel}
|
||||
enableNsfw={this.props.enableNsfw}
|
||||
|
@ -138,22 +139,21 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
|
|||
}
|
||||
|
||||
body() {
|
||||
let post = this.props.post_view.post;
|
||||
return (
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
{this.props.post.url &&
|
||||
this.props.showBody &&
|
||||
this.props.post.embed_title && (
|
||||
<IFramelyCard post={this.props.post} />
|
||||
)}
|
||||
{post.url && this.props.showBody && post.embed_title && (
|
||||
<IFramelyCard post={post} />
|
||||
)}
|
||||
{this.props.showBody &&
|
||||
this.props.post.body &&
|
||||
post.body &&
|
||||
(this.state.viewSource ? (
|
||||
<pre>{this.props.post.body}</pre>
|
||||
<pre>{post.body}</pre>
|
||||
) : (
|
||||
<div
|
||||
className="md-div"
|
||||
dangerouslySetInnerHTML={mdToHtml(this.props.post.body)}
|
||||
dangerouslySetInnerHTML={mdToHtml(post.body)}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
|
@ -162,18 +162,18 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
|
|||
}
|
||||
|
||||
imgThumb(src: string) {
|
||||
let post = this.props.post;
|
||||
let post_view = this.props.post_view;
|
||||
return (
|
||||
<PictrsImage
|
||||
src={src}
|
||||
thumbnail
|
||||
nsfw={post.nsfw || post.community_nsfw}
|
||||
nsfw={post_view.post.nsfw || post_view.community.nsfw}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
getImageSrc(): string {
|
||||
let post = this.props.post;
|
||||
let post = this.props.post_view.post;
|
||||
if (isImage(post.url)) {
|
||||
if (post.url.includes('pictrs')) {
|
||||
return post.url;
|
||||
|
@ -190,7 +190,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
|
|||
}
|
||||
|
||||
thumbnail() {
|
||||
let post = this.props.post;
|
||||
let post = this.props.post_view.post;
|
||||
|
||||
if (isImage(post.url)) {
|
||||
return (
|
||||
|
@ -270,21 +270,11 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
|
|||
}
|
||||
|
||||
createdLine() {
|
||||
let post = this.props.post;
|
||||
let post_view = this.props.post_view;
|
||||
return (
|
||||
<ul class="list-inline mb-1 text-muted small">
|
||||
<li className="list-inline-item">
|
||||
<UserListing
|
||||
user={{
|
||||
name: post.creator_name,
|
||||
preferred_username: post.creator_preferred_username,
|
||||
avatar: post.creator_avatar,
|
||||
id: post.creator_id,
|
||||
local: post.creator_local,
|
||||
actor_id: post.creator_actor_id,
|
||||
published: post.creator_published,
|
||||
}}
|
||||
/>
|
||||
<UserListing user={post_view.creator} />
|
||||
|
||||
{this.isMod && (
|
||||
<span className="mx-1 badge badge-light">{i18n.t('mod')}</span>
|
||||
|
@ -292,36 +282,29 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
|
|||
{this.isAdmin && (
|
||||
<span className="mx-1 badge badge-light">{i18n.t('admin')}</span>
|
||||
)}
|
||||
{(post.banned_from_community || post.banned) && (
|
||||
{(post_view.creator_banned_from_community ||
|
||||
post_view.creator.banned) && (
|
||||
<span className="mx-1 badge badge-danger">{i18n.t('banned')}</span>
|
||||
)}
|
||||
{this.props.showCommunity && (
|
||||
<span>
|
||||
<span class="mx-1"> {i18n.t('to')} </span>
|
||||
<CommunityLink
|
||||
community={{
|
||||
name: post.community_name,
|
||||
id: post.community_id,
|
||||
local: post.community_local,
|
||||
actor_id: post.community_actor_id,
|
||||
icon: post.community_icon,
|
||||
}}
|
||||
/>
|
||||
<CommunityLink community={post_view.community} />
|
||||
</span>
|
||||
)}
|
||||
</li>
|
||||
<li className="list-inline-item">•</li>
|
||||
{post.url && !(hostname(post.url) == externalHost) && (
|
||||
{post_view.post.url && !(hostname(post_view.post.url) == externalHost) && (
|
||||
<>
|
||||
<li className="list-inline-item">
|
||||
<a
|
||||
className="text-muted font-italic"
|
||||
href={post.url}
|
||||
href={post_view.post.url}
|
||||
target="_blank"
|
||||
title={post.url}
|
||||
title={post_view.post.url}
|
||||
rel="noopener"
|
||||
>
|
||||
{hostname(post.url)}
|
||||
{hostname(post_view.post.url)}
|
||||
</a>
|
||||
</li>
|
||||
<li className="list-inline-item">•</li>
|
||||
|
@ -329,19 +312,21 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
|
|||
)}
|
||||
<li className="list-inline-item">
|
||||
<span>
|
||||
<MomentTime data={post} />
|
||||
<MomentTime data={post_view.post} />
|
||||
</span>
|
||||
</li>
|
||||
{post.body && (
|
||||
{post_view.post.body && (
|
||||
<>
|
||||
<li className="list-inline-item">•</li>
|
||||
<li className="list-inline-item">
|
||||
{/* Using a link with tippy doesn't work on touch devices unfortunately */}
|
||||
<Link
|
||||
className="text-muted"
|
||||
data-tippy-content={md.render(previewLines(post.body))}
|
||||
data-tippy-content={md.render(
|
||||
previewLines(post_view.post.body)
|
||||
)}
|
||||
data-tippy-allowHtml={true}
|
||||
to={`/post/${post.id}`}
|
||||
to={`/post/${post_view.post.id}`}
|
||||
>
|
||||
<svg class="mr-1 icon icon-inline">
|
||||
<use xlinkHref="#icon-book-open"></use>
|
||||
|
@ -392,7 +377,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
|
|||
}
|
||||
|
||||
postTitleLine() {
|
||||
let post = this.props.post;
|
||||
let post = this.props.post_view.post;
|
||||
return (
|
||||
<div className="post-title overflow-hidden">
|
||||
<h5>
|
||||
|
@ -415,7 +400,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
|
|||
{post.name}
|
||||
</Link>
|
||||
)}
|
||||
{(isImage(post.url) || this.props.post.thumbnail_url) &&
|
||||
{(isImage(post.url) || post.thumbnail_url) &&
|
||||
(!this.state.imageExpanded ? (
|
||||
<span
|
||||
class="text-monospace unselectable pointer ml-2 text-muted small"
|
||||
|
@ -492,22 +477,22 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
|
|||
}
|
||||
|
||||
commentsLine(mobile: boolean = false) {
|
||||
let post = this.props.post;
|
||||
let post_view = this.props.post_view;
|
||||
return (
|
||||
<div class="d-flex justify-content-between justify-content-lg-start flex-wrap text-muted font-weight-bold mb-1">
|
||||
<button class="btn btn-link text-muted p-0">
|
||||
<Link
|
||||
className="text-muted small"
|
||||
title={i18n.t('number_of_comments', {
|
||||
count: post.number_of_comments,
|
||||
count: post_view.counts.comments,
|
||||
})}
|
||||
to={`/post/${post.id}`}
|
||||
to={`/post/${post_view.post.id}`}
|
||||
>
|
||||
<svg class="mr-1 icon icon-inline">
|
||||
<use xlinkHref="#icon-message-square"></use>
|
||||
</svg>
|
||||
{i18n.t('number_of_comments', {
|
||||
count: post.number_of_comments,
|
||||
count: post_view.counts.comments,
|
||||
})}
|
||||
</Link>
|
||||
</button>
|
||||
|
@ -531,12 +516,14 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
|
|||
class="btn btn-link btn-animate text-muted py-0"
|
||||
onClick={linkEvent(this, this.handleSavePostClick)}
|
||||
data-tippy-content={
|
||||
post.saved ? i18n.t('unsave') : i18n.t('save')
|
||||
post_view.saved ? i18n.t('unsave') : i18n.t('save')
|
||||
}
|
||||
>
|
||||
<small>
|
||||
<svg
|
||||
class={`icon icon-inline ${post.saved && 'text-warning'}`}
|
||||
class={`icon icon-inline ${
|
||||
post_view.saved && 'text-warning'
|
||||
}`}
|
||||
>
|
||||
<use xlinkHref="#icon-star"></use>
|
||||
</svg>
|
||||
|
@ -583,10 +570,12 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
|
|||
class="btn btn-link btn-animate text-muted py-0 pl-1 pr-0"
|
||||
onClick={linkEvent(this, this.handleSavePostClick)}
|
||||
data-tippy-content={
|
||||
post.saved ? i18n.t('unsave') : i18n.t('save')
|
||||
post_view.saved ? i18n.t('unsave') : i18n.t('save')
|
||||
}
|
||||
>
|
||||
<svg class={`icon icon-inline ${post.saved && 'text-warning'}`}>
|
||||
<svg
|
||||
class={`icon icon-inline ${post_view.saved && 'text-warning'}`}
|
||||
>
|
||||
<use xlinkHref="#icon-star"></use>
|
||||
</svg>
|
||||
</button>
|
||||
|
@ -611,20 +600,18 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
|
|||
|
||||
duplicatesLine() {
|
||||
return (
|
||||
this.props.post.duplicates && (
|
||||
this.props.duplicates && (
|
||||
<ul class="list-inline mb-1 small text-muted">
|
||||
<>
|
||||
<li className="list-inline-item mr-2">
|
||||
{i18n.t('cross_posted_to')}
|
||||
</li>
|
||||
{this.props.post.duplicates.map(post => (
|
||||
{this.props.duplicates.map(pv => (
|
||||
<li className="list-inline-item mr-2">
|
||||
<Link to={`/post/${post.id}`}>
|
||||
{post.community_local
|
||||
? post.community_name
|
||||
: `${post.community_name}@${hostname(
|
||||
post.community_actor_id
|
||||
)}`}
|
||||
<Link to={`/post/${pv.post.id}`}>
|
||||
{pv.community.local
|
||||
? pv.community.name
|
||||
: `${pv.community.name}@${hostname(pv.community.actor_id)}`}
|
||||
</Link>
|
||||
</li>
|
||||
))}
|
||||
|
@ -635,7 +622,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
|
|||
}
|
||||
|
||||
postActions(mobile: boolean = false) {
|
||||
let post = this.props.post;
|
||||
let post_view = this.props.post_view;
|
||||
return (
|
||||
UserService.Instance.user && (
|
||||
<>
|
||||
|
@ -646,11 +633,13 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
|
|||
class="btn btn-link btn-animate text-muted py-0 pl-0"
|
||||
onClick={linkEvent(this, this.handleSavePostClick)}
|
||||
data-tippy-content={
|
||||
post.saved ? i18n.t('unsave') : i18n.t('save')
|
||||
post_view.saved ? i18n.t('unsave') : i18n.t('save')
|
||||
}
|
||||
>
|
||||
<svg
|
||||
class={`icon icon-inline ${post.saved && 'text-warning'}`}
|
||||
class={`icon icon-inline ${
|
||||
post_view.saved && 'text-warning'
|
||||
}`}
|
||||
>
|
||||
<use xlinkHref="#icon-star"></use>
|
||||
</svg>
|
||||
|
@ -682,11 +671,13 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
|
|||
class="btn btn-link btn-animate text-muted py-0"
|
||||
onClick={linkEvent(this, this.handleDeleteClick)}
|
||||
data-tippy-content={
|
||||
!post.deleted ? i18n.t('delete') : i18n.t('restore')
|
||||
!post_view.post.deleted ? i18n.t('delete') : i18n.t('restore')
|
||||
}
|
||||
>
|
||||
<svg
|
||||
class={`icon icon-inline ${post.deleted && 'text-danger'}`}
|
||||
class={`icon icon-inline ${
|
||||
post_view.post.deleted && 'text-danger'
|
||||
}`}
|
||||
>
|
||||
<use xlinkHref="#icon-trash"></use>
|
||||
</svg>
|
||||
|
@ -706,7 +697,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
|
|||
</button>
|
||||
) : (
|
||||
<>
|
||||
{this.props.showBody && post.body && (
|
||||
{this.props.showBody && post_view.post.body && (
|
||||
<button
|
||||
class="btn btn-link btn-animate text-muted py-0"
|
||||
onClick={linkEvent(this, this.handleViewSource)}
|
||||
|
@ -727,11 +718,13 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
|
|||
class="btn btn-link btn-animate text-muted py-0"
|
||||
onClick={linkEvent(this, this.handleModLock)}
|
||||
data-tippy-content={
|
||||
post.locked ? i18n.t('unlock') : i18n.t('lock')
|
||||
post_view.post.locked ? i18n.t('unlock') : i18n.t('lock')
|
||||
}
|
||||
>
|
||||
<svg
|
||||
class={`icon icon-inline ${post.locked && 'text-danger'}`}
|
||||
class={`icon icon-inline ${
|
||||
post_view.post.locked && 'text-danger'
|
||||
}`}
|
||||
>
|
||||
<use xlinkHref="#icon-lock"></use>
|
||||
</svg>
|
||||
|
@ -740,12 +733,14 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
|
|||
class="btn btn-link btn-animate text-muted py-0"
|
||||
onClick={linkEvent(this, this.handleModSticky)}
|
||||
data-tippy-content={
|
||||
post.stickied ? i18n.t('unsticky') : i18n.t('sticky')
|
||||
post_view.post.stickied
|
||||
? i18n.t('unsticky')
|
||||
: i18n.t('sticky')
|
||||
}
|
||||
>
|
||||
<svg
|
||||
class={`icon icon-inline ${
|
||||
post.stickied && 'text-success'
|
||||
post_view.post.stickied && 'text-success'
|
||||
}`}
|
||||
>
|
||||
<use xlinkHref="#icon-pin"></use>
|
||||
|
@ -755,7 +750,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
|
|||
)}
|
||||
{/* Mods can ban from community, and appoint as mods to community */}
|
||||
{(this.canMod || this.canAdmin) &&
|
||||
(!post.removed ? (
|
||||
(!post_view.post.removed ? (
|
||||
<button
|
||||
class="btn btn-link btn-animate text-muted py-0"
|
||||
onClick={linkEvent(this, this.handleModRemoveShow)}
|
||||
|
@ -773,7 +768,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
|
|||
{this.canMod && (
|
||||
<>
|
||||
{!this.isMod &&
|
||||
(!post.banned_from_community ? (
|
||||
(!post_view.creator_banned_from_community ? (
|
||||
<button
|
||||
class="btn btn-link btn-animate text-muted py-0"
|
||||
onClick={linkEvent(
|
||||
|
@ -794,22 +789,23 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
|
|||
{i18n.t('unban')}
|
||||
</button>
|
||||
))}
|
||||
{!post.banned_from_community && post.creator_local && (
|
||||
<button
|
||||
class="btn btn-link btn-animate text-muted py-0"
|
||||
onClick={linkEvent(this, this.handleAddModToCommunity)}
|
||||
>
|
||||
{this.isMod
|
||||
? i18n.t('remove_as_mod')
|
||||
: i18n.t('appoint_as_mod')}
|
||||
</button>
|
||||
)}
|
||||
{!post_view.creator_banned_from_community &&
|
||||
post_view.creator.local && (
|
||||
<button
|
||||
class="btn btn-link btn-animate text-muted py-0"
|
||||
onClick={linkEvent(this, this.handleAddModToCommunity)}
|
||||
>
|
||||
{this.isMod
|
||||
? i18n.t('remove_as_mod')
|
||||
: i18n.t('appoint_as_mod')}
|
||||
</button>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
{/* Community creators and admins can transfer community to another mod */}
|
||||
{(this.amCommunityCreator || this.canAdmin) &&
|
||||
this.isMod &&
|
||||
post.creator_local &&
|
||||
post_view.creator.local &&
|
||||
(!this.state.showConfirmTransferCommunity ? (
|
||||
<button
|
||||
class="btn btn-link btn-animate text-muted py-0"
|
||||
|
@ -846,7 +842,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
|
|||
{this.canAdmin && (
|
||||
<>
|
||||
{!this.isAdmin &&
|
||||
(!post.banned ? (
|
||||
(!post_view.creator.banned ? (
|
||||
<button
|
||||
class="btn btn-link btn-animate text-muted py-0"
|
||||
onClick={linkEvent(this, this.handleModBanShow)}
|
||||
|
@ -861,7 +857,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
|
|||
{i18n.t('unban_from_site')}
|
||||
</button>
|
||||
))}
|
||||
{!post.banned && post.creator_local && (
|
||||
{!post_view.creator.banned && post_view.creator.local && (
|
||||
<button
|
||||
class="btn btn-link btn-animate text-muted py-0"
|
||||
onClick={linkEvent(this, this.handleAddAdmin)}
|
||||
|
@ -916,7 +912,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
|
|||
}
|
||||
|
||||
removeAndBanDialogs() {
|
||||
let post = this.props.post;
|
||||
let post = this.props.post_view;
|
||||
return (
|
||||
<>
|
||||
{this.state.showRemoveDialog && (
|
||||
|
@ -972,7 +968,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
|
|||
{/* </div> */}
|
||||
<div class="form-group row">
|
||||
<button type="submit" class="btn btn-secondary">
|
||||
{i18n.t('ban')} {post.creator_name}
|
||||
{i18n.t('ban')} {post.creator.name}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
|
@ -982,7 +978,8 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
|
|||
}
|
||||
|
||||
mobileThumbnail() {
|
||||
return this.props.post.thumbnail_url || isImage(this.props.post.url) ? (
|
||||
let post = this.props.post_view.post;
|
||||
return post.thumbnail_url || isImage(post.url) ? (
|
||||
<div class="row">
|
||||
<div className={`${this.state.imageExpanded ? 'col-12' : 'col-8'}`}>
|
||||
{this.postTitleLine()}
|
||||
|
@ -998,13 +995,14 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
|
|||
}
|
||||
|
||||
showMobilePreview() {
|
||||
let post = this.props.post_view.post;
|
||||
return (
|
||||
this.props.post.body &&
|
||||
post.body &&
|
||||
!this.props.showBody && (
|
||||
<div
|
||||
className="md-div mb-1"
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: md.render(previewLines(this.props.post.body)),
|
||||
__html: md.render(previewLines(post.body)),
|
||||
}}
|
||||
/>
|
||||
)
|
||||
|
@ -1067,7 +1065,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
|
|||
private get myPost(): boolean {
|
||||
return (
|
||||
UserService.Instance.user &&
|
||||
this.props.post.creator_id == UserService.Instance.user.id
|
||||
this.props.post_view.creator.id == UserService.Instance.user.id
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -1075,8 +1073,8 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
|
|||
return (
|
||||
this.props.moderators &&
|
||||
isMod(
|
||||
this.props.moderators.map(m => m.user_id),
|
||||
this.props.post.creator_id
|
||||
this.props.moderators.map(m => m.moderator.id),
|
||||
this.props.post_view.creator.id
|
||||
)
|
||||
);
|
||||
}
|
||||
|
@ -1085,8 +1083,8 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
|
|||
return (
|
||||
this.props.admins &&
|
||||
isMod(
|
||||
this.props.admins.map(a => a.id),
|
||||
this.props.post.creator_id
|
||||
this.props.admins.map(a => a.user.id),
|
||||
this.props.post_view.creator.id
|
||||
)
|
||||
);
|
||||
}
|
||||
|
@ -1094,13 +1092,13 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
|
|||
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));
|
||||
.map(a => a.user.id)
|
||||
.concat(this.props.moderators.map(m => m.moderator.id));
|
||||
|
||||
return canMod(
|
||||
UserService.Instance.user,
|
||||
adminsThenMods,
|
||||
this.props.post.creator_id
|
||||
this.props.post_view.creator.id
|
||||
);
|
||||
} else {
|
||||
return false;
|
||||
|
@ -1110,13 +1108,13 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
|
|||
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));
|
||||
.map(a => a.user.id)
|
||||
.concat(this.props.moderators.map(m => m.moderator.id));
|
||||
|
||||
return canMod(
|
||||
UserService.Instance.user,
|
||||
adminsThenMods,
|
||||
this.props.post.creator_id,
|
||||
this.props.post_view.creator.id,
|
||||
true
|
||||
);
|
||||
} else {
|
||||
|
@ -1129,8 +1127,8 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
|
|||
this.props.admins &&
|
||||
canMod(
|
||||
UserService.Instance.user,
|
||||
this.props.admins.map(a => a.id),
|
||||
this.props.post.creator_id
|
||||
this.props.admins.map(a => a.user.id),
|
||||
this.props.post_view.creator.id
|
||||
)
|
||||
);
|
||||
}
|
||||
|
@ -1139,8 +1137,8 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
|
|||
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
|
||||
this.props.post_view.creator.id != UserService.Instance.user.id &&
|
||||
UserService.Instance.user.id == this.props.moderators[0].moderator.id
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -1148,8 +1146,8 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
|
|||
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
|
||||
this.props.post_view.creator.id != UserService.Instance.user.id &&
|
||||
UserService.Instance.user.id == this.props.admins[0].user.id
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -1174,12 +1172,13 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
|
|||
|
||||
i.state.my_vote = new_vote;
|
||||
|
||||
let form: CreatePostLikeForm = {
|
||||
post_id: i.props.post.id,
|
||||
let form: CreatePostLike = {
|
||||
post_id: i.props.post_view.post.id,
|
||||
score: i.state.my_vote,
|
||||
auth: UserService.Instance.authField(),
|
||||
};
|
||||
|
||||
WebSocketService.Instance.likePost(form);
|
||||
WebSocketService.Instance.client.likePost(form);
|
||||
i.setState(i.state);
|
||||
setupTippy();
|
||||
}
|
||||
|
@ -1205,12 +1204,13 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
|
|||
|
||||
i.state.my_vote = new_vote;
|
||||
|
||||
let form: CreatePostLikeForm = {
|
||||
post_id: i.props.post.id,
|
||||
let form: CreatePostLike = {
|
||||
post_id: i.props.post_view.post.id,
|
||||
score: i.state.my_vote,
|
||||
auth: UserService.Instance.authField(),
|
||||
};
|
||||
|
||||
WebSocketService.Instance.likePost(form);
|
||||
WebSocketService.Instance.client.likePost(form);
|
||||
i.setState(i.state);
|
||||
setupTippy();
|
||||
}
|
||||
|
@ -1232,33 +1232,35 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
|
|||
}
|
||||
|
||||
handleDeleteClick(i: PostListing) {
|
||||
let deleteForm: DeletePostForm = {
|
||||
edit_id: i.props.post.id,
|
||||
deleted: !i.props.post.deleted,
|
||||
auth: null,
|
||||
let deleteForm: DeletePost = {
|
||||
edit_id: i.props.post_view.post.id,
|
||||
deleted: !i.props.post_view.post.deleted,
|
||||
auth: UserService.Instance.authField(),
|
||||
};
|
||||
WebSocketService.Instance.deletePost(deleteForm);
|
||||
WebSocketService.Instance.client.deletePost(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,
|
||||
let saved =
|
||||
i.props.post_view.saved == undefined ? true : !i.props.post_view.saved;
|
||||
let form: SavePost = {
|
||||
post_id: i.props.post_view.post.id,
|
||||
save: saved,
|
||||
auth: UserService.Instance.authField(),
|
||||
};
|
||||
|
||||
WebSocketService.Instance.savePost(form);
|
||||
WebSocketService.Instance.client.savePost(form);
|
||||
}
|
||||
|
||||
get crossPostParams(): string {
|
||||
let params = `?title=${this.props.post.name}`;
|
||||
let post = this.props.post;
|
||||
let post = this.props.post_view.post;
|
||||
let params = `?title=${post.name}`;
|
||||
|
||||
if (post.url) {
|
||||
params += `&url=${encodeURIComponent(post.url)}`;
|
||||
}
|
||||
if (this.props.post.body) {
|
||||
params += `&body=${this.props.post.body}`;
|
||||
if (post.body) {
|
||||
params += `&body=${post.body}`;
|
||||
}
|
||||
return params;
|
||||
}
|
||||
|
@ -1280,34 +1282,34 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
|
|||
|
||||
handleModRemoveSubmit(i: PostListing) {
|
||||
event.preventDefault();
|
||||
let form: RemovePostForm = {
|
||||
edit_id: i.props.post.id,
|
||||
removed: !i.props.post.removed,
|
||||
let form: RemovePost = {
|
||||
edit_id: i.props.post_view.post.id,
|
||||
removed: !i.props.post_view.post.removed,
|
||||
reason: i.state.removeReason,
|
||||
auth: null,
|
||||
auth: UserService.Instance.authField(),
|
||||
};
|
||||
WebSocketService.Instance.removePost(form);
|
||||
WebSocketService.Instance.client.removePost(form);
|
||||
|
||||
i.state.showRemoveDialog = false;
|
||||
i.setState(i.state);
|
||||
}
|
||||
|
||||
handleModLock(i: PostListing) {
|
||||
let form: LockPostForm = {
|
||||
edit_id: i.props.post.id,
|
||||
locked: !i.props.post.locked,
|
||||
auth: null,
|
||||
let form: LockPost = {
|
||||
edit_id: i.props.post_view.post.id,
|
||||
locked: !i.props.post_view.post.locked,
|
||||
auth: UserService.Instance.authField(),
|
||||
};
|
||||
WebSocketService.Instance.lockPost(form);
|
||||
WebSocketService.Instance.client.lockPost(form);
|
||||
}
|
||||
|
||||
handleModSticky(i: PostListing) {
|
||||
let form: StickyPostForm = {
|
||||
edit_id: i.props.post.id,
|
||||
stickied: !i.props.post.stickied,
|
||||
auth: null,
|
||||
let form: StickyPost = {
|
||||
edit_id: i.props.post_view.post.id,
|
||||
stickied: !i.props.post_view.post.stickied,
|
||||
auth: UserService.Instance.authField(),
|
||||
};
|
||||
WebSocketService.Instance.stickyPost(form);
|
||||
WebSocketService.Instance.client.stickyPost(form);
|
||||
}
|
||||
|
||||
handleModBanFromCommunityShow(i: PostListing) {
|
||||
|
@ -1349,33 +1351,35 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
|
|||
|
||||
if (i.state.banType == BanType.Community) {
|
||||
// If its an unban, restore all their data
|
||||
let ban = !i.props.post.banned_from_community;
|
||||
let ban = !i.props.post_view.creator_banned_from_community;
|
||||
if (ban == false) {
|
||||
i.state.removeData = false;
|
||||
}
|
||||
let form: BanFromCommunityForm = {
|
||||
user_id: i.props.post.creator_id,
|
||||
community_id: i.props.post.community_id,
|
||||
let form: BanFromCommunity = {
|
||||
user_id: i.props.post_view.creator.id,
|
||||
community_id: i.props.post_view.community.id,
|
||||
ban,
|
||||
remove_data: i.state.removeData,
|
||||
reason: i.state.banReason,
|
||||
expires: getUnixTime(i.state.banExpires),
|
||||
auth: UserService.Instance.authField(),
|
||||
};
|
||||
WebSocketService.Instance.banFromCommunity(form);
|
||||
WebSocketService.Instance.client.banFromCommunity(form);
|
||||
} else {
|
||||
// If its an unban, restore all their data
|
||||
let ban = !i.props.post.banned;
|
||||
let ban = !i.props.post_view.creator.banned;
|
||||
if (ban == false) {
|
||||
i.state.removeData = false;
|
||||
}
|
||||
let form: BanUserForm = {
|
||||
user_id: i.props.post.creator_id,
|
||||
let form: BanUser = {
|
||||
user_id: i.props.post_view.creator.id,
|
||||
ban,
|
||||
remove_data: i.state.removeData,
|
||||
reason: i.state.banReason,
|
||||
expires: getUnixTime(i.state.banExpires),
|
||||
auth: UserService.Instance.authField(),
|
||||
};
|
||||
WebSocketService.Instance.banUser(form);
|
||||
WebSocketService.Instance.client.banUser(form);
|
||||
}
|
||||
|
||||
i.state.showBanDialog = false;
|
||||
|
@ -1383,21 +1387,23 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
|
|||
}
|
||||
|
||||
handleAddModToCommunity(i: PostListing) {
|
||||
let form: AddModToCommunityForm = {
|
||||
user_id: i.props.post.creator_id,
|
||||
community_id: i.props.post.community_id,
|
||||
let form: AddModToCommunity = {
|
||||
user_id: i.props.post_view.creator.id,
|
||||
community_id: i.props.post_view.community.id,
|
||||
added: !i.isMod,
|
||||
auth: UserService.Instance.authField(),
|
||||
};
|
||||
WebSocketService.Instance.addModToCommunity(form);
|
||||
WebSocketService.Instance.client.addModToCommunity(form);
|
||||
i.setState(i.state);
|
||||
}
|
||||
|
||||
handleAddAdmin(i: PostListing) {
|
||||
let form: AddAdminForm = {
|
||||
user_id: i.props.post.creator_id,
|
||||
let form: AddAdmin = {
|
||||
user_id: i.props.post_view.creator.id,
|
||||
added: !i.isAdmin,
|
||||
auth: UserService.Instance.authField(),
|
||||
};
|
||||
WebSocketService.Instance.addAdmin(form);
|
||||
WebSocketService.Instance.client.addAdmin(form);
|
||||
i.setState(i.state);
|
||||
}
|
||||
|
||||
|
@ -1412,11 +1418,12 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
|
|||
}
|
||||
|
||||
handleTransferCommunity(i: PostListing) {
|
||||
let form: TransferCommunityForm = {
|
||||
community_id: i.props.post.community_id,
|
||||
user_id: i.props.post.creator_id,
|
||||
let form: TransferCommunity = {
|
||||
community_id: i.props.post_view.community.id,
|
||||
user_id: i.props.post_view.creator.id,
|
||||
auth: UserService.Instance.authField(),
|
||||
};
|
||||
WebSocketService.Instance.transferCommunity(form);
|
||||
WebSocketService.Instance.client.transferCommunity(form);
|
||||
i.state.showConfirmTransferCommunity = false;
|
||||
i.setState(i.state);
|
||||
}
|
||||
|
@ -1432,10 +1439,11 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
|
|||
}
|
||||
|
||||
handleTransferSite(i: PostListing) {
|
||||
let form: TransferSiteForm = {
|
||||
user_id: i.props.post.creator_id,
|
||||
let form: TransferSite = {
|
||||
user_id: i.props.post_view.creator.id,
|
||||
auth: UserService.Instance.authField(),
|
||||
};
|
||||
WebSocketService.Instance.transferSite(form);
|
||||
WebSocketService.Instance.client.transferSite(form);
|
||||
i.state.showConfirmTransferSite = false;
|
||||
i.setState(i.state);
|
||||
}
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
import { Component } from 'inferno';
|
||||
import { Link } from 'inferno-router';
|
||||
import { Post, SortType } from 'lemmy-js-client';
|
||||
import { PostView, SortType } from 'lemmy-js-client';
|
||||
import { postSort } from '../utils';
|
||||
import { PostListing } from './post-listing';
|
||||
import { i18n } from '../i18next';
|
||||
import { T } from 'inferno-i18next';
|
||||
|
||||
interface PostListingsProps {
|
||||
posts: Post[];
|
||||
posts: PostView[];
|
||||
showCommunity?: boolean;
|
||||
removeDuplicates?: boolean;
|
||||
sort?: SortType;
|
||||
|
@ -16,6 +16,8 @@ interface PostListingsProps {
|
|||
}
|
||||
|
||||
export class PostListings extends Component<PostListingsProps, any> {
|
||||
private duplicatesMap = new Map<number, PostView[]>();
|
||||
|
||||
constructor(props: any, context: any) {
|
||||
super(props, context);
|
||||
}
|
||||
|
@ -24,10 +26,11 @@ export class PostListings extends Component<PostListingsProps, any> {
|
|||
return (
|
||||
<div>
|
||||
{this.props.posts.length > 0 ? (
|
||||
this.outer().map(post => (
|
||||
this.outer().map(post_view => (
|
||||
<>
|
||||
<PostListing
|
||||
post={post}
|
||||
post_view={post_view}
|
||||
duplicates={this.duplicatesMap.get(post_view.post.id)}
|
||||
showCommunity={this.props.showCommunity}
|
||||
enableDownvotes={this.props.enableDownvotes}
|
||||
enableNsfw={this.props.enableNsfw}
|
||||
|
@ -49,7 +52,7 @@ export class PostListings extends Component<PostListingsProps, any> {
|
|||
);
|
||||
}
|
||||
|
||||
outer(): Post[] {
|
||||
outer(): PostView[] {
|
||||
let out = this.props.posts;
|
||||
if (this.props.removeDuplicates) {
|
||||
out = this.removeDuplicates(out);
|
||||
|
@ -62,23 +65,23 @@ export class PostListings extends Component<PostListingsProps, any> {
|
|||
return out;
|
||||
}
|
||||
|
||||
removeDuplicates(posts: Post[]): Post[] {
|
||||
removeDuplicates(posts: PostView[]): PostView[] {
|
||||
// A map from post url to list of posts (dupes)
|
||||
let urlMap = new Map<string, Post[]>();
|
||||
let urlMap = new Map<string, PostView[]>();
|
||||
|
||||
// Loop over the posts, find ones with same urls
|
||||
for (let post of posts) {
|
||||
for (let pv of posts) {
|
||||
if (
|
||||
post.url &&
|
||||
!post.deleted &&
|
||||
!post.removed &&
|
||||
!post.community_deleted &&
|
||||
!post.community_removed
|
||||
pv.post.url &&
|
||||
!pv.post.deleted &&
|
||||
!pv.post.removed &&
|
||||
!pv.community.deleted &&
|
||||
!pv.community.removed
|
||||
) {
|
||||
if (!urlMap.get(post.url)) {
|
||||
urlMap.set(post.url, [post]);
|
||||
if (!urlMap.get(pv.post.url)) {
|
||||
urlMap.set(pv.post.url, [pv]);
|
||||
} else {
|
||||
urlMap.get(post.url).push(post);
|
||||
urlMap.get(pv.post.url).push(pv);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -89,18 +92,18 @@ export class PostListings extends Component<PostListingsProps, any> {
|
|||
if (e[1].length == 1) {
|
||||
urlMap.delete(e[0]);
|
||||
} else {
|
||||
e[1].sort((a, b) => a.published.localeCompare(b.published));
|
||||
e[1].sort((a, b) => a.post.published.localeCompare(b.post.published));
|
||||
}
|
||||
}
|
||||
|
||||
for (let i = 0; i < posts.length; i++) {
|
||||
let post = posts[i];
|
||||
if (post.url) {
|
||||
let found = urlMap.get(post.url);
|
||||
let pv = posts[i];
|
||||
if (pv.post.url) {
|
||||
let found = urlMap.get(pv.post.url);
|
||||
if (found) {
|
||||
// If its the oldest, add
|
||||
if (post.id == found[0].id) {
|
||||
post.duplicates = found.slice(1);
|
||||
if (pv.post.id == found[0].post.id) {
|
||||
this.duplicatesMap.set(pv.post.id, found.slice(1));
|
||||
}
|
||||
// Otherwise, delete it
|
||||
else {
|
||||
|
|
|
@ -3,25 +3,23 @@ import { HtmlTags } from './html-tags';
|
|||
import { Subscription } from 'rxjs';
|
||||
import {
|
||||
UserOperation,
|
||||
Post as PostI,
|
||||
PostView,
|
||||
GetPostResponse,
|
||||
PostResponse,
|
||||
MarkCommentAsReadForm,
|
||||
MarkCommentAsRead,
|
||||
CommentResponse,
|
||||
CommunityResponse,
|
||||
CommentNode as CommentNodeI,
|
||||
BanFromCommunityResponse,
|
||||
BanUserResponse,
|
||||
AddModToCommunityResponse,
|
||||
AddAdminResponse,
|
||||
SearchType,
|
||||
SortType,
|
||||
SearchForm,
|
||||
GetPostForm,
|
||||
Search,
|
||||
GetPost,
|
||||
SearchResponse,
|
||||
GetSiteResponse,
|
||||
GetCommunityResponse,
|
||||
WebSocketJsonResponse,
|
||||
ListCategoriesResponse,
|
||||
Category,
|
||||
} from 'lemmy-js-client';
|
||||
|
@ -29,6 +27,7 @@ import {
|
|||
CommentSortType,
|
||||
CommentViewType,
|
||||
InitialFetchRequest,
|
||||
CommentNode as CommentNodeI,
|
||||
} from '../interfaces';
|
||||
import { WebSocketService, UserService } from '../services';
|
||||
import {
|
||||
|
@ -44,10 +43,10 @@ import {
|
|||
getIdFromProps,
|
||||
getCommentIdFromProps,
|
||||
wsSubscribe,
|
||||
setAuth,
|
||||
isBrowser,
|
||||
previewLines,
|
||||
isImage,
|
||||
wsUserOp,
|
||||
} from '../utils';
|
||||
import { PostListing } from './post-listing';
|
||||
import { Sidebar } from './sidebar';
|
||||
|
@ -64,7 +63,7 @@ interface PostState {
|
|||
commentViewType: CommentViewType;
|
||||
scrolled?: boolean;
|
||||
loading: boolean;
|
||||
crossPosts: PostI[];
|
||||
crossPosts: PostView[];
|
||||
siteRes: GetSiteResponse;
|
||||
categories: Category[];
|
||||
}
|
||||
|
@ -81,7 +80,7 @@ export class Post extends Component<any, PostState> {
|
|||
scrolled: false,
|
||||
loading: true,
|
||||
crossPosts: [],
|
||||
siteRes: this.isoData.site,
|
||||
siteRes: this.isoData.site_res,
|
||||
categories: [],
|
||||
};
|
||||
|
||||
|
@ -104,15 +103,16 @@ export class Post extends Component<any, PostState> {
|
|||
}
|
||||
} else {
|
||||
this.fetchPost();
|
||||
WebSocketService.Instance.listCategories();
|
||||
WebSocketService.Instance.client.listCategories();
|
||||
}
|
||||
}
|
||||
|
||||
fetchPost() {
|
||||
let form: GetPostForm = {
|
||||
let form: GetPost = {
|
||||
id: this.state.postId,
|
||||
auth: UserService.Instance.authField(false),
|
||||
};
|
||||
WebSocketService.Instance.getPost(form);
|
||||
WebSocketService.Instance.client.getPost(form);
|
||||
}
|
||||
|
||||
static fetchInitialData(req: InitialFetchRequest): Promise<any>[] {
|
||||
|
@ -121,10 +121,10 @@ export class Post extends Component<any, PostState> {
|
|||
|
||||
let id = Number(pathSplit[2]);
|
||||
|
||||
let postForm: GetPostForm = {
|
||||
let postForm: GetPost = {
|
||||
id,
|
||||
auth: req.auth,
|
||||
};
|
||||
setAuth(postForm, req.auth);
|
||||
|
||||
promises.push(req.client.getPost(postForm));
|
||||
promises.push(req.client.listCategories());
|
||||
|
@ -138,7 +138,7 @@ export class Post extends Component<any, PostState> {
|
|||
}
|
||||
|
||||
componentDidMount() {
|
||||
WebSocketService.Instance.postJoin({ post_id: this.state.postId });
|
||||
WebSocketService.Instance.client.postJoin({ post_id: this.state.postId });
|
||||
autosize(document.querySelectorAll('textarea'));
|
||||
}
|
||||
|
||||
|
@ -172,23 +172,28 @@ export class Post extends Component<any, PostState> {
|
|||
this.markScrolledAsRead(this.state.commentId);
|
||||
}
|
||||
|
||||
// TODO this needs some re-work
|
||||
markScrolledAsRead(commentId: number) {
|
||||
let found = this.state.postRes.comments.find(c => c.id == commentId);
|
||||
let parent = this.state.postRes.comments.find(c => found.parent_id == c.id);
|
||||
let found = this.state.postRes.comments.find(
|
||||
c => c.comment.id == commentId
|
||||
);
|
||||
let parent = this.state.postRes.comments.find(
|
||||
c => found.comment.parent_id == c.comment.id
|
||||
);
|
||||
let parent_user_id = parent
|
||||
? parent.creator_id
|
||||
: this.state.postRes.post.creator_id;
|
||||
? parent.creator.id
|
||||
: this.state.postRes.post_view.creator.id;
|
||||
|
||||
if (
|
||||
UserService.Instance.user &&
|
||||
UserService.Instance.user.id == parent_user_id
|
||||
) {
|
||||
let form: MarkCommentAsReadForm = {
|
||||
edit_id: found.id,
|
||||
let form: MarkCommentAsRead = {
|
||||
comment_id: found.creator.id,
|
||||
read: true,
|
||||
auth: null,
|
||||
auth: UserService.Instance.authField(),
|
||||
};
|
||||
WebSocketService.Instance.markCommentAsRead(form);
|
||||
WebSocketService.Instance.client.markCommentAsRead(form);
|
||||
UserService.Instance.unreadCountSub.next(
|
||||
UserService.Instance.unreadCountSub.value - 1
|
||||
);
|
||||
|
@ -196,27 +201,24 @@ export class Post extends Component<any, PostState> {
|
|||
}
|
||||
|
||||
get documentTitle(): string {
|
||||
return `${this.state.postRes.post.name} - ${this.state.siteRes.site.name}`;
|
||||
return `${this.state.postRes.post_view.post.name} - ${this.state.siteRes.site_view.site.name}`;
|
||||
}
|
||||
|
||||
get imageTag(): string {
|
||||
let post = this.state.postRes.post_view.post;
|
||||
return (
|
||||
this.state.postRes.post.thumbnail_url ||
|
||||
(this.state.postRes.post.url
|
||||
? isImage(this.state.postRes.post.url)
|
||||
? this.state.postRes.post.url
|
||||
: undefined
|
||||
: undefined)
|
||||
post.thumbnail_url ||
|
||||
(post.url ? (isImage(post.url) ? post.url : undefined) : undefined)
|
||||
);
|
||||
}
|
||||
|
||||
get descriptionTag(): string {
|
||||
return this.state.postRes.post.body
|
||||
? previewLines(this.state.postRes.post.body)
|
||||
: undefined;
|
||||
let body = this.state.postRes.post_view.post.body;
|
||||
return body ? previewLines(body) : undefined;
|
||||
}
|
||||
|
||||
render() {
|
||||
let pv = this.state.postRes.post_view;
|
||||
return (
|
||||
<div class="container">
|
||||
{this.state.loading ? (
|
||||
|
@ -235,18 +237,21 @@ export class Post extends Component<any, PostState> {
|
|||
description={this.descriptionTag}
|
||||
/>
|
||||
<PostListing
|
||||
post={this.state.postRes.post}
|
||||
post_view={pv}
|
||||
duplicates={this.state.crossPosts}
|
||||
showBody
|
||||
showCommunity
|
||||
moderators={this.state.postRes.moderators}
|
||||
admins={this.state.siteRes.admins}
|
||||
enableDownvotes={this.state.siteRes.site.enable_downvotes}
|
||||
enableNsfw={this.state.siteRes.site.enable_nsfw}
|
||||
enableDownvotes={
|
||||
this.state.siteRes.site_view.site.enable_downvotes
|
||||
}
|
||||
enableNsfw={this.state.siteRes.site_view.site.enable_nsfw}
|
||||
/>
|
||||
<div className="mb-2" />
|
||||
<CommentForm
|
||||
postId={this.state.postId}
|
||||
disabled={this.state.postRes.post.locked}
|
||||
disabled={pv.post.locked}
|
||||
/>
|
||||
{this.state.postRes.comments.length > 0 && this.sortRadios()}
|
||||
{this.state.commentViewType == CommentViewType.Tree &&
|
||||
|
@ -343,12 +348,12 @@ export class Post extends Component<any, PostState> {
|
|||
<CommentNodes
|
||||
nodes={commentsToFlatNodes(this.state.postRes.comments)}
|
||||
noIndent
|
||||
locked={this.state.postRes.post.locked}
|
||||
locked={this.state.postRes.post_view.post.locked}
|
||||
moderators={this.state.postRes.moderators}
|
||||
admins={this.state.siteRes.admins}
|
||||
postCreatorId={this.state.postRes.post.creator_id}
|
||||
postCreatorId={this.state.postRes.post_view.creator.id}
|
||||
showContext
|
||||
enableDownvotes={this.state.siteRes.site.enable_downvotes}
|
||||
enableDownvotes={this.state.siteRes.site_view.site.enable_downvotes}
|
||||
sort={this.state.commentSort}
|
||||
/>
|
||||
</div>
|
||||
|
@ -359,11 +364,11 @@ export class Post extends Component<any, PostState> {
|
|||
return (
|
||||
<div class="mb-3">
|
||||
<Sidebar
|
||||
community={this.state.postRes.community}
|
||||
community_view={this.state.postRes.community_view}
|
||||
moderators={this.state.postRes.moderators}
|
||||
admins={this.state.siteRes.admins}
|
||||
online={this.state.postRes.online}
|
||||
enableNsfw={this.state.siteRes.site.enable_nsfw}
|
||||
enableNsfw={this.state.siteRes.site_view.site.enable_nsfw}
|
||||
showIcon
|
||||
categories={this.state.categories}
|
||||
/>
|
||||
|
@ -385,18 +390,18 @@ export class Post extends Component<any, PostState> {
|
|||
|
||||
buildCommentsTree(): CommentNodeI[] {
|
||||
let map = new Map<number, CommentNodeI>();
|
||||
for (let comment of this.state.postRes.comments) {
|
||||
for (let comment_view of this.state.postRes.comments) {
|
||||
let node: CommentNodeI = {
|
||||
comment: comment,
|
||||
comment_view: comment_view,
|
||||
children: [],
|
||||
};
|
||||
map.set(comment.id, { ...node });
|
||||
map.set(comment_view.comment.id, { ...node });
|
||||
}
|
||||
let tree: CommentNodeI[] = [];
|
||||
for (let comment of this.state.postRes.comments) {
|
||||
let child = map.get(comment.id);
|
||||
if (comment.parent_id) {
|
||||
let parent_ = map.get(comment.parent_id);
|
||||
for (let comment_view of this.state.postRes.comments) {
|
||||
let child = map.get(comment_view.comment.id);
|
||||
if (comment_view.comment.parent_id) {
|
||||
let parent_ = map.get(comment_view.comment.parent_id);
|
||||
parent_.children.push(child);
|
||||
} else {
|
||||
tree.push(child);
|
||||
|
@ -410,7 +415,7 @@ export class Post extends Component<any, PostState> {
|
|||
|
||||
setDepth(node: CommentNodeI, i: number = 0): void {
|
||||
for (let child of node.children) {
|
||||
child.comment.depth = i;
|
||||
child.depth = i;
|
||||
this.setDepth(child, i + 1);
|
||||
}
|
||||
}
|
||||
|
@ -421,155 +426,146 @@ export class Post extends Component<any, PostState> {
|
|||
<div>
|
||||
<CommentNodes
|
||||
nodes={nodes}
|
||||
locked={this.state.postRes.post.locked}
|
||||
locked={this.state.postRes.post_view.post.locked}
|
||||
moderators={this.state.postRes.moderators}
|
||||
admins={this.state.siteRes.admins}
|
||||
postCreatorId={this.state.postRes.post.creator_id}
|
||||
postCreatorId={this.state.postRes.post_view.creator.id}
|
||||
sort={this.state.commentSort}
|
||||
enableDownvotes={this.state.siteRes.site.enable_downvotes}
|
||||
enableDownvotes={this.state.siteRes.site_view.site.enable_downvotes}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
parseMessage(msg: WebSocketJsonResponse) {
|
||||
console.log(msg);
|
||||
let res = wsJsonToRes(msg);
|
||||
parseMessage(msg: any) {
|
||||
let op = wsUserOp(msg);
|
||||
if (msg.error) {
|
||||
toast(i18n.t(msg.error), 'danger');
|
||||
return;
|
||||
} else if (msg.reconnect) {
|
||||
let postId = Number(this.props.match.params.id);
|
||||
WebSocketService.Instance.postJoin({ post_id: postId });
|
||||
WebSocketService.Instance.getPost({
|
||||
WebSocketService.Instance.client.postJoin({ post_id: postId });
|
||||
WebSocketService.Instance.client.getPost({
|
||||
id: postId,
|
||||
auth: UserService.Instance.authField(false),
|
||||
});
|
||||
} else if (res.op == UserOperation.GetPost) {
|
||||
let data = res.data as GetPostResponse;
|
||||
} else if (op == UserOperation.GetPost) {
|
||||
let data = wsJsonToRes<GetPostResponse>(msg).data;
|
||||
this.state.postRes = data;
|
||||
this.state.loading = false;
|
||||
|
||||
// Get cross-posts
|
||||
if (this.state.postRes.post.url) {
|
||||
let form: SearchForm = {
|
||||
q: this.state.postRes.post.url,
|
||||
if (this.state.postRes.post_view.post.url) {
|
||||
let form: Search = {
|
||||
q: this.state.postRes.post_view.post.url,
|
||||
type_: SearchType.Url,
|
||||
sort: SortType.TopAll,
|
||||
page: 1,
|
||||
limit: 6,
|
||||
auth: UserService.Instance.authField(false),
|
||||
};
|
||||
WebSocketService.Instance.search(form);
|
||||
WebSocketService.Instance.client.search(form);
|
||||
}
|
||||
|
||||
this.setState(this.state);
|
||||
setupTippy();
|
||||
} else if (res.op == UserOperation.CreateComment) {
|
||||
let data = res.data as CommentResponse;
|
||||
} else if (op == UserOperation.CreateComment) {
|
||||
let data = wsJsonToRes<CommentResponse>(msg).data;
|
||||
|
||||
// Necessary since it might be a user reply
|
||||
if (data.recipient_ids.length == 0) {
|
||||
this.state.postRes.comments.unshift(data.comment);
|
||||
this.state.postRes.comments.unshift(data.comment_view);
|
||||
this.setState(this.state);
|
||||
}
|
||||
} else if (
|
||||
res.op == UserOperation.EditComment ||
|
||||
res.op == UserOperation.DeleteComment ||
|
||||
res.op == UserOperation.RemoveComment
|
||||
op == UserOperation.EditComment ||
|
||||
op == UserOperation.DeleteComment ||
|
||||
op == UserOperation.RemoveComment
|
||||
) {
|
||||
let data = res.data as CommentResponse;
|
||||
editCommentRes(data, this.state.postRes.comments);
|
||||
let data = wsJsonToRes<CommentResponse>(msg).data;
|
||||
editCommentRes(data.comment_view, this.state.postRes.comments);
|
||||
this.setState(this.state);
|
||||
} else if (res.op == UserOperation.SaveComment) {
|
||||
let data = res.data as CommentResponse;
|
||||
saveCommentRes(data, this.state.postRes.comments);
|
||||
} else if (op == UserOperation.SaveComment) {
|
||||
let data = wsJsonToRes<CommentResponse>(msg).data;
|
||||
saveCommentRes(data.comment_view, this.state.postRes.comments);
|
||||
this.setState(this.state);
|
||||
setupTippy();
|
||||
} else if (res.op == UserOperation.CreateCommentLike) {
|
||||
let data = res.data as CommentResponse;
|
||||
createCommentLikeRes(data, this.state.postRes.comments);
|
||||
} else if (op == UserOperation.CreateCommentLike) {
|
||||
let data = wsJsonToRes<CommentResponse>(msg).data;
|
||||
createCommentLikeRes(data.comment_view, this.state.postRes.comments);
|
||||
this.setState(this.state);
|
||||
} else if (res.op == UserOperation.CreatePostLike) {
|
||||
let data = res.data as PostResponse;
|
||||
createPostLikeRes(data, this.state.postRes.post);
|
||||
} else if (op == UserOperation.CreatePostLike) {
|
||||
let data = wsJsonToRes<PostResponse>(msg).data;
|
||||
createPostLikeRes(data.post_view, this.state.postRes.post_view);
|
||||
this.setState(this.state);
|
||||
} else if (
|
||||
res.op == UserOperation.EditPost ||
|
||||
res.op == UserOperation.DeletePost ||
|
||||
res.op == UserOperation.RemovePost ||
|
||||
res.op == UserOperation.LockPost ||
|
||||
res.op == UserOperation.StickyPost
|
||||
op == UserOperation.EditPost ||
|
||||
op == UserOperation.DeletePost ||
|
||||
op == UserOperation.RemovePost ||
|
||||
op == UserOperation.LockPost ||
|
||||
op == UserOperation.StickyPost ||
|
||||
op == UserOperation.SavePost
|
||||
) {
|
||||
let data = res.data as PostResponse;
|
||||
this.state.postRes.post = data.post;
|
||||
this.setState(this.state);
|
||||
setupTippy();
|
||||
} else if (res.op == UserOperation.SavePost) {
|
||||
let data = res.data as PostResponse;
|
||||
this.state.postRes.post = data.post;
|
||||
let data = wsJsonToRes<PostResponse>(msg).data;
|
||||
this.state.postRes.post_view = data.post_view;
|
||||
this.setState(this.state);
|
||||
setupTippy();
|
||||
} else if (
|
||||
res.op == UserOperation.EditCommunity ||
|
||||
res.op == UserOperation.DeleteCommunity ||
|
||||
res.op == UserOperation.RemoveCommunity
|
||||
op == UserOperation.EditCommunity ||
|
||||
op == UserOperation.DeleteCommunity ||
|
||||
op == UserOperation.RemoveCommunity ||
|
||||
op == UserOperation.FollowCommunity
|
||||
) {
|
||||
let data = res.data as CommunityResponse;
|
||||
this.state.postRes.community = data.community;
|
||||
this.state.postRes.post.community_id = data.community.id;
|
||||
this.state.postRes.post.community_name = data.community.name;
|
||||
let data = wsJsonToRes<CommunityResponse>(msg).data;
|
||||
this.state.postRes.community_view = data.community_view;
|
||||
this.state.postRes.post_view.community = data.community_view.community;
|
||||
this.setState(this.state);
|
||||
} else if (res.op == UserOperation.FollowCommunity) {
|
||||
let data = res.data as CommunityResponse;
|
||||
this.state.postRes.community.subscribed = data.community.subscribed;
|
||||
this.state.postRes.community.number_of_subscribers =
|
||||
data.community.number_of_subscribers;
|
||||
this.setState(this.state);
|
||||
} else if (res.op == UserOperation.BanFromCommunity) {
|
||||
let data = res.data as BanFromCommunityResponse;
|
||||
} else if (op == UserOperation.BanFromCommunity) {
|
||||
let data = wsJsonToRes<BanFromCommunityResponse>(msg).data;
|
||||
this.state.postRes.comments
|
||||
.filter(c => c.creator_id == data.user.id)
|
||||
.forEach(c => (c.banned_from_community = data.banned));
|
||||
if (this.state.postRes.post.creator_id == data.user.id) {
|
||||
this.state.postRes.post.banned_from_community = data.banned;
|
||||
.filter(c => c.creator.id == data.user_view.user.id)
|
||||
.forEach(c => (c.creator_banned_from_community = data.banned));
|
||||
if (this.state.postRes.post_view.creator.id == data.user_view.user.id) {
|
||||
this.state.postRes.post_view.creator_banned_from_community =
|
||||
data.banned;
|
||||
}
|
||||
this.setState(this.state);
|
||||
} else if (res.op == UserOperation.AddModToCommunity) {
|
||||
let data = res.data as AddModToCommunityResponse;
|
||||
} else if (op == UserOperation.AddModToCommunity) {
|
||||
let data = wsJsonToRes<AddModToCommunityResponse>(msg).data;
|
||||
this.state.postRes.moderators = data.moderators;
|
||||
this.setState(this.state);
|
||||
} else if (res.op == UserOperation.BanUser) {
|
||||
let data = res.data as BanUserResponse;
|
||||
} else if (op == UserOperation.BanUser) {
|
||||
let data = wsJsonToRes<BanUserResponse>(msg).data;
|
||||
this.state.postRes.comments
|
||||
.filter(c => c.creator_id == data.user.id)
|
||||
.forEach(c => (c.banned = data.banned));
|
||||
if (this.state.postRes.post.creator_id == data.user.id) {
|
||||
this.state.postRes.post.banned = data.banned;
|
||||
.filter(c => c.creator.id == data.user_view.user.id)
|
||||
.forEach(c => (c.creator.banned = data.banned));
|
||||
if (this.state.postRes.post_view.creator.id == data.user_view.user.id) {
|
||||
this.state.postRes.post_view.creator.banned = data.banned;
|
||||
}
|
||||
this.setState(this.state);
|
||||
} else if (res.op == UserOperation.AddAdmin) {
|
||||
let data = res.data as AddAdminResponse;
|
||||
} else if (op == UserOperation.AddAdmin) {
|
||||
let data = wsJsonToRes<AddAdminResponse>(msg).data;
|
||||
this.state.siteRes.admins = data.admins;
|
||||
this.setState(this.state);
|
||||
} else if (res.op == UserOperation.Search) {
|
||||
let data = res.data as SearchResponse;
|
||||
} else if (op == UserOperation.Search) {
|
||||
let data = wsJsonToRes<SearchResponse>(msg).data;
|
||||
this.state.crossPosts = data.posts.filter(
|
||||
p => p.id != Number(this.props.match.params.id)
|
||||
p => p.post.id != Number(this.props.match.params.id)
|
||||
);
|
||||
if (this.state.crossPosts.length) {
|
||||
this.state.postRes.post.duplicates = this.state.crossPosts;
|
||||
}
|
||||
this.setState(this.state);
|
||||
} else if (res.op == UserOperation.TransferSite) {
|
||||
let data = res.data as GetSiteResponse;
|
||||
} else if (op == UserOperation.TransferSite) {
|
||||
let data = wsJsonToRes<GetSiteResponse>(msg).data;
|
||||
this.state.siteRes = data;
|
||||
this.setState(this.state);
|
||||
} else if (res.op == UserOperation.TransferCommunity) {
|
||||
let data = res.data as GetCommunityResponse;
|
||||
this.state.postRes.community = data.community;
|
||||
} else if (op == UserOperation.TransferCommunity) {
|
||||
let data = wsJsonToRes<GetCommunityResponse>(msg).data;
|
||||
this.state.postRes.community_view = data.community_view;
|
||||
this.state.postRes.post_view.community = data.community_view.community;
|
||||
this.state.postRes.moderators = data.moderators;
|
||||
this.setState(this.state);
|
||||
} else if (res.op == UserOperation.ListCategories) {
|
||||
let data = res.data as ListCategoriesResponse;
|
||||
} else if (op == UserOperation.ListCategories) {
|
||||
let data = wsJsonToRes<ListCategoriesResponse>(msg).data;
|
||||
this.state.categories = data.categories;
|
||||
this.setState(this.state);
|
||||
}
|
||||
|
|
|
@ -2,15 +2,14 @@ import { Component, linkEvent } from 'inferno';
|
|||
import { Prompt } from 'inferno-router';
|
||||
import { Subscription } from 'rxjs';
|
||||
import {
|
||||
PrivateMessageForm as PrivateMessageFormI,
|
||||
EditPrivateMessageForm,
|
||||
PrivateMessage,
|
||||
CreatePrivateMessage,
|
||||
EditPrivateMessage,
|
||||
PrivateMessageView,
|
||||
PrivateMessageResponse,
|
||||
UserView,
|
||||
UserSafe,
|
||||
UserOperation,
|
||||
WebSocketJsonResponse,
|
||||
} from 'lemmy-js-client';
|
||||
import { WebSocketService } from '../services';
|
||||
import { UserService, WebSocketService } from '../services';
|
||||
import {
|
||||
capitalizeFirstLetter,
|
||||
wsJsonToRes,
|
||||
|
@ -18,6 +17,7 @@ import {
|
|||
setupTippy,
|
||||
wsSubscribe,
|
||||
isBrowser,
|
||||
wsUserOp,
|
||||
} from '../utils';
|
||||
import { UserListing } from './user-listing';
|
||||
import { MarkdownTextArea } from './markdown-textarea';
|
||||
|
@ -25,15 +25,15 @@ import { i18n } from '../i18next';
|
|||
import { T } from 'inferno-i18next';
|
||||
|
||||
interface PrivateMessageFormProps {
|
||||
recipient: UserView;
|
||||
privateMessage?: PrivateMessage; // If a pm is given, that means this is an edit
|
||||
recipient: UserSafe;
|
||||
privateMessage?: PrivateMessageView; // If a pm is given, that means this is an edit
|
||||
onCancel?(): any;
|
||||
onCreate?(message: PrivateMessage): any;
|
||||
onEdit?(message: PrivateMessage): any;
|
||||
onCreate?(message: PrivateMessageView): any;
|
||||
onEdit?(message: PrivateMessageView): any;
|
||||
}
|
||||
|
||||
interface PrivateMessageFormState {
|
||||
privateMessageForm: PrivateMessageFormI;
|
||||
privateMessageForm: CreatePrivateMessage;
|
||||
loading: boolean;
|
||||
previewMode: boolean;
|
||||
showDisclaimer: boolean;
|
||||
|
@ -48,6 +48,7 @@ export class PrivateMessageForm extends Component<
|
|||
privateMessageForm: {
|
||||
content: null,
|
||||
recipient_id: this.props.recipient.id,
|
||||
auth: UserService.Instance.authField(),
|
||||
},
|
||||
loading: false,
|
||||
previewMode: false,
|
||||
|
@ -64,11 +65,9 @@ export class PrivateMessageForm extends Component<
|
|||
this.parseMessage = this.parseMessage.bind(this);
|
||||
this.subscription = wsSubscribe(this.parseMessage);
|
||||
|
||||
// Its an edit
|
||||
if (this.props.privateMessage) {
|
||||
this.state.privateMessageForm = {
|
||||
content: this.props.privateMessage.content,
|
||||
recipient_id: this.props.privateMessage.recipient_id,
|
||||
};
|
||||
this.state.privateMessageForm.content = this.props.privateMessage.private_message.content;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -106,16 +105,7 @@ export class PrivateMessageForm extends Component<
|
|||
</label>
|
||||
|
||||
<div class="col-sm-10 form-control-plaintext">
|
||||
<UserListing
|
||||
user={{
|
||||
name: this.props.recipient.name,
|
||||
preferred_username: this.props.recipient.preferred_username,
|
||||
avatar: this.props.recipient.avatar,
|
||||
id: this.props.recipient.id,
|
||||
local: this.props.recipient.local,
|
||||
actor_id: this.props.recipient.actor_id,
|
||||
}}
|
||||
/>
|
||||
<UserListing user={this.props.recipient} />
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
@ -198,13 +188,14 @@ export class PrivateMessageForm extends Component<
|
|||
handlePrivateMessageSubmit(i: PrivateMessageForm, event: any) {
|
||||
event.preventDefault();
|
||||
if (i.props.privateMessage) {
|
||||
let editForm: EditPrivateMessageForm = {
|
||||
edit_id: i.props.privateMessage.id,
|
||||
let form: EditPrivateMessage = {
|
||||
edit_id: i.props.privateMessage.private_message.id,
|
||||
content: i.state.privateMessageForm.content,
|
||||
auth: UserService.Instance.authField(),
|
||||
};
|
||||
WebSocketService.Instance.editPrivateMessage(editForm);
|
||||
WebSocketService.Instance.client.editPrivateMessage(form);
|
||||
} else {
|
||||
WebSocketService.Instance.createPrivateMessage(
|
||||
WebSocketService.Instance.client.createPrivateMessage(
|
||||
i.state.privateMessageForm
|
||||
);
|
||||
}
|
||||
|
@ -232,25 +223,25 @@ export class PrivateMessageForm extends Component<
|
|||
i.setState(i.state);
|
||||
}
|
||||
|
||||
parseMessage(msg: WebSocketJsonResponse) {
|
||||
let res = wsJsonToRes(msg);
|
||||
parseMessage(msg: any) {
|
||||
let op = wsUserOp(msg);
|
||||
if (msg.error) {
|
||||
toast(i18n.t(msg.error), 'danger');
|
||||
this.state.loading = false;
|
||||
this.setState(this.state);
|
||||
return;
|
||||
} else if (
|
||||
res.op == UserOperation.EditPrivateMessage ||
|
||||
res.op == UserOperation.DeletePrivateMessage ||
|
||||
res.op == UserOperation.MarkPrivateMessageAsRead
|
||||
op == UserOperation.EditPrivateMessage ||
|
||||
op == UserOperation.DeletePrivateMessage ||
|
||||
op == UserOperation.MarkPrivateMessageAsRead
|
||||
) {
|
||||
let data = res.data as PrivateMessageResponse;
|
||||
let data = wsJsonToRes<PrivateMessageResponse>(msg).data;
|
||||
this.state.loading = false;
|
||||
this.props.onEdit(data.message);
|
||||
} else if (res.op == UserOperation.CreatePrivateMessage) {
|
||||
let data = res.data as PrivateMessageResponse;
|
||||
this.props.onEdit(data.private_message_view);
|
||||
} else if (op == UserOperation.CreatePrivateMessage) {
|
||||
let data = wsJsonToRes<PrivateMessageResponse>(msg).data;
|
||||
this.state.loading = false;
|
||||
this.props.onCreate(data.message);
|
||||
this.props.onCreate(data.private_message_view);
|
||||
this.setState(this.state);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import { Component, linkEvent } from 'inferno';
|
||||
import {
|
||||
PrivateMessage as PrivateMessageI,
|
||||
DeletePrivateMessageForm,
|
||||
MarkPrivateMessageAsReadForm,
|
||||
UserView,
|
||||
PrivateMessageView,
|
||||
DeletePrivateMessage,
|
||||
MarkPrivateMessageAsRead,
|
||||
UserSafe,
|
||||
} from 'lemmy-js-client';
|
||||
import { WebSocketService, UserService } from '../services';
|
||||
import { mdToHtml, toast } from '../utils';
|
||||
|
@ -20,7 +20,7 @@ interface PrivateMessageState {
|
|||
}
|
||||
|
||||
interface PrivateMessageProps {
|
||||
privateMessage: PrivateMessageI;
|
||||
private_message_view: PrivateMessageView;
|
||||
}
|
||||
|
||||
export class PrivateMessage extends Component<
|
||||
|
@ -48,41 +48,16 @@ export class PrivateMessage extends Component<
|
|||
get mine(): boolean {
|
||||
return (
|
||||
UserService.Instance.user &&
|
||||
UserService.Instance.user.id == this.props.privateMessage.creator_id
|
||||
UserService.Instance.user.id == this.props.private_message_view.creator.id
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
let message = this.props.privateMessage;
|
||||
let userOther: UserView = this.mine
|
||||
? {
|
||||
name: message.recipient_name,
|
||||
preferred_username: message.recipient_preferred_username,
|
||||
id: message.recipient_id,
|
||||
avatar: message.recipient_avatar,
|
||||
local: message.recipient_local,
|
||||
actor_id: message.recipient_actor_id,
|
||||
published: message.published,
|
||||
number_of_posts: 0,
|
||||
post_score: 0,
|
||||
number_of_comments: 0,
|
||||
comment_score: 0,
|
||||
banned: false,
|
||||
}
|
||||
: {
|
||||
name: message.creator_name,
|
||||
preferred_username: message.creator_preferred_username,
|
||||
id: message.creator_id,
|
||||
avatar: message.creator_avatar,
|
||||
local: message.creator_local,
|
||||
actor_id: message.creator_actor_id,
|
||||
published: message.published,
|
||||
number_of_posts: 0,
|
||||
post_score: 0,
|
||||
number_of_comments: 0,
|
||||
comment_score: 0,
|
||||
banned: false,
|
||||
};
|
||||
let message_view = this.props.private_message_view;
|
||||
// TODO check this again
|
||||
let userOther: UserSafe = this.mine
|
||||
? message_view.recipient
|
||||
: message_view.creator;
|
||||
|
||||
return (
|
||||
<div class="border-top border-light">
|
||||
|
@ -97,7 +72,7 @@ export class PrivateMessage extends Component<
|
|||
</li>
|
||||
<li className="list-inline-item">
|
||||
<span>
|
||||
<MomentTime data={message} />
|
||||
<MomentTime data={message_view.private_message} />
|
||||
</span>
|
||||
</li>
|
||||
<li className="list-inline-item">
|
||||
|
@ -120,7 +95,7 @@ export class PrivateMessage extends Component<
|
|||
{this.state.showEdit && (
|
||||
<PrivateMessageForm
|
||||
recipient={userOther}
|
||||
privateMessage={message}
|
||||
privateMessage={message_view}
|
||||
onEdit={this.handlePrivateMessageEdit}
|
||||
onCreate={this.handlePrivateMessageCreate}
|
||||
onCancel={this.handleReplyCancel}
|
||||
|
@ -144,14 +119,14 @@ export class PrivateMessage extends Component<
|
|||
class="btn btn-link btn-animate text-muted"
|
||||
onClick={linkEvent(this, this.handleMarkRead)}
|
||||
data-tippy-content={
|
||||
message.read
|
||||
message_view.private_message.read
|
||||
? i18n.t('mark_as_unread')
|
||||
: i18n.t('mark_as_read')
|
||||
}
|
||||
>
|
||||
<svg
|
||||
class={`icon icon-inline ${
|
||||
message.read && 'text-success'
|
||||
message_view.private_message.read && 'text-success'
|
||||
}`}
|
||||
>
|
||||
<use xlinkHref="#icon-check"></use>
|
||||
|
@ -189,14 +164,15 @@ export class PrivateMessage extends Component<
|
|||
class="btn btn-link btn-animate text-muted"
|
||||
onClick={linkEvent(this, this.handleDeleteClick)}
|
||||
data-tippy-content={
|
||||
!message.deleted
|
||||
!message_view.private_message.deleted
|
||||
? i18n.t('delete')
|
||||
: i18n.t('restore')
|
||||
}
|
||||
>
|
||||
<svg
|
||||
class={`icon icon-inline ${
|
||||
message.deleted && 'text-danger'
|
||||
message_view.private_message.deleted &&
|
||||
'text-danger'
|
||||
}`}
|
||||
>
|
||||
<use xlinkHref="#icon-trash"></use>
|
||||
|
@ -237,7 +213,7 @@ export class PrivateMessage extends Component<
|
|||
}
|
||||
|
||||
get messageUnlessRemoved(): string {
|
||||
let message = this.props.privateMessage;
|
||||
let message = this.props.private_message_view.private_message;
|
||||
return message.deleted ? `*${i18n.t('deleted')}*` : message.content;
|
||||
}
|
||||
|
||||
|
@ -252,11 +228,12 @@ export class PrivateMessage extends Component<
|
|||
}
|
||||
|
||||
handleDeleteClick(i: PrivateMessage) {
|
||||
let form: DeletePrivateMessageForm = {
|
||||
edit_id: i.props.privateMessage.id,
|
||||
deleted: !i.props.privateMessage.deleted,
|
||||
let form: DeletePrivateMessage = {
|
||||
edit_id: i.props.private_message_view.private_message.id,
|
||||
deleted: !i.props.private_message_view.private_message.deleted,
|
||||
auth: UserService.Instance.authField(),
|
||||
};
|
||||
WebSocketService.Instance.deletePrivateMessage(form);
|
||||
WebSocketService.Instance.client.deletePrivateMessage(form);
|
||||
}
|
||||
|
||||
handleReplyCancel() {
|
||||
|
@ -266,11 +243,12 @@ export class PrivateMessage extends Component<
|
|||
}
|
||||
|
||||
handleMarkRead(i: PrivateMessage) {
|
||||
let form: MarkPrivateMessageAsReadForm = {
|
||||
edit_id: i.props.privateMessage.id,
|
||||
read: !i.props.privateMessage.read,
|
||||
let form: MarkPrivateMessageAsRead = {
|
||||
edit_id: i.props.private_message_view.private_message.id,
|
||||
read: !i.props.private_message_view.private_message.read,
|
||||
auth: UserService.Instance.authField(),
|
||||
};
|
||||
WebSocketService.Instance.markPrivateMessageAsRead(form);
|
||||
WebSocketService.Instance.client.markPrivateMessageAsRead(form);
|
||||
}
|
||||
|
||||
handleMessageCollapse(i: PrivateMessage) {
|
||||
|
@ -288,10 +266,10 @@ export class PrivateMessage extends Component<
|
|||
this.setState(this.state);
|
||||
}
|
||||
|
||||
handlePrivateMessageCreate(message: PrivateMessageI) {
|
||||
handlePrivateMessageCreate(message: PrivateMessageView) {
|
||||
if (
|
||||
UserService.Instance.user &&
|
||||
message.creator_id == UserService.Instance.user.id
|
||||
message.creator.id == UserService.Instance.user.id
|
||||
) {
|
||||
this.state.showReply = false;
|
||||
this.setState(this.state);
|
||||
|
|
|
@ -2,20 +2,19 @@ import { Component, linkEvent } from 'inferno';
|
|||
import { Subscription } from 'rxjs';
|
||||
import {
|
||||
UserOperation,
|
||||
Post,
|
||||
Comment,
|
||||
Community,
|
||||
UserView,
|
||||
PostView,
|
||||
CommentView,
|
||||
CommunityView,
|
||||
UserViewSafe,
|
||||
SortType,
|
||||
SearchForm,
|
||||
Search as SearchForm,
|
||||
SearchResponse,
|
||||
SearchType,
|
||||
PostResponse,
|
||||
CommentResponse,
|
||||
WebSocketJsonResponse,
|
||||
Site,
|
||||
} from 'lemmy-js-client';
|
||||
import { WebSocketService } from '../services';
|
||||
import { UserService, WebSocketService } from '../services';
|
||||
import {
|
||||
wsJsonToRes,
|
||||
fetchLimit,
|
||||
|
@ -27,7 +26,7 @@ import {
|
|||
commentsToFlatNodes,
|
||||
setIsoData,
|
||||
wsSubscribe,
|
||||
setAuth,
|
||||
wsUserOp,
|
||||
} from '../utils';
|
||||
import { PostListing } from './post-listing';
|
||||
import { HtmlTags } from './html-tags';
|
||||
|
@ -80,7 +79,7 @@ export class Search extends Component<any, SearchState> {
|
|||
users: [],
|
||||
},
|
||||
loading: false,
|
||||
site: this.isoData.site.site,
|
||||
site: this.isoData.site_res.site_view.site,
|
||||
};
|
||||
|
||||
static getSearchQueryFromProps(q: string): string {
|
||||
|
@ -142,8 +141,8 @@ export class Search extends Component<any, SearchState> {
|
|||
sort: this.getSortTypeFromProps(pathSplit[7]),
|
||||
page: this.getPageFromProps(pathSplit[9]),
|
||||
limit: fetchLimit,
|
||||
auth: req.auth,
|
||||
};
|
||||
setAuth(form, req.auth);
|
||||
|
||||
if (form.q != '') {
|
||||
promises.push(req.client.search(form));
|
||||
|
@ -252,19 +251,24 @@ export class Search extends Component<any, SearchState> {
|
|||
all() {
|
||||
let combined: {
|
||||
type_: string;
|
||||
data: Comment | Post | Community | UserView;
|
||||
data: CommentView | PostView | CommunityView | UserViewSafe;
|
||||
published: string;
|
||||
}[] = [];
|
||||
let comments = this.state.searchResponse.comments.map(e => {
|
||||
return { type_: 'comments', data: e };
|
||||
return { type_: 'comments', data: e, published: e.comment.published };
|
||||
});
|
||||
let posts = this.state.searchResponse.posts.map(e => {
|
||||
return { type_: 'posts', data: e };
|
||||
return { type_: 'posts', data: e, published: e.post.published };
|
||||
});
|
||||
let communities = this.state.searchResponse.communities.map(e => {
|
||||
return { type_: 'communities', data: e };
|
||||
return {
|
||||
type_: 'communities',
|
||||
data: e,
|
||||
published: e.community.published,
|
||||
};
|
||||
});
|
||||
let users = this.state.searchResponse.users.map(e => {
|
||||
return { type_: 'users', data: e };
|
||||
return { type_: 'users', data: e, published: e.user.published };
|
||||
});
|
||||
|
||||
combined.push(...comments);
|
||||
|
@ -274,16 +278,16 @@ export class Search extends Component<any, SearchState> {
|
|||
|
||||
// Sort it
|
||||
if (this.state.sort == SortType.New) {
|
||||
combined.sort((a, b) => b.data.published.localeCompare(a.data.published));
|
||||
combined.sort((a, b) => b.published.localeCompare(a.published));
|
||||
} else {
|
||||
combined.sort(
|
||||
(a, b) =>
|
||||
((b.data as Comment | Post).score |
|
||||
(b.data as Community).number_of_subscribers |
|
||||
(b.data as UserView).comment_score) -
|
||||
((a.data as Comment | Post).score |
|
||||
(a.data as Community).number_of_subscribers |
|
||||
(a.data as UserView).comment_score)
|
||||
((b.data as CommentView | PostView).counts.score |
|
||||
(b.data as CommunityView).counts.subscribers |
|
||||
(b.data as UserViewSafe).counts.comment_score) -
|
||||
((a.data as CommentView | PostView).counts.score |
|
||||
(a.data as CommunityView).counts.subscribers |
|
||||
(a.data as UserViewSafe).counts.comment_score)
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -294,8 +298,8 @@ export class Search extends Component<any, SearchState> {
|
|||
<div class="col-12">
|
||||
{i.type_ == 'posts' && (
|
||||
<PostListing
|
||||
key={(i.data as Post).id}
|
||||
post={i.data as Post}
|
||||
key={(i.data as PostView).post.id}
|
||||
post_view={i.data as PostView}
|
||||
showCommunity
|
||||
enableDownvotes={this.state.site.enable_downvotes}
|
||||
enableNsfw={this.state.site.enable_nsfw}
|
||||
|
@ -303,18 +307,18 @@ export class Search extends Component<any, SearchState> {
|
|||
)}
|
||||
{i.type_ == 'comments' && (
|
||||
<CommentNodes
|
||||
key={(i.data as Comment).id}
|
||||
nodes={[{ comment: i.data as Comment }]}
|
||||
key={(i.data as CommentView).comment.id}
|
||||
nodes={[{ comment_view: i.data as CommentView }]}
|
||||
locked
|
||||
noIndent
|
||||
enableDownvotes={this.state.site.enable_downvotes}
|
||||
/>
|
||||
)}
|
||||
{i.type_ == 'communities' && (
|
||||
<div>{this.communityListing(i.data as Community)}</div>
|
||||
<div>{this.communityListing(i.data as CommunityView)}</div>
|
||||
)}
|
||||
{i.type_ == 'users' && (
|
||||
<div>{this.userListing(i.data as UserView)}</div>
|
||||
<div>{this.userListing(i.data as UserViewSafe)}</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -341,7 +345,7 @@ export class Search extends Component<any, SearchState> {
|
|||
<div class="row">
|
||||
<div class="col-12">
|
||||
<PostListing
|
||||
post={post}
|
||||
post_view={post}
|
||||
showCommunity
|
||||
enableDownvotes={this.state.site.enable_downvotes}
|
||||
enableNsfw={this.state.site.enable_nsfw}
|
||||
|
@ -365,28 +369,28 @@ export class Search extends Component<any, SearchState> {
|
|||
);
|
||||
}
|
||||
|
||||
communityListing(community: Community) {
|
||||
communityListing(community_view: CommunityView) {
|
||||
return (
|
||||
<>
|
||||
<span>
|
||||
<CommunityLink community={community} />
|
||||
<CommunityLink community={community_view.community} />
|
||||
</span>
|
||||
<span>{` - ${community.title} -
|
||||
<span>{` - ${community_view.community.title} -
|
||||
${i18n.t('number_of_subscribers', {
|
||||
count: community.number_of_subscribers,
|
||||
count: community_view.counts.subscribers,
|
||||
})}
|
||||
`}</span>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
userListing(user: UserView) {
|
||||
userListing(user_view: UserViewSafe) {
|
||||
return [
|
||||
<span>
|
||||
<UserListing user={user} showApubName />
|
||||
<UserListing user={user_view.user} showApubName />
|
||||
</span>,
|
||||
<span>{` - ${i18n.t('number_of_comments', {
|
||||
count: user.number_of_comments,
|
||||
count: user_view.counts.comment_count,
|
||||
})}`}</span>,
|
||||
];
|
||||
}
|
||||
|
@ -452,10 +456,11 @@ export class Search extends Component<any, SearchState> {
|
|||
sort: this.state.sort,
|
||||
page: this.state.page,
|
||||
limit: fetchLimit,
|
||||
auth: UserService.Instance.authField(false),
|
||||
};
|
||||
|
||||
if (this.state.q != '') {
|
||||
WebSocketService.Instance.search(form);
|
||||
WebSocketService.Instance.client.search(form);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -495,25 +500,28 @@ export class Search extends Component<any, SearchState> {
|
|||
);
|
||||
}
|
||||
|
||||
parseMessage(msg: WebSocketJsonResponse) {
|
||||
parseMessage(msg: any) {
|
||||
console.log(msg);
|
||||
let res = wsJsonToRes(msg);
|
||||
let op = wsUserOp(msg);
|
||||
if (msg.error) {
|
||||
toast(i18n.t(msg.error), 'danger');
|
||||
return;
|
||||
} else if (res.op == UserOperation.Search) {
|
||||
let data = res.data as SearchResponse;
|
||||
} else if (op == UserOperation.Search) {
|
||||
let data = wsJsonToRes<SearchResponse>(msg).data;
|
||||
this.state.searchResponse = data;
|
||||
this.state.loading = false;
|
||||
window.scrollTo(0, 0);
|
||||
this.setState(this.state);
|
||||
} else if (res.op == UserOperation.CreateCommentLike) {
|
||||
let data = res.data as CommentResponse;
|
||||
createCommentLikeRes(data, this.state.searchResponse.comments);
|
||||
} else if (op == UserOperation.CreateCommentLike) {
|
||||
let data = wsJsonToRes<CommentResponse>(msg).data;
|
||||
createCommentLikeRes(
|
||||
data.comment_view,
|
||||
this.state.searchResponse.comments
|
||||
);
|
||||
this.setState(this.state);
|
||||
} else if (res.op == UserOperation.CreatePostLike) {
|
||||
let data = res.data as PostResponse;
|
||||
createPostLikeFindRes(data, this.state.searchResponse.posts);
|
||||
} else if (op == UserOperation.CreatePostLike) {
|
||||
let data = wsJsonToRes<PostResponse>(msg).data;
|
||||
createPostLikeFindRes(data.post_view, this.state.searchResponse.posts);
|
||||
this.setState(this.state);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,19 +2,14 @@ import { Component, linkEvent } from 'inferno';
|
|||
import { Helmet } from 'inferno-helmet';
|
||||
import { Subscription } from 'rxjs';
|
||||
import { retryWhen, delay, take } from 'rxjs/operators';
|
||||
import {
|
||||
RegisterForm,
|
||||
LoginResponse,
|
||||
UserOperation,
|
||||
WebSocketJsonResponse,
|
||||
} from 'lemmy-js-client';
|
||||
import { Register, LoginResponse, UserOperation } from 'lemmy-js-client';
|
||||
import { WebSocketService, UserService } from '../services';
|
||||
import { wsJsonToRes, toast } from '../utils';
|
||||
import { wsUserOp, wsJsonToRes, toast } from '../utils';
|
||||
import { SiteForm } from './site-form';
|
||||
import { i18n } from '../i18next';
|
||||
|
||||
interface State {
|
||||
userForm: RegisterForm;
|
||||
userForm: Register;
|
||||
doneRegisteringUser: boolean;
|
||||
userLoading: boolean;
|
||||
}
|
||||
|
@ -168,7 +163,7 @@ export class Setup extends Component<any, State> {
|
|||
i.state.userLoading = true;
|
||||
i.setState(i.state);
|
||||
event.preventDefault();
|
||||
WebSocketService.Instance.register(i.state.userForm);
|
||||
WebSocketService.Instance.client.register(i.state.userForm);
|
||||
}
|
||||
|
||||
handleRegisterUsernameChange(i: Setup, event: any) {
|
||||
|
@ -191,20 +186,20 @@ export class Setup extends Component<any, State> {
|
|||
i.setState(i.state);
|
||||
}
|
||||
|
||||
parseMessage(msg: WebSocketJsonResponse) {
|
||||
let res = wsJsonToRes(msg);
|
||||
parseMessage(msg: any) {
|
||||
let op = wsUserOp(msg);
|
||||
if (msg.error) {
|
||||
toast(i18n.t(msg.error), 'danger');
|
||||
this.state.userLoading = false;
|
||||
this.setState(this.state);
|
||||
return;
|
||||
} else if (res.op == UserOperation.Register) {
|
||||
let data = res.data as LoginResponse;
|
||||
} else if (op == UserOperation.Register) {
|
||||
let data = wsJsonToRes<LoginResponse>(msg).data;
|
||||
this.state.userLoading = false;
|
||||
this.state.doneRegisteringUser = true;
|
||||
UserService.Instance.login(data);
|
||||
this.setState(this.state);
|
||||
} else if (res.op == UserOperation.CreateSite) {
|
||||
} else if (op == UserOperation.CreateSite) {
|
||||
window.location.href = '/';
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
import { Component, linkEvent } from 'inferno';
|
||||
import { Link } from 'inferno-router';
|
||||
import {
|
||||
Community,
|
||||
CommunityUser,
|
||||
FollowCommunityForm,
|
||||
DeleteCommunityForm,
|
||||
RemoveCommunityForm,
|
||||
UserView,
|
||||
AddModToCommunityForm,
|
||||
CommunityView,
|
||||
CommunityModeratorView,
|
||||
FollowCommunity,
|
||||
DeleteCommunity,
|
||||
RemoveCommunity,
|
||||
UserViewSafe,
|
||||
AddModToCommunity,
|
||||
Category,
|
||||
} from 'lemmy-js-client';
|
||||
import { WebSocketService, UserService } from '../services';
|
||||
|
@ -19,10 +19,10 @@ import { BannerIconHeader } from './banner-icon-header';
|
|||
import { i18n } from '../i18next';
|
||||
|
||||
interface SidebarProps {
|
||||
community: Community;
|
||||
community_view: CommunityView;
|
||||
categories: Category[];
|
||||
moderators: CommunityUser[];
|
||||
admins: UserView[];
|
||||
moderators: CommunityModeratorView[];
|
||||
admins: UserViewSafe[];
|
||||
online: number;
|
||||
enableNsfw: boolean;
|
||||
showIcon?: boolean;
|
||||
|
@ -60,7 +60,7 @@ export class Sidebar extends Component<SidebarProps, SidebarState> {
|
|||
) : (
|
||||
<CommunityForm
|
||||
categories={this.props.categories}
|
||||
community={this.props.community}
|
||||
community_view={this.props.community_view}
|
||||
onEdit={this.handleEditCommunity}
|
||||
onCancel={this.handleEditCancel}
|
||||
enableNsfw={this.props.enableNsfw}
|
||||
|
@ -93,7 +93,8 @@ export class Sidebar extends Component<SidebarProps, SidebarState> {
|
|||
}
|
||||
|
||||
communityTitle() {
|
||||
let community = this.props.community;
|
||||
let community = this.props.community_view.community;
|
||||
let subscribed = this.props.community_view.subscribed;
|
||||
return (
|
||||
<div>
|
||||
<h5 className="mb-0">
|
||||
|
@ -101,7 +102,7 @@ export class Sidebar extends Component<SidebarProps, SidebarState> {
|
|||
<BannerIconHeader icon={community.icon} banner={community.banner} />
|
||||
)}
|
||||
<span class="mr-2">{community.title}</span>
|
||||
{community.subscribed && (
|
||||
{subscribed && (
|
||||
<a
|
||||
class="btn btn-secondary btn-sm mr-2"
|
||||
href="#"
|
||||
|
@ -141,7 +142,7 @@ export class Sidebar extends Component<SidebarProps, SidebarState> {
|
|||
}
|
||||
|
||||
badges() {
|
||||
let community = this.props.community;
|
||||
let community_view = this.props.community_view;
|
||||
return (
|
||||
<ul class="my-1 list-inline">
|
||||
<li className="list-inline-item badge badge-secondary">
|
||||
|
@ -149,28 +150,28 @@ export class Sidebar extends Component<SidebarProps, SidebarState> {
|
|||
</li>
|
||||
<li className="list-inline-item badge badge-secondary">
|
||||
{i18n.t('number_of_subscribers', {
|
||||
count: community.number_of_subscribers,
|
||||
count: community_view.counts.subscribers,
|
||||
})}
|
||||
</li>
|
||||
<li className="list-inline-item badge badge-secondary">
|
||||
{i18n.t('number_of_posts', {
|
||||
count: community.number_of_posts,
|
||||
count: community_view.counts.posts,
|
||||
})}
|
||||
</li>
|
||||
<li className="list-inline-item badge badge-secondary">
|
||||
{i18n.t('number_of_comments', {
|
||||
count: community.number_of_comments,
|
||||
count: community_view.counts.comments,
|
||||
})}
|
||||
</li>
|
||||
<li className="list-inline-item">
|
||||
<Link className="badge badge-secondary" to="/communities">
|
||||
{community.category_name}
|
||||
{community_view.category.name}
|
||||
</Link>
|
||||
</li>
|
||||
<li className="list-inline-item">
|
||||
<Link
|
||||
className="badge badge-secondary"
|
||||
to={`/modlog/community/${this.props.community.id}`}
|
||||
to={`/modlog/community/${this.props.community_view.community.id}`}
|
||||
>
|
||||
{i18n.t('modlog')}
|
||||
</Link>
|
||||
|
@ -185,16 +186,7 @@ export class Sidebar extends Component<SidebarProps, SidebarState> {
|
|||
<li class="list-inline-item">{i18n.t('mods')}: </li>
|
||||
{this.props.moderators.map(mod => (
|
||||
<li class="list-inline-item">
|
||||
<UserListing
|
||||
user={{
|
||||
name: mod.user_name,
|
||||
preferred_username: mod.user_preferred_username,
|
||||
avatar: mod.avatar,
|
||||
id: mod.user_id,
|
||||
local: mod.user_local,
|
||||
actor_id: mod.user_actor_id,
|
||||
}}
|
||||
/>
|
||||
<UserListing user={mod.moderator} />
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
|
@ -202,14 +194,16 @@ export class Sidebar extends Component<SidebarProps, SidebarState> {
|
|||
}
|
||||
|
||||
createPost() {
|
||||
let community = this.props.community;
|
||||
let community_view = this.props.community_view;
|
||||
return (
|
||||
community.subscribed && (
|
||||
community_view.subscribed && (
|
||||
<Link
|
||||
className={`btn btn-secondary btn-block mb-2 ${
|
||||
community.deleted || community.removed ? 'no-click' : ''
|
||||
community_view.community.deleted || community_view.community.removed
|
||||
? 'no-click'
|
||||
: ''
|
||||
}`}
|
||||
to={`/create_post?community_id=${community.id}`}
|
||||
to={`/create_post?community_id=${community_view.community.id}`}
|
||||
>
|
||||
{i18n.t('create_a_post')}
|
||||
</Link>
|
||||
|
@ -218,14 +212,17 @@ export class Sidebar extends Component<SidebarProps, SidebarState> {
|
|||
}
|
||||
|
||||
subscribe() {
|
||||
let community = this.props.community;
|
||||
let community_view = this.props.community_view;
|
||||
return (
|
||||
<div class="mb-2">
|
||||
{!community.subscribed && (
|
||||
{!community_view.subscribed && (
|
||||
<a
|
||||
class="btn btn-secondary btn-block"
|
||||
href="#"
|
||||
onClick={linkEvent(community.id, this.handleSubscribe)}
|
||||
onClick={linkEvent(
|
||||
community_view.community.id,
|
||||
this.handleSubscribe
|
||||
)}
|
||||
>
|
||||
{i18n.t('subscribe')}
|
||||
</a>
|
||||
|
@ -235,19 +232,19 @@ export class Sidebar extends Component<SidebarProps, SidebarState> {
|
|||
}
|
||||
|
||||
description() {
|
||||
let community = this.props.community;
|
||||
let description = this.props.community_view.community.description;
|
||||
return (
|
||||
community.description && (
|
||||
description && (
|
||||
<div
|
||||
className="md-div"
|
||||
dangerouslySetInnerHTML={mdToHtml(community.description)}
|
||||
dangerouslySetInnerHTML={mdToHtml(description)}
|
||||
/>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
adminButtons() {
|
||||
let community = this.props.community;
|
||||
let community_view = this.props.community_view;
|
||||
return (
|
||||
<>
|
||||
<ul class="list-inline mb-1 text-muted font-weight-bold">
|
||||
|
@ -309,12 +306,14 @@ export class Sidebar extends Component<SidebarProps, SidebarState> {
|
|||
class="pointer"
|
||||
onClick={linkEvent(this, this.handleDeleteClick)}
|
||||
data-tippy-content={
|
||||
!community.deleted ? i18n.t('delete') : i18n.t('restore')
|
||||
!community_view.community.deleted
|
||||
? i18n.t('delete')
|
||||
: i18n.t('restore')
|
||||
}
|
||||
>
|
||||
<svg
|
||||
class={`icon icon-inline ${
|
||||
community.deleted && 'text-danger'
|
||||
community_view.community.deleted && 'text-danger'
|
||||
}`}
|
||||
>
|
||||
<use xlinkHref="#icon-trash"></use>
|
||||
|
@ -326,7 +325,7 @@ export class Sidebar extends Component<SidebarProps, SidebarState> {
|
|||
)}
|
||||
{this.canAdmin && (
|
||||
<li className="list-inline-item">
|
||||
{!this.props.community.removed ? (
|
||||
{!this.props.community_view.community.removed ? (
|
||||
<span
|
||||
class="pointer"
|
||||
onClick={linkEvent(this, this.handleModRemoveShow)}
|
||||
|
@ -392,11 +391,12 @@ export class Sidebar extends Component<SidebarProps, SidebarState> {
|
|||
|
||||
handleDeleteClick(i: Sidebar, event: any) {
|
||||
event.preventDefault();
|
||||
let deleteForm: DeleteCommunityForm = {
|
||||
edit_id: i.props.community.id,
|
||||
deleted: !i.props.community.deleted,
|
||||
let deleteForm: DeleteCommunity = {
|
||||
edit_id: i.props.community_view.community.id,
|
||||
deleted: !i.props.community_view.community.deleted,
|
||||
auth: UserService.Instance.authField(),
|
||||
};
|
||||
WebSocketService.Instance.deleteCommunity(deleteForm);
|
||||
WebSocketService.Instance.client.deleteCommunity(deleteForm);
|
||||
}
|
||||
|
||||
handleShowConfirmLeaveModTeamClick(i: Sidebar) {
|
||||
|
@ -405,12 +405,13 @@ export class Sidebar extends Component<SidebarProps, SidebarState> {
|
|||
}
|
||||
|
||||
handleLeaveModTeamClick(i: Sidebar) {
|
||||
let form: AddModToCommunityForm = {
|
||||
let form: AddModToCommunity = {
|
||||
user_id: UserService.Instance.user.id,
|
||||
community_id: i.props.community.id,
|
||||
community_id: i.props.community_view.community.id,
|
||||
added: false,
|
||||
auth: UserService.Instance.authField(),
|
||||
};
|
||||
WebSocketService.Instance.addModToCommunity(form);
|
||||
WebSocketService.Instance.client.addModToCommunity(form);
|
||||
i.state.showConfirmLeaveModTeam = false;
|
||||
i.setState(i.state);
|
||||
}
|
||||
|
@ -422,31 +423,33 @@ export class Sidebar extends Component<SidebarProps, SidebarState> {
|
|||
|
||||
handleUnsubscribe(communityId: number, event: any) {
|
||||
event.preventDefault();
|
||||
let form: FollowCommunityForm = {
|
||||
let form: FollowCommunity = {
|
||||
community_id: communityId,
|
||||
follow: false,
|
||||
auth: UserService.Instance.authField(),
|
||||
};
|
||||
WebSocketService.Instance.followCommunity(form);
|
||||
WebSocketService.Instance.client.followCommunity(form);
|
||||
}
|
||||
|
||||
handleSubscribe(communityId: number, event: any) {
|
||||
event.preventDefault();
|
||||
let form: FollowCommunityForm = {
|
||||
let form: FollowCommunity = {
|
||||
community_id: communityId,
|
||||
follow: true,
|
||||
auth: UserService.Instance.authField(),
|
||||
};
|
||||
WebSocketService.Instance.followCommunity(form);
|
||||
WebSocketService.Instance.client.followCommunity(form);
|
||||
}
|
||||
|
||||
private get amCreator(): boolean {
|
||||
return this.props.community.creator_id == UserService.Instance.user.id;
|
||||
return this.props.community_view.creator.id == UserService.Instance.user.id;
|
||||
}
|
||||
|
||||
get canMod(): boolean {
|
||||
return (
|
||||
UserService.Instance.user &&
|
||||
this.props.moderators
|
||||
.map(m => m.user_id)
|
||||
.map(m => m.moderator.id)
|
||||
.includes(UserService.Instance.user.id)
|
||||
);
|
||||
}
|
||||
|
@ -454,7 +457,9 @@ export class Sidebar extends Component<SidebarProps, SidebarState> {
|
|||
get canAdmin(): boolean {
|
||||
return (
|
||||
UserService.Instance.user &&
|
||||
this.props.admins.map(a => a.id).includes(UserService.Instance.user.id)
|
||||
this.props.admins
|
||||
.map(a => a.user.id)
|
||||
.includes(UserService.Instance.user.id)
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -476,13 +481,14 @@ export class Sidebar extends Component<SidebarProps, SidebarState> {
|
|||
|
||||
handleModRemoveSubmit(i: Sidebar, event: any) {
|
||||
event.preventDefault();
|
||||
let removeForm: RemoveCommunityForm = {
|
||||
edit_id: i.props.community.id,
|
||||
removed: !i.props.community.removed,
|
||||
let removeForm: RemoveCommunity = {
|
||||
edit_id: i.props.community_view.community.id,
|
||||
removed: !i.props.community_view.community.removed,
|
||||
reason: i.state.removeReason,
|
||||
expires: getUnixTime(i.state.removeExpires),
|
||||
auth: UserService.Instance.authField(),
|
||||
};
|
||||
WebSocketService.Instance.removeCommunity(removeForm);
|
||||
WebSocketService.Instance.client.removeCommunity(removeForm);
|
||||
|
||||
i.state.showRemoveDialog = false;
|
||||
i.setState(i.state);
|
||||
|
|
|
@ -2,8 +2,8 @@ import { Component, linkEvent } from 'inferno';
|
|||
import { Prompt } from 'inferno-router';
|
||||
import { MarkdownTextArea } from './markdown-textarea';
|
||||
import { ImageUploadForm } from './image-upload-form';
|
||||
import { Site, SiteForm as SiteFormI } from 'lemmy-js-client';
|
||||
import { WebSocketService } from '../services';
|
||||
import { Site, EditSite } from 'lemmy-js-client';
|
||||
import { UserService, WebSocketService } from '../services';
|
||||
import { capitalizeFirstLetter, randomStr } from '../utils';
|
||||
import { i18n } from '../i18next';
|
||||
|
||||
|
@ -13,7 +13,7 @@ interface SiteFormProps {
|
|||
}
|
||||
|
||||
interface SiteFormState {
|
||||
siteForm: SiteFormI;
|
||||
siteForm: EditSite;
|
||||
loading: boolean;
|
||||
}
|
||||
|
||||
|
@ -27,6 +27,7 @@ export class SiteForm extends Component<SiteFormProps, SiteFormState> {
|
|||
name: null,
|
||||
icon: null,
|
||||
banner: null,
|
||||
auth: UserService.Instance.authField(),
|
||||
},
|
||||
loading: false,
|
||||
};
|
||||
|
@ -54,6 +55,7 @@ export class SiteForm extends Component<SiteFormProps, SiteFormState> {
|
|||
enable_nsfw: this.props.site.enable_nsfw,
|
||||
icon: this.props.site.icon,
|
||||
banner: this.props.site.banner,
|
||||
auth: UserService.Instance.authField(),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -242,9 +244,9 @@ export class SiteForm extends Component<SiteFormProps, SiteFormState> {
|
|||
event.preventDefault();
|
||||
i.state.loading = true;
|
||||
if (i.props.site) {
|
||||
WebSocketService.Instance.editSite(i.state.siteForm);
|
||||
WebSocketService.Instance.client.editSite(i.state.siteForm);
|
||||
} else {
|
||||
WebSocketService.Instance.createSite(i.state.siteForm);
|
||||
WebSocketService.Instance.client.createSite(i.state.siteForm);
|
||||
}
|
||||
i.setState(i.state);
|
||||
}
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import { User } from 'lemmy-js-client';
|
||||
import { User_ } from 'lemmy-js-client';
|
||||
import { Helmet } from 'inferno-helmet';
|
||||
import { Component } from 'inferno';
|
||||
|
||||
interface Props {
|
||||
user: User | undefined;
|
||||
user: User_ | undefined;
|
||||
}
|
||||
|
||||
export class Theme extends Component<Props> {
|
||||
|
|
|
@ -1,13 +1,20 @@
|
|||
import { Component, linkEvent } from 'inferno';
|
||||
import { i18n } from '../i18next';
|
||||
import { Post, Comment, SortType, UserDetailsResponse } from 'lemmy-js-client';
|
||||
import {
|
||||
PostView,
|
||||
CommentView,
|
||||
SortType,
|
||||
GetUserDetailsResponse,
|
||||
UserViewSafe,
|
||||
} from 'lemmy-js-client';
|
||||
import { UserDetailsView } from '../interfaces';
|
||||
import { commentsToFlatNodes, setupTippy } from '../utils';
|
||||
import { PostListing } from './post-listing';
|
||||
import { CommentNodes } from './comment-nodes';
|
||||
|
||||
interface UserDetailsProps {
|
||||
userRes: UserDetailsResponse;
|
||||
userRes: GetUserDetailsResponse;
|
||||
admins: UserViewSafe[];
|
||||
page: number;
|
||||
limit: number;
|
||||
sort: SortType;
|
||||
|
@ -19,6 +26,18 @@ interface UserDetailsProps {
|
|||
|
||||
interface UserDetailsState {}
|
||||
|
||||
enum ItemEnum {
|
||||
Comment,
|
||||
Post,
|
||||
}
|
||||
type ItemType = {
|
||||
id: number;
|
||||
type_: ItemEnum;
|
||||
view: CommentView | PostView;
|
||||
published: string;
|
||||
score: number;
|
||||
};
|
||||
|
||||
export class UserDetails extends Component<UserDetailsProps, UserDetailsState> {
|
||||
constructor(props: any, context: any) {
|
||||
super(props, context);
|
||||
|
@ -60,56 +79,68 @@ export class UserDetails extends Component<UserDetailsProps, UserDetailsState> {
|
|||
}
|
||||
}
|
||||
|
||||
overview() {
|
||||
const comments = this.props.userRes.comments.map((c: Comment) => {
|
||||
return { type: 'comments', data: c };
|
||||
});
|
||||
const posts = this.props.userRes.posts.map((p: Post) => {
|
||||
return { type: 'posts', data: p };
|
||||
});
|
||||
renderItemType(i: ItemType) {
|
||||
switch (i.type_) {
|
||||
case ItemEnum.Comment:
|
||||
let c = i.view as CommentView;
|
||||
return (
|
||||
<CommentNodes
|
||||
key={i.id}
|
||||
nodes={[{ comment_view: c }]}
|
||||
admins={this.props.admins}
|
||||
noBorder
|
||||
noIndent
|
||||
showCommunity
|
||||
showContext
|
||||
enableDownvotes={this.props.enableDownvotes}
|
||||
/>
|
||||
);
|
||||
case ItemEnum.Post:
|
||||
let p = i.view as PostView;
|
||||
return (
|
||||
<PostListing
|
||||
key={i.id}
|
||||
post_view={p}
|
||||
admins={this.props.admins}
|
||||
showCommunity
|
||||
enableDownvotes={this.props.enableDownvotes}
|
||||
enableNsfw={this.props.enableNsfw}
|
||||
/>
|
||||
);
|
||||
default:
|
||||
return <div />;
|
||||
}
|
||||
}
|
||||
|
||||
const combined: { type: string; data: Comment | Post }[] = [
|
||||
...comments,
|
||||
...posts,
|
||||
];
|
||||
overview() {
|
||||
let id = 0;
|
||||
let comments: ItemType[] = this.props.userRes.comments.map(r => ({
|
||||
id: id++,
|
||||
type_: ItemEnum.Comment,
|
||||
view: r,
|
||||
published: r.comment.published,
|
||||
score: r.counts.score,
|
||||
}));
|
||||
let posts: ItemType[] = this.props.userRes.posts.map(r => ({
|
||||
id: id++,
|
||||
type_: ItemEnum.Comment,
|
||||
view: r,
|
||||
published: r.post.published,
|
||||
score: r.counts.score,
|
||||
}));
|
||||
|
||||
let combined = [...comments, ...posts];
|
||||
|
||||
// Sort it
|
||||
if (this.props.sort === SortType.New) {
|
||||
combined.sort((a, b) => b.data.published.localeCompare(a.data.published));
|
||||
combined.sort((a, b) => b.published.localeCompare(a.published));
|
||||
} else {
|
||||
combined.sort((a, b) => b.data.score - a.data.score);
|
||||
combined.sort((a, b) => b.score - a.score);
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
{combined.map(i => (
|
||||
<>
|
||||
<div>
|
||||
{i.type === 'posts' ? (
|
||||
<PostListing
|
||||
key={(i.data as Post).id}
|
||||
post={i.data as Post}
|
||||
admins={this.props.userRes.admins}
|
||||
showCommunity
|
||||
enableDownvotes={this.props.enableDownvotes}
|
||||
enableNsfw={this.props.enableNsfw}
|
||||
/>
|
||||
) : (
|
||||
<CommentNodes
|
||||
key={(i.data as Comment).id}
|
||||
nodes={[{ comment: i.data as Comment }]}
|
||||
admins={this.props.userRes.admins}
|
||||
noBorder
|
||||
noIndent
|
||||
showCommunity
|
||||
showContext
|
||||
enableDownvotes={this.props.enableDownvotes}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
<hr class="my-3" />
|
||||
</>
|
||||
))}
|
||||
{combined.map(i => [this.renderItemType(i), <hr class="my-3" />])}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -119,7 +150,7 @@ export class UserDetails extends Component<UserDetailsProps, UserDetailsState> {
|
|||
<div>
|
||||
<CommentNodes
|
||||
nodes={commentsToFlatNodes(this.props.userRes.comments)}
|
||||
admins={this.props.userRes.admins}
|
||||
admins={this.props.admins}
|
||||
noIndent
|
||||
showCommunity
|
||||
showContext
|
||||
|
@ -135,8 +166,8 @@ export class UserDetails extends Component<UserDetailsProps, UserDetailsState> {
|
|||
{this.props.userRes.posts.map(post => (
|
||||
<>
|
||||
<PostListing
|
||||
post={post}
|
||||
admins={this.props.userRes.admins}
|
||||
post_view={post}
|
||||
admins={this.props.admins}
|
||||
showCommunity
|
||||
enableDownvotes={this.props.enableDownvotes}
|
||||
enableNsfw={this.props.enableNsfw}
|
||||
|
|
|
@ -1,22 +1,12 @@
|
|||
import { Component } from 'inferno';
|
||||
import { Link } from 'inferno-router';
|
||||
import { UserView } from 'lemmy-js-client';
|
||||
import { UserSafe } from 'lemmy-js-client';
|
||||
import { showAvatars, hostname, isCakeDay } from '../utils';
|
||||
import { CakeDay } from './cake-day';
|
||||
import { PictrsImage } from './pictrs-image';
|
||||
|
||||
export interface UserOther {
|
||||
name: string;
|
||||
preferred_username?: string;
|
||||
id?: number; // Necessary if its federated
|
||||
avatar?: string;
|
||||
local?: boolean;
|
||||
actor_id?: string;
|
||||
published?: string;
|
||||
}
|
||||
|
||||
interface UserListingProps {
|
||||
user: UserView | UserOther;
|
||||
user: UserSafe;
|
||||
realLink?: boolean;
|
||||
useApubName?: boolean;
|
||||
muted?: boolean;
|
||||
|
|
|
@ -5,14 +5,13 @@ import {
|
|||
UserOperation,
|
||||
SortType,
|
||||
ListingType,
|
||||
UserSettingsForm,
|
||||
SaveUserSettings,
|
||||
LoginResponse,
|
||||
DeleteAccountForm,
|
||||
WebSocketJsonResponse,
|
||||
DeleteAccount,
|
||||
GetSiteResponse,
|
||||
UserDetailsResponse,
|
||||
GetUserDetailsResponse,
|
||||
AddAdminResponse,
|
||||
GetUserDetailsForm,
|
||||
GetUserDetails,
|
||||
CommentResponse,
|
||||
PostResponse,
|
||||
BanUserResponse,
|
||||
|
@ -40,9 +39,9 @@ import {
|
|||
editCommentRes,
|
||||
saveCommentRes,
|
||||
createPostLikeFindRes,
|
||||
setAuth,
|
||||
previewLines,
|
||||
editPostFindRes,
|
||||
wsUserOp,
|
||||
} from '../utils';
|
||||
import { UserListing } from './user-listing';
|
||||
import { HtmlTags } from './html-tags';
|
||||
|
@ -58,18 +57,18 @@ import { BannerIconHeader } from './banner-icon-header';
|
|||
import { CommunityLink } from './community-link';
|
||||
|
||||
interface UserState {
|
||||
userRes: UserDetailsResponse;
|
||||
userRes: GetUserDetailsResponse;
|
||||
userId: number;
|
||||
userName: string;
|
||||
view: UserDetailsView;
|
||||
sort: SortType;
|
||||
page: number;
|
||||
loading: boolean;
|
||||
userSettingsForm: UserSettingsForm;
|
||||
userSettingsForm: SaveUserSettings;
|
||||
userSettingsLoading: boolean;
|
||||
deleteAccountLoading: boolean;
|
||||
deleteAccountShowConfirm: boolean;
|
||||
deleteAccountForm: DeleteAccountForm;
|
||||
deleteAccountForm: DeleteAccount;
|
||||
siteRes: GetSiteResponse;
|
||||
}
|
||||
|
||||
|
@ -106,17 +105,18 @@ export class User extends Component<any, UserState> {
|
|||
lang: null,
|
||||
show_avatars: null,
|
||||
send_notifications_to_email: null,
|
||||
auth: null,
|
||||
bio: null,
|
||||
preferred_username: null,
|
||||
auth: UserService.Instance.authField(),
|
||||
},
|
||||
userSettingsLoading: null,
|
||||
deleteAccountLoading: null,
|
||||
deleteAccountShowConfirm: false,
|
||||
deleteAccountForm: {
|
||||
password: null,
|
||||
auth: UserService.Instance.authField(),
|
||||
},
|
||||
siteRes: this.isoData.site,
|
||||
siteRes: this.isoData.site_res,
|
||||
};
|
||||
|
||||
constructor(props: any, context: any) {
|
||||
|
@ -157,21 +157,22 @@ export class User extends Component<any, UserState> {
|
|||
}
|
||||
|
||||
fetchUserData() {
|
||||
let form: GetUserDetailsForm = {
|
||||
let form: GetUserDetails = {
|
||||
user_id: this.state.userId,
|
||||
username: this.state.userName,
|
||||
sort: this.state.sort,
|
||||
saved_only: this.state.view === UserDetailsView.Saved,
|
||||
page: this.state.page,
|
||||
limit: fetchLimit,
|
||||
auth: UserService.Instance.authField(false),
|
||||
};
|
||||
WebSocketService.Instance.getUserDetails(form);
|
||||
WebSocketService.Instance.client.getUserDetails(form);
|
||||
}
|
||||
|
||||
get isCurrentUser() {
|
||||
return (
|
||||
UserService.Instance.user &&
|
||||
UserService.Instance.user.id == this.state.userRes.user.id
|
||||
UserService.Instance.user.id == this.state.userRes.user_view.user.id
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -205,14 +206,14 @@ export class User extends Component<any, UserState> {
|
|||
let sort = this.getSortTypeFromProps(pathSplit[6]);
|
||||
let page = this.getPageFromProps(Number(pathSplit[8]));
|
||||
|
||||
let form: GetUserDetailsForm = {
|
||||
let form: GetUserDetails = {
|
||||
sort,
|
||||
saved_only: view === UserDetailsView.Saved,
|
||||
page,
|
||||
limit: fetchLimit,
|
||||
auth: req.auth,
|
||||
};
|
||||
this.setIdOrName(form, user_id, username);
|
||||
setAuth(form, req.auth);
|
||||
promises.push(req.client.getUserDetails(form));
|
||||
return promises;
|
||||
}
|
||||
|
@ -251,12 +252,12 @@ export class User extends Component<any, UserState> {
|
|||
}
|
||||
|
||||
get documentTitle(): string {
|
||||
return `@${this.state.userRes.user.name} - ${this.state.siteRes.site.name}`;
|
||||
return `@${this.state.userRes.user_view.user.name} - ${this.state.siteRes.site_view.site.name}`;
|
||||
}
|
||||
|
||||
get bioTag(): string {
|
||||
return this.state.userRes.user.bio
|
||||
? previewLines(this.state.userRes.user.bio)
|
||||
return this.state.userRes.user_view.user.bio
|
||||
? previewLines(this.state.userRes.user_view.user.bio)
|
||||
: undefined;
|
||||
}
|
||||
|
||||
|
@ -277,7 +278,7 @@ export class User extends Component<any, UserState> {
|
|||
title={this.documentTitle}
|
||||
path={this.context.router.route.match.url}
|
||||
description={this.bioTag}
|
||||
image={this.state.userRes.user.avatar}
|
||||
image={this.state.userRes.user_view.user.avatar}
|
||||
/>
|
||||
{this.userInfo()}
|
||||
<hr />
|
||||
|
@ -285,11 +286,14 @@ export class User extends Component<any, UserState> {
|
|||
{!this.state.loading && this.selects()}
|
||||
<UserDetails
|
||||
userRes={this.state.userRes}
|
||||
admins={this.state.siteRes.admins}
|
||||
sort={this.state.sort}
|
||||
page={this.state.page}
|
||||
limit={fetchLimit}
|
||||
enableDownvotes={this.state.siteRes.site.enable_downvotes}
|
||||
enableNsfw={this.state.siteRes.site.enable_nsfw}
|
||||
enableDownvotes={
|
||||
this.state.siteRes.site_view.site.enable_downvotes
|
||||
}
|
||||
enableNsfw={this.state.siteRes.site_view.site.enable_nsfw}
|
||||
view={this.state.view}
|
||||
onPageChange={this.handlePageChange}
|
||||
/>
|
||||
|
@ -391,29 +395,29 @@ export class User extends Component<any, UserState> {
|
|||
}
|
||||
|
||||
userInfo() {
|
||||
let user = this.state.userRes.user;
|
||||
let uv = this.state.userRes.user_view;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<BannerIconHeader banner={user.banner} icon={user.avatar} />
|
||||
<BannerIconHeader banner={uv.user.banner} icon={uv.user.avatar} />
|
||||
<div class="mb-3">
|
||||
<div class="">
|
||||
<div class="mb-0 d-flex flex-wrap">
|
||||
<div>
|
||||
{user.preferred_username && (
|
||||
<h5 class="mb-0">{user.preferred_username}</h5>
|
||||
{uv.user.preferred_username && (
|
||||
<h5 class="mb-0">{uv.user.preferred_username}</h5>
|
||||
)}
|
||||
<ul class="list-inline mb-2">
|
||||
<li className="list-inline-item">
|
||||
<UserListing
|
||||
user={user}
|
||||
user={uv.user}
|
||||
realLink
|
||||
useApubName
|
||||
muted
|
||||
hideAvatar
|
||||
/>
|
||||
</li>
|
||||
{user.banned && (
|
||||
{uv.user.banned && (
|
||||
<li className="list-inline-item badge badge-danger">
|
||||
{i18n.t('banned')}
|
||||
</li>
|
||||
|
@ -432,45 +436,45 @@ export class User extends Component<any, UserState> {
|
|||
<>
|
||||
<a
|
||||
className={`d-flex align-self-start btn btn-secondary mr-2 ${
|
||||
!user.matrix_user_id && 'invisible'
|
||||
!uv.user.matrix_user_id && 'invisible'
|
||||
}`}
|
||||
target="_blank"
|
||||
rel="noopener"
|
||||
href={`https://matrix.to/#/${user.matrix_user_id}`}
|
||||
href={`https://matrix.to/#/${uv.user.matrix_user_id}`}
|
||||
>
|
||||
{i18n.t('send_secure_message')}
|
||||
</a>
|
||||
<Link
|
||||
className={'d-flex align-self-start btn btn-secondary'}
|
||||
to={`/create_private_message/recipient/${user.id}`}
|
||||
to={`/create_private_message/recipient/${uv.user.id}`}
|
||||
>
|
||||
{i18n.t('send_message')}
|
||||
</Link>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
{user.bio && (
|
||||
{uv.user.bio && (
|
||||
<div className="d-flex align-items-center mb-2">
|
||||
<div
|
||||
className="md-div"
|
||||
dangerouslySetInnerHTML={mdToHtml(user.bio)}
|
||||
dangerouslySetInnerHTML={mdToHtml(uv.user.bio)}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
<div>
|
||||
<ul class="list-inline mb-2">
|
||||
<li className="list-inline-item badge badge-light">
|
||||
{i18n.t('number_of_posts', { count: user.number_of_posts })}
|
||||
{i18n.t('number_of_posts', { count: uv.counts.post_count })}
|
||||
</li>
|
||||
<li className="list-inline-item badge badge-light">
|
||||
{i18n.t('number_of_comments', {
|
||||
count: user.number_of_comments,
|
||||
count: uv.counts.comment_count,
|
||||
})}
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="text-muted">
|
||||
{i18n.t('joined')} <MomentTime data={user} showAgo />
|
||||
{i18n.t('joined')} <MomentTime data={uv.user} showAgo />
|
||||
</div>
|
||||
<div className="d-flex align-items-center text-muted mb-2">
|
||||
<svg class="icon">
|
||||
|
@ -478,7 +482,7 @@ export class User extends Component<any, UserState> {
|
|||
</svg>
|
||||
<span className="ml-2">
|
||||
{i18n.t('cake_day_title')}{' '}
|
||||
{moment.utc(user.published).local().format('MMM DD, YYYY')}
|
||||
{moment.utc(uv.user.published).local().format('MMM DD, YYYY')}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -704,7 +708,7 @@ export class User extends Component<any, UserState> {
|
|||
/>
|
||||
</div>
|
||||
</div>
|
||||
{this.state.siteRes.site.enable_nsfw && (
|
||||
{this.state.siteRes.site_view.site.enable_nsfw && (
|
||||
<div class="form-group">
|
||||
<div class="form-check">
|
||||
<input
|
||||
|
@ -840,17 +844,9 @@ export class User extends Component<any, UserState> {
|
|||
<div class="card-body">
|
||||
<h5>{i18n.t('moderates')}</h5>
|
||||
<ul class="list-unstyled mb-0">
|
||||
{this.state.userRes.moderates.map(community => (
|
||||
{this.state.userRes.moderates.map(cmv => (
|
||||
<li>
|
||||
<CommunityLink
|
||||
community={{
|
||||
name: community.community_name,
|
||||
id: community.community_id,
|
||||
local: community.community_local,
|
||||
actor_id: community.community_actor_id,
|
||||
icon: community.community_icon,
|
||||
}}
|
||||
/>
|
||||
<CommunityLink community={cmv.community} />
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
|
@ -869,17 +865,9 @@ export class User extends Component<any, UserState> {
|
|||
<div class="card-body">
|
||||
<h5>{i18n.t('subscribed')}</h5>
|
||||
<ul class="list-unstyled mb-0">
|
||||
{this.state.userRes.follows.map(community => (
|
||||
{this.state.userRes.follows.map(cfv => (
|
||||
<li>
|
||||
<CommunityLink
|
||||
community={{
|
||||
name: community.community_name,
|
||||
id: community.community_id,
|
||||
local: community.community_local,
|
||||
actor_id: community.community_actor_id,
|
||||
icon: community.community_icon,
|
||||
}}
|
||||
/>
|
||||
<CommunityLink community={cfv.community} />
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
|
@ -946,16 +934,12 @@ export class User extends Component<any, UserState> {
|
|||
}
|
||||
|
||||
handleUserSettingsSortTypeChange(val: SortType) {
|
||||
this.state.userSettingsForm.default_sort_type = Object.keys(
|
||||
SortType
|
||||
).indexOf(val);
|
||||
this.state.userSettingsForm.default_sort_type = val;
|
||||
this.setState(this.state);
|
||||
}
|
||||
|
||||
handleUserSettingsListingTypeChange(val: ListingType) {
|
||||
this.state.userSettingsForm.default_listing_type = Object.keys(
|
||||
ListingType
|
||||
).indexOf(val);
|
||||
this.state.userSettingsForm.default_listing_type = val;
|
||||
this.setState(this.state);
|
||||
}
|
||||
|
||||
|
@ -998,7 +982,7 @@ export class User extends Component<any, UserState> {
|
|||
i.state.userSettingsForm.matrix_user_id = event.target.value;
|
||||
if (
|
||||
i.state.userSettingsForm.matrix_user_id == '' &&
|
||||
!i.state.userRes.user.matrix_user_id
|
||||
!i.state.userRes.user_view.user.matrix_user_id
|
||||
) {
|
||||
i.state.userSettingsForm.matrix_user_id = undefined;
|
||||
}
|
||||
|
@ -1034,7 +1018,7 @@ export class User extends Component<any, UserState> {
|
|||
i.state.userSettingsLoading = true;
|
||||
i.setState(i.state);
|
||||
|
||||
WebSocketService.Instance.saveUserSettings(i.state.userSettingsForm);
|
||||
WebSocketService.Instance.client.saveUserSettings(i.state.userSettingsForm);
|
||||
}
|
||||
|
||||
handleDeleteAccountShowConfirmToggle(i: User, event: any) {
|
||||
|
@ -1058,7 +1042,7 @@ export class User extends Component<any, UserState> {
|
|||
i.state.deleteAccountLoading = true;
|
||||
i.setState(i.state);
|
||||
|
||||
WebSocketService.Instance.deleteAccount(i.state.deleteAccountForm);
|
||||
WebSocketService.Instance.client.deleteAccount(i.state.deleteAccountForm);
|
||||
i.handleLogoutClick(i);
|
||||
}
|
||||
|
||||
|
@ -1089,9 +1073,9 @@ export class User extends Component<any, UserState> {
|
|||
}
|
||||
}
|
||||
|
||||
parseMessage(msg: WebSocketJsonResponse) {
|
||||
parseMessage(msg: any) {
|
||||
console.log(msg);
|
||||
const res = wsJsonToRes(msg);
|
||||
let op = wsUserOp(msg);
|
||||
if (msg.error) {
|
||||
toast(i18n.t(msg.error), 'danger');
|
||||
if (msg.error == 'couldnt_find_that_username_or_email') {
|
||||
|
@ -1104,83 +1088,83 @@ export class User extends Component<any, UserState> {
|
|||
return;
|
||||
} else if (msg.reconnect) {
|
||||
this.fetchUserData();
|
||||
} else if (res.op == UserOperation.GetUserDetails) {
|
||||
} else if (op == UserOperation.GetUserDetails) {
|
||||
// Since the UserDetails contains posts/comments as well as some general user info we listen here as well
|
||||
// and set the parent state if it is not set or differs
|
||||
// TODO this might need to get abstracted
|
||||
const data = res.data as UserDetailsResponse;
|
||||
let data = wsJsonToRes<GetUserDetailsResponse>(msg).data;
|
||||
this.state.userRes = data;
|
||||
this.setUserInfo();
|
||||
this.state.loading = false;
|
||||
this.setState(this.state);
|
||||
} else if (res.op == UserOperation.SaveUserSettings) {
|
||||
const data = res.data as LoginResponse;
|
||||
} else if (op == UserOperation.SaveUserSettings) {
|
||||
let data = wsJsonToRes<LoginResponse>(msg).data;
|
||||
UserService.Instance.login(data);
|
||||
this.state.userRes.user.bio = this.state.userSettingsForm.bio;
|
||||
this.state.userRes.user.preferred_username = this.state.userSettingsForm.preferred_username;
|
||||
this.state.userRes.user.banner = this.state.userSettingsForm.banner;
|
||||
this.state.userRes.user.avatar = this.state.userSettingsForm.avatar;
|
||||
this.state.userRes.user_view.user.bio = this.state.userSettingsForm.bio;
|
||||
this.state.userRes.user_view.user.preferred_username = this.state.userSettingsForm.preferred_username;
|
||||
this.state.userRes.user_view.user.banner = this.state.userSettingsForm.banner;
|
||||
this.state.userRes.user_view.user.avatar = this.state.userSettingsForm.avatar;
|
||||
this.state.userSettingsLoading = false;
|
||||
this.setState(this.state);
|
||||
|
||||
window.scrollTo(0, 0);
|
||||
} else if (res.op == UserOperation.DeleteAccount) {
|
||||
} else if (op == UserOperation.DeleteAccount) {
|
||||
this.setState({
|
||||
deleteAccountLoading: false,
|
||||
deleteAccountShowConfirm: false,
|
||||
});
|
||||
this.context.router.history.push('/');
|
||||
} else if (res.op == UserOperation.AddAdmin) {
|
||||
const data = res.data as AddAdminResponse;
|
||||
} else if (op == UserOperation.AddAdmin) {
|
||||
let data = wsJsonToRes<AddAdminResponse>(msg).data;
|
||||
this.state.siteRes.admins = data.admins;
|
||||
this.setState(this.state);
|
||||
} else if (res.op == UserOperation.CreateCommentLike) {
|
||||
const data = res.data as CommentResponse;
|
||||
createCommentLikeRes(data, this.state.userRes.comments);
|
||||
} else if (op == UserOperation.CreateCommentLike) {
|
||||
let data = wsJsonToRes<CommentResponse>(msg).data;
|
||||
createCommentLikeRes(data.comment_view, this.state.userRes.comments);
|
||||
this.setState(this.state);
|
||||
} else if (
|
||||
res.op == UserOperation.EditComment ||
|
||||
res.op == UserOperation.DeleteComment ||
|
||||
res.op == UserOperation.RemoveComment
|
||||
op == UserOperation.EditComment ||
|
||||
op == UserOperation.DeleteComment ||
|
||||
op == UserOperation.RemoveComment
|
||||
) {
|
||||
const data = res.data as CommentResponse;
|
||||
editCommentRes(data, this.state.userRes.comments);
|
||||
let data = wsJsonToRes<CommentResponse>(msg).data;
|
||||
editCommentRes(data.comment_view, this.state.userRes.comments);
|
||||
this.setState(this.state);
|
||||
} else if (res.op == UserOperation.CreateComment) {
|
||||
const data = res.data as CommentResponse;
|
||||
} else if (op == UserOperation.CreateComment) {
|
||||
let data = wsJsonToRes<CommentResponse>(msg).data;
|
||||
if (
|
||||
UserService.Instance.user &&
|
||||
data.comment.creator_id == UserService.Instance.user.id
|
||||
data.comment_view.creator.id == UserService.Instance.user.id
|
||||
) {
|
||||
toast(i18n.t('reply_sent'));
|
||||
}
|
||||
} else if (res.op == UserOperation.SaveComment) {
|
||||
const data = res.data as CommentResponse;
|
||||
saveCommentRes(data, this.state.userRes.comments);
|
||||
} else if (op == UserOperation.SaveComment) {
|
||||
let data = wsJsonToRes<CommentResponse>(msg).data;
|
||||
saveCommentRes(data.comment_view, this.state.userRes.comments);
|
||||
this.setState(this.state);
|
||||
} else if (
|
||||
res.op == UserOperation.EditPost ||
|
||||
res.op == UserOperation.DeletePost ||
|
||||
res.op == UserOperation.RemovePost ||
|
||||
res.op == UserOperation.LockPost ||
|
||||
res.op == UserOperation.StickyPost ||
|
||||
res.op == UserOperation.SavePost
|
||||
op == UserOperation.EditPost ||
|
||||
op == UserOperation.DeletePost ||
|
||||
op == UserOperation.RemovePost ||
|
||||
op == UserOperation.LockPost ||
|
||||
op == UserOperation.StickyPost ||
|
||||
op == UserOperation.SavePost
|
||||
) {
|
||||
let data = res.data as PostResponse;
|
||||
editPostFindRes(data, this.state.userRes.posts);
|
||||
let data = wsJsonToRes<PostResponse>(msg).data;
|
||||
editPostFindRes(data.post_view, this.state.userRes.posts);
|
||||
this.setState(this.state);
|
||||
} else if (res.op == UserOperation.CreatePostLike) {
|
||||
const data = res.data as PostResponse;
|
||||
createPostLikeFindRes(data, this.state.userRes.posts);
|
||||
} else if (op == UserOperation.CreatePostLike) {
|
||||
let data = wsJsonToRes<PostResponse>(msg).data;
|
||||
createPostLikeFindRes(data.post_view, this.state.userRes.posts);
|
||||
this.setState(this.state);
|
||||
} else if (res.op == UserOperation.BanUser) {
|
||||
const data = res.data as BanUserResponse;
|
||||
} else if (op == UserOperation.BanUser) {
|
||||
let data = wsJsonToRes<BanUserResponse>(msg).data;
|
||||
this.state.userRes.comments
|
||||
.filter(c => c.creator_id == data.user.id)
|
||||
.forEach(c => (c.banned = data.banned));
|
||||
.filter(c => c.creator.id == data.user_view.user.id)
|
||||
.forEach(c => (c.creator.banned = data.banned));
|
||||
this.state.userRes.posts
|
||||
.filter(c => c.creator_id == data.user.id)
|
||||
.forEach(c => (c.banned = data.banned));
|
||||
.filter(c => c.creator.id == data.user_view.user.id)
|
||||
.forEach(c => (c.creator.banned = data.banned));
|
||||
this.setState(this.state);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,9 +1,14 @@
|
|||
import { GetSiteResponse, LemmyHttp } from 'lemmy-js-client';
|
||||
import {
|
||||
CommentView,
|
||||
GetSiteResponse,
|
||||
LemmyHttp,
|
||||
UserMentionView,
|
||||
} from 'lemmy-js-client';
|
||||
|
||||
export interface IsoData {
|
||||
path: string;
|
||||
routeData: any[];
|
||||
site: GetSiteResponse;
|
||||
site_res: GetSiteResponse;
|
||||
// Lang and theme
|
||||
lang: string;
|
||||
// communities?: ListCommunitiesResponse;
|
||||
|
@ -21,6 +26,20 @@ export interface InitialFetchRequest {
|
|||
client: LemmyHttp;
|
||||
}
|
||||
|
||||
export interface CommentNode {
|
||||
comment_view: CommentView | UserMentionView;
|
||||
children?: CommentNode[];
|
||||
depth?: number;
|
||||
}
|
||||
|
||||
export interface PostFormParams {
|
||||
name: string;
|
||||
url?: string;
|
||||
body?: string;
|
||||
community_name?: string;
|
||||
community_id?: number;
|
||||
}
|
||||
|
||||
export enum CommentSortType {
|
||||
Hot,
|
||||
Top,
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
// import Cookies from 'js-cookie';
|
||||
import IsomorphicCookie from 'isomorphic-cookie';
|
||||
import { User, LoginResponse } from 'lemmy-js-client';
|
||||
import { User_, LoginResponse } from 'lemmy-js-client';
|
||||
import jwt_decode from 'jwt-decode';
|
||||
import { Subject, BehaviorSubject } from 'rxjs';
|
||||
import { i18n } from '../i18next';
|
||||
import { toast } from '../utils';
|
||||
|
||||
interface Claims {
|
||||
id: number;
|
||||
|
@ -11,7 +13,7 @@ interface Claims {
|
|||
|
||||
export class UserService {
|
||||
private static _instance: UserService;
|
||||
public user: User;
|
||||
public user: User_;
|
||||
public claims: Claims;
|
||||
public jwtSub: Subject<string> = new Subject<string>();
|
||||
public unreadCountSub: BehaviorSubject<number> = new BehaviorSubject<number>(
|
||||
|
@ -48,6 +50,15 @@ export class UserService {
|
|||
return IsomorphicCookie.load('jwt');
|
||||
}
|
||||
|
||||
public authField(throwErr: boolean = true): string {
|
||||
if (this.auth == null && throwErr) {
|
||||
toast(i18n.t('not_logged_in'), 'danger');
|
||||
throw 'Not logged in';
|
||||
} else {
|
||||
return this.auth;
|
||||
}
|
||||
}
|
||||
|
||||
private setClaims(jwt: string) {
|
||||
this.claims = jwt_decode(jwt);
|
||||
this.jwtSub.next(jwt);
|
||||
|
|
|
@ -1,66 +1,10 @@
|
|||
import { wsUri } from '../env';
|
||||
import {
|
||||
LemmyWebsocket,
|
||||
LoginForm,
|
||||
RegisterForm,
|
||||
CommunityForm,
|
||||
DeleteCommunityForm,
|
||||
RemoveCommunityForm,
|
||||
PostForm,
|
||||
DeletePostForm,
|
||||
RemovePostForm,
|
||||
LockPostForm,
|
||||
StickyPostForm,
|
||||
SavePostForm,
|
||||
CommentForm,
|
||||
DeleteCommentForm,
|
||||
RemoveCommentForm,
|
||||
MarkCommentAsReadForm,
|
||||
SaveCommentForm,
|
||||
CommentLikeForm,
|
||||
GetPostForm,
|
||||
GetPostsForm,
|
||||
CreatePostLikeForm,
|
||||
GetCommunityForm,
|
||||
FollowCommunityForm,
|
||||
GetFollowedCommunitiesForm,
|
||||
GetUserDetailsForm,
|
||||
ListCommunitiesForm,
|
||||
GetModlogForm,
|
||||
BanFromCommunityForm,
|
||||
AddModToCommunityForm,
|
||||
TransferCommunityForm,
|
||||
AddAdminForm,
|
||||
TransferSiteForm,
|
||||
BanUserForm,
|
||||
SiteForm,
|
||||
UserView,
|
||||
GetRepliesForm,
|
||||
GetUserMentionsForm,
|
||||
MarkUserMentionAsReadForm,
|
||||
SearchForm,
|
||||
UserSettingsForm,
|
||||
DeleteAccountForm,
|
||||
PasswordResetForm,
|
||||
PasswordChangeForm,
|
||||
PrivateMessageForm,
|
||||
EditPrivateMessageForm,
|
||||
DeletePrivateMessageForm,
|
||||
MarkPrivateMessageAsReadForm,
|
||||
GetPrivateMessagesForm,
|
||||
GetCommentsForm,
|
||||
UserJoinForm,
|
||||
GetSiteConfig,
|
||||
GetSiteForm,
|
||||
SiteConfigForm,
|
||||
MarkAllAsReadForm,
|
||||
UserViewSafe,
|
||||
WebSocketJsonResponse,
|
||||
CommunityJoinForm,
|
||||
PostJoinForm,
|
||||
} from 'lemmy-js-client';
|
||||
import { UserService } from './';
|
||||
import { i18n } from '../i18next';
|
||||
import { toast, isBrowser } from '../utils';
|
||||
import { isBrowser } from '../utils';
|
||||
import { Observable } from 'rxjs';
|
||||
import { share } from 'rxjs/operators';
|
||||
import {
|
||||
|
@ -77,9 +21,9 @@ export class WebSocketService {
|
|||
};
|
||||
public subject: Observable<any>;
|
||||
|
||||
public admins: UserView[];
|
||||
public banned: UserView[];
|
||||
private client = new LemmyWebsocket();
|
||||
public admins: UserViewSafe[];
|
||||
public banned: UserViewSafe[];
|
||||
public client = new LemmyWebsocket();
|
||||
|
||||
private constructor() {
|
||||
this.ws = new ReconnectingWebSocket(wsUri, [], this.wsOptions);
|
||||
|
@ -93,7 +37,7 @@ export class WebSocketService {
|
|||
console.log(`Connected to ${wsUri}`);
|
||||
|
||||
if (!firstConnect) {
|
||||
let res: WebSocketJsonResponse = {
|
||||
let res: WebSocketJsonResponse<any> = {
|
||||
reconnect: true,
|
||||
};
|
||||
obs.next(res);
|
||||
|
@ -107,307 +51,6 @@ export class WebSocketService {
|
|||
public static get Instance() {
|
||||
return this._instance || (this._instance = new this());
|
||||
}
|
||||
|
||||
public userJoin() {
|
||||
let form: UserJoinForm = { auth: UserService.Instance.auth };
|
||||
this.ws.send(this.client.userJoin(form));
|
||||
}
|
||||
|
||||
public postJoin(form: PostJoinForm) {
|
||||
this.ws.send(this.client.postJoin(form));
|
||||
}
|
||||
|
||||
public communityJoin(form: CommunityJoinForm) {
|
||||
this.ws.send(this.client.communityJoin(form));
|
||||
}
|
||||
|
||||
public login(form: LoginForm) {
|
||||
this.ws.send(this.client.login(form));
|
||||
}
|
||||
|
||||
public register(form: RegisterForm) {
|
||||
this.ws.send(this.client.register(form));
|
||||
}
|
||||
|
||||
public getCaptcha() {
|
||||
this.ws.send(this.client.getCaptcha());
|
||||
}
|
||||
|
||||
public createCommunity(form: CommunityForm) {
|
||||
this.setAuth(form); // TODO all these setauths at some point would be good to make required
|
||||
this.ws.send(this.client.createCommunity(form));
|
||||
}
|
||||
|
||||
public editCommunity(form: CommunityForm) {
|
||||
this.setAuth(form);
|
||||
this.ws.send(this.client.editCommunity(form));
|
||||
}
|
||||
|
||||
public deleteCommunity(form: DeleteCommunityForm) {
|
||||
this.setAuth(form);
|
||||
this.ws.send(this.client.deleteCommunity(form));
|
||||
}
|
||||
|
||||
public removeCommunity(form: RemoveCommunityForm) {
|
||||
this.setAuth(form);
|
||||
this.ws.send(this.client.removeCommunity(form));
|
||||
}
|
||||
|
||||
public followCommunity(form: FollowCommunityForm) {
|
||||
this.setAuth(form);
|
||||
this.ws.send(this.client.followCommunity(form));
|
||||
}
|
||||
|
||||
public listCommunities(form: ListCommunitiesForm) {
|
||||
this.setAuth(form, false);
|
||||
this.ws.send(this.client.listCommunities(form));
|
||||
}
|
||||
|
||||
public getFollowedCommunities() {
|
||||
let form: GetFollowedCommunitiesForm = { auth: UserService.Instance.auth };
|
||||
this.ws.send(this.client.getFollowedCommunities(form));
|
||||
}
|
||||
|
||||
public listCategories() {
|
||||
this.ws.send(this.client.listCategories());
|
||||
}
|
||||
|
||||
public createPost(form: PostForm) {
|
||||
this.setAuth(form);
|
||||
this.ws.send(this.client.createPost(form));
|
||||
}
|
||||
|
||||
public getPost(form: GetPostForm) {
|
||||
this.setAuth(form, false);
|
||||
this.ws.send(this.client.getPost(form));
|
||||
}
|
||||
|
||||
public getCommunity(form: GetCommunityForm) {
|
||||
this.setAuth(form, false);
|
||||
this.ws.send(this.client.getCommunity(form));
|
||||
}
|
||||
|
||||
public createComment(form: CommentForm) {
|
||||
this.setAuth(form);
|
||||
this.ws.send(this.client.createComment(form));
|
||||
}
|
||||
|
||||
public editComment(form: CommentForm) {
|
||||
this.setAuth(form);
|
||||
this.ws.send(this.client.editComment(form));
|
||||
}
|
||||
|
||||
public deleteComment(form: DeleteCommentForm) {
|
||||
this.setAuth(form);
|
||||
this.ws.send(this.client.deleteComment(form));
|
||||
}
|
||||
|
||||
public removeComment(form: RemoveCommentForm) {
|
||||
this.setAuth(form);
|
||||
this.ws.send(this.client.removeComment(form));
|
||||
}
|
||||
|
||||
public markCommentAsRead(form: MarkCommentAsReadForm) {
|
||||
this.setAuth(form);
|
||||
this.ws.send(this.client.markCommentAsRead(form));
|
||||
}
|
||||
|
||||
public likeComment(form: CommentLikeForm) {
|
||||
this.setAuth(form);
|
||||
this.ws.send(this.client.likeComment(form));
|
||||
}
|
||||
|
||||
public saveComment(form: SaveCommentForm) {
|
||||
this.setAuth(form);
|
||||
this.ws.send(this.client.saveComment(form));
|
||||
}
|
||||
|
||||
public getPosts(form: GetPostsForm) {
|
||||
this.setAuth(form, false);
|
||||
this.ws.send(this.client.getPosts(form));
|
||||
}
|
||||
|
||||
public getComments(form: GetCommentsForm) {
|
||||
this.setAuth(form, false);
|
||||
this.ws.send(this.client.getComments(form));
|
||||
}
|
||||
|
||||
public likePost(form: CreatePostLikeForm) {
|
||||
this.setAuth(form);
|
||||
this.ws.send(this.client.likePost(form));
|
||||
}
|
||||
|
||||
public editPost(form: PostForm) {
|
||||
this.setAuth(form);
|
||||
this.ws.send(this.client.editPost(form));
|
||||
}
|
||||
|
||||
public deletePost(form: DeletePostForm) {
|
||||
this.setAuth(form);
|
||||
this.ws.send(this.client.deletePost(form));
|
||||
}
|
||||
|
||||
public removePost(form: RemovePostForm) {
|
||||
this.setAuth(form);
|
||||
this.ws.send(this.client.removePost(form));
|
||||
}
|
||||
|
||||
public lockPost(form: LockPostForm) {
|
||||
this.setAuth(form);
|
||||
this.ws.send(this.client.lockPost(form));
|
||||
}
|
||||
|
||||
public stickyPost(form: StickyPostForm) {
|
||||
this.setAuth(form);
|
||||
this.ws.send(this.client.stickyPost(form));
|
||||
}
|
||||
|
||||
public savePost(form: SavePostForm) {
|
||||
this.setAuth(form);
|
||||
this.ws.send(this.client.savePost(form));
|
||||
}
|
||||
|
||||
public banFromCommunity(form: BanFromCommunityForm) {
|
||||
this.setAuth(form);
|
||||
this.ws.send(this.client.banFromCommunity(form));
|
||||
}
|
||||
|
||||
public addModToCommunity(form: AddModToCommunityForm) {
|
||||
this.setAuth(form);
|
||||
this.ws.send(this.client.addModToCommunity(form));
|
||||
}
|
||||
|
||||
public transferCommunity(form: TransferCommunityForm) {
|
||||
this.setAuth(form);
|
||||
this.ws.send(this.client.transferCommunity(form));
|
||||
}
|
||||
|
||||
public transferSite(form: TransferSiteForm) {
|
||||
this.setAuth(form);
|
||||
this.ws.send(this.client.transferSite(form));
|
||||
}
|
||||
|
||||
public banUser(form: BanUserForm) {
|
||||
this.setAuth(form);
|
||||
this.ws.send(this.client.banUser(form));
|
||||
}
|
||||
|
||||
public addAdmin(form: AddAdminForm) {
|
||||
this.setAuth(form);
|
||||
this.ws.send(this.client.addAdmin(form));
|
||||
}
|
||||
|
||||
public getUserDetails(form: GetUserDetailsForm) {
|
||||
this.setAuth(form, false);
|
||||
this.ws.send(this.client.getUserDetails(form));
|
||||
}
|
||||
|
||||
public getReplies(form: GetRepliesForm) {
|
||||
this.setAuth(form);
|
||||
this.ws.send(this.client.getReplies(form));
|
||||
}
|
||||
|
||||
public getUserMentions(form: GetUserMentionsForm) {
|
||||
this.setAuth(form);
|
||||
this.ws.send(this.client.getUserMentions(form));
|
||||
}
|
||||
|
||||
public markUserMentionAsRead(form: MarkUserMentionAsReadForm) {
|
||||
this.setAuth(form);
|
||||
this.ws.send(this.client.markUserMentionAsRead(form));
|
||||
}
|
||||
|
||||
public getModlog(form: GetModlogForm) {
|
||||
this.ws.send(this.client.getModlog(form));
|
||||
}
|
||||
|
||||
public createSite(form: SiteForm) {
|
||||
this.setAuth(form);
|
||||
this.ws.send(this.client.createSite(form));
|
||||
}
|
||||
|
||||
public editSite(form: SiteForm) {
|
||||
this.setAuth(form);
|
||||
this.ws.send(this.client.editSite(form));
|
||||
}
|
||||
|
||||
public getSite(form: GetSiteForm = {}) {
|
||||
this.setAuth(form, false);
|
||||
this.ws.send(this.client.getSite(form));
|
||||
}
|
||||
|
||||
public getSiteConfig() {
|
||||
let form: GetSiteConfig = {};
|
||||
this.setAuth(form);
|
||||
this.ws.send(this.client.getSiteConfig(form));
|
||||
}
|
||||
|
||||
public search(form: SearchForm) {
|
||||
this.setAuth(form, false);
|
||||
this.ws.send(this.client.search(form));
|
||||
}
|
||||
|
||||
public markAllAsRead() {
|
||||
let form: MarkAllAsReadForm = { auth: null };
|
||||
this.setAuth(form);
|
||||
this.ws.send(this.client.markAllAsRead(form));
|
||||
}
|
||||
|
||||
public saveUserSettings(form: UserSettingsForm) {
|
||||
this.setAuth(form);
|
||||
this.ws.send(this.client.saveUserSettings(form));
|
||||
}
|
||||
|
||||
public deleteAccount(form: DeleteAccountForm) {
|
||||
this.setAuth(form);
|
||||
this.ws.send(this.client.deleteAccount(form));
|
||||
}
|
||||
|
||||
public passwordReset(form: PasswordResetForm) {
|
||||
this.ws.send(this.client.passwordReset(form));
|
||||
}
|
||||
|
||||
public passwordChange(form: PasswordChangeForm) {
|
||||
this.ws.send(this.client.passwordChange(form));
|
||||
}
|
||||
|
||||
public createPrivateMessage(form: PrivateMessageForm) {
|
||||
this.setAuth(form);
|
||||
this.ws.send(this.client.createPrivateMessage(form));
|
||||
}
|
||||
|
||||
public editPrivateMessage(form: EditPrivateMessageForm) {
|
||||
this.setAuth(form);
|
||||
this.ws.send(this.client.editPrivateMessage(form));
|
||||
}
|
||||
|
||||
public deletePrivateMessage(form: DeletePrivateMessageForm) {
|
||||
this.setAuth(form);
|
||||
this.ws.send(this.client.deletePrivateMessage(form));
|
||||
}
|
||||
|
||||
public markPrivateMessageAsRead(form: MarkPrivateMessageAsReadForm) {
|
||||
this.setAuth(form);
|
||||
this.ws.send(this.client.markPrivateMessageAsRead(form));
|
||||
}
|
||||
|
||||
public getPrivateMessages(form: GetPrivateMessagesForm) {
|
||||
this.setAuth(form);
|
||||
this.ws.send(this.client.getPrivateMessages(form));
|
||||
}
|
||||
|
||||
public saveSiteConfig(form: SiteConfigForm) {
|
||||
this.setAuth(form);
|
||||
this.ws.send(this.client.saveSiteConfig(form));
|
||||
}
|
||||
|
||||
public setAuth(obj: any, throwErr: boolean = true) {
|
||||
obj.auth = UserService.Instance.auth;
|
||||
if (obj.auth == null && throwErr) {
|
||||
toast(i18n.t('not_logged_in'), 'danger');
|
||||
throw 'Not logged in';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isBrowser()) {
|
||||
|
|
|
@ -30,23 +30,25 @@ import 'moment/locale/da';
|
|||
|
||||
import {
|
||||
UserOperation,
|
||||
Comment,
|
||||
CommentNode as CommentNodeI,
|
||||
Post,
|
||||
PrivateMessage,
|
||||
User,
|
||||
CommentView,
|
||||
User_,
|
||||
SortType,
|
||||
ListingType,
|
||||
SearchType,
|
||||
WebSocketResponse,
|
||||
WebSocketJsonResponse,
|
||||
SearchForm,
|
||||
Search,
|
||||
SearchResponse,
|
||||
CommentResponse,
|
||||
PostResponse,
|
||||
PostView,
|
||||
PrivateMessageView,
|
||||
} from 'lemmy-js-client';
|
||||
|
||||
import { CommentSortType, DataType, IsoData } from './interfaces';
|
||||
import {
|
||||
CommentSortType,
|
||||
DataType,
|
||||
IsoData,
|
||||
CommentNode as CommentNodeI,
|
||||
} from './interfaces';
|
||||
import { UserService, WebSocketService } from './services';
|
||||
|
||||
var Tribute;
|
||||
|
@ -154,14 +156,20 @@ export function randomStr(
|
|||
.join('');
|
||||
}
|
||||
|
||||
export function wsJsonToRes(msg: WebSocketJsonResponse): WebSocketResponse {
|
||||
let opStr: string = msg.op;
|
||||
export function wsJsonToRes<ResponseType>(
|
||||
msg: WebSocketJsonResponse<ResponseType>
|
||||
): WebSocketResponse<ResponseType> {
|
||||
return {
|
||||
op: UserOperation[opStr],
|
||||
op: wsUserOp(msg),
|
||||
data: msg.data,
|
||||
};
|
||||
}
|
||||
|
||||
export function wsUserOp(msg: any): UserOperation {
|
||||
let opStr: string = msg.op;
|
||||
return UserOperation[opStr];
|
||||
}
|
||||
|
||||
export const md = new markdown_it({
|
||||
html: false,
|
||||
linkify: true,
|
||||
|
@ -190,12 +198,16 @@ export const md = new markdown_it({
|
|||
defs: objectFlip(emojiShortName),
|
||||
});
|
||||
|
||||
export function hotRankComment(comment: Comment): number {
|
||||
return hotRank(comment.score, comment.published);
|
||||
export function hotRankComment(comment_view: CommentView): number {
|
||||
return hotRank(comment_view.counts.score, comment_view.comment.published);
|
||||
}
|
||||
|
||||
export function hotRankPost(post: Post): number {
|
||||
return hotRank(post.score, post.newest_activity_time);
|
||||
export function hotRankActivePost(post_view: PostView): number {
|
||||
return hotRank(post_view.counts.score, post_view.counts.newest_comment_time);
|
||||
}
|
||||
|
||||
export function hotRankPost(post_view: PostView): number {
|
||||
return hotRank(post_view.counts.score, post_view.post.published);
|
||||
}
|
||||
|
||||
export function hotRank(score: number, timeStr: string): number {
|
||||
|
@ -221,17 +233,8 @@ export function getUnixTime(text: string): number {
|
|||
return text ? new Date(text).getTime() / 1000 : undefined;
|
||||
}
|
||||
|
||||
export function addTypeInfo<T>(
|
||||
arr: T[],
|
||||
name: string
|
||||
): { type_: string; data: T }[] {
|
||||
return arr.map(e => {
|
||||
return { type_: name, data: e };
|
||||
});
|
||||
}
|
||||
|
||||
export function canMod(
|
||||
user: User,
|
||||
user: User_,
|
||||
modIds: number[],
|
||||
creator_id: number,
|
||||
onSelf: boolean = false
|
||||
|
@ -509,21 +512,6 @@ export function isCakeDay(published: string): boolean {
|
|||
);
|
||||
}
|
||||
|
||||
export function isCommentType(
|
||||
item: Comment | PrivateMessage | Post
|
||||
): item is Comment {
|
||||
return (
|
||||
(item as Comment).community_id !== undefined &&
|
||||
(item as Comment).content !== undefined
|
||||
);
|
||||
}
|
||||
|
||||
export function isPostType(
|
||||
item: Comment | PrivateMessage | Post
|
||||
): item is Post {
|
||||
return (item as Post).stickied !== undefined;
|
||||
}
|
||||
|
||||
export function toast(text: string, background: string = 'success') {
|
||||
if (isBrowser()) {
|
||||
let backgroundColor = `var(--${background})`;
|
||||
|
@ -592,32 +580,34 @@ export function messageToastify(info: NotifyInfo, router: any) {
|
|||
}
|
||||
}
|
||||
|
||||
export function notifyPost(post: Post, router: any) {
|
||||
export function notifyPost(post_view: PostView, router: any) {
|
||||
let info: NotifyInfo = {
|
||||
name: post.community_name,
|
||||
icon: post.community_icon ? post.community_icon : defaultFavIcon,
|
||||
link: `/post/${post.id}`,
|
||||
body: post.name,
|
||||
name: post_view.community.name,
|
||||
icon: post_view.community.icon ? post_view.community.icon : defaultFavIcon,
|
||||
link: `/post/${post_view.post.id}`,
|
||||
body: post_view.post.name,
|
||||
};
|
||||
notify(info, router);
|
||||
}
|
||||
|
||||
export function notifyComment(comment: Comment, router: any) {
|
||||
export function notifyComment(comment_view: CommentView, router: any) {
|
||||
let info: NotifyInfo = {
|
||||
name: comment.creator_name,
|
||||
icon: comment.creator_avatar ? comment.creator_avatar : defaultFavIcon,
|
||||
link: `/post/${comment.post_id}/comment/${comment.id}`,
|
||||
body: comment.content,
|
||||
name: comment_view.creator.name,
|
||||
icon: comment_view.creator.avatar
|
||||
? comment_view.creator.avatar
|
||||
: defaultFavIcon,
|
||||
link: `/post/${comment_view.post.id}/comment/${comment_view.comment.id}`,
|
||||
body: comment_view.comment.content,
|
||||
};
|
||||
notify(info, router);
|
||||
}
|
||||
|
||||
export function notifyPrivateMessage(pm: PrivateMessage, router: any) {
|
||||
export function notifyPrivateMessage(pmv: PrivateMessageView, router: any) {
|
||||
let info: NotifyInfo = {
|
||||
name: pm.creator_name,
|
||||
icon: pm.creator_avatar ? pm.creator_avatar : defaultFavIcon,
|
||||
name: pmv.creator.name,
|
||||
icon: pmv.creator.avatar ? pmv.creator.avatar : defaultFavIcon,
|
||||
link: `/inbox`,
|
||||
body: pm.content,
|
||||
body: pmv.private_message.content,
|
||||
};
|
||||
notify(info, router);
|
||||
}
|
||||
|
@ -723,27 +713,28 @@ export function setupTippy() {
|
|||
|
||||
function userSearch(text: string, cb: any) {
|
||||
if (text) {
|
||||
let form: SearchForm = {
|
||||
let form: Search = {
|
||||
q: text,
|
||||
type_: SearchType.Users,
|
||||
sort: SortType.TopAll,
|
||||
page: 1,
|
||||
limit: mentionDropdownFetchLimit,
|
||||
auth: UserService.Instance.authField(false),
|
||||
};
|
||||
|
||||
WebSocketService.Instance.search(form);
|
||||
WebSocketService.Instance.client.search(form);
|
||||
|
||||
let userSub = WebSocketService.Instance.subject.subscribe(
|
||||
msg => {
|
||||
let res = wsJsonToRes(msg);
|
||||
if (res.op == UserOperation.Search) {
|
||||
let data = res.data as SearchResponse;
|
||||
let users = data.users.map(u => {
|
||||
let users = data.users.map(uv => {
|
||||
return {
|
||||
key: `@${u.name}@${hostname(u.actor_id)}`,
|
||||
name: u.name,
|
||||
local: u.local,
|
||||
id: u.id,
|
||||
key: `@${uv.user.name}@${hostname(uv.user.actor_id)}`,
|
||||
name: uv.user.name,
|
||||
local: uv.user.local,
|
||||
id: uv.user.id,
|
||||
};
|
||||
});
|
||||
cb(users);
|
||||
|
@ -760,27 +751,28 @@ function userSearch(text: string, cb: any) {
|
|||
|
||||
function communitySearch(text: string, cb: any) {
|
||||
if (text) {
|
||||
let form: SearchForm = {
|
||||
let form: Search = {
|
||||
q: text,
|
||||
type_: SearchType.Communities,
|
||||
sort: SortType.TopAll,
|
||||
page: 1,
|
||||
limit: mentionDropdownFetchLimit,
|
||||
auth: UserService.Instance.authField(false),
|
||||
};
|
||||
|
||||
WebSocketService.Instance.search(form);
|
||||
WebSocketService.Instance.client.search(form);
|
||||
|
||||
let communitySub = WebSocketService.Instance.subject.subscribe(
|
||||
msg => {
|
||||
let res = wsJsonToRes(msg);
|
||||
if (res.op == UserOperation.Search) {
|
||||
let data = res.data as SearchResponse;
|
||||
let communities = data.communities.map(c => {
|
||||
let communities = data.communities.map(cv => {
|
||||
return {
|
||||
key: `!${c.name}@${hostname(c.actor_id)}`,
|
||||
name: c.name,
|
||||
local: c.local,
|
||||
id: c.id,
|
||||
key: `!${cv.community.name}@${hostname(cv.community.actor_id)}`,
|
||||
name: cv.community.name,
|
||||
local: cv.community.local,
|
||||
id: cv.community.id,
|
||||
};
|
||||
});
|
||||
cb(communities);
|
||||
|
@ -840,84 +832,84 @@ export function getUsernameFromProps(props: any): string {
|
|||
return props.match.params.username;
|
||||
}
|
||||
|
||||
export function editCommentRes(data: CommentResponse, comments: Comment[]) {
|
||||
let found = comments.find(c => c.id == data.comment.id);
|
||||
export function editCommentRes(data: CommentView, comments: CommentView[]) {
|
||||
let found = comments.find(c => c.comment.id == data.comment.id);
|
||||
if (found) {
|
||||
found.content = data.comment.content;
|
||||
found.updated = data.comment.updated;
|
||||
found.removed = data.comment.removed;
|
||||
found.deleted = data.comment.deleted;
|
||||
found.upvotes = data.comment.upvotes;
|
||||
found.downvotes = data.comment.downvotes;
|
||||
found.score = data.comment.score;
|
||||
found.comment.content = data.comment.content;
|
||||
found.comment.updated = data.comment.updated;
|
||||
found.comment.removed = data.comment.removed;
|
||||
found.comment.deleted = data.comment.deleted;
|
||||
found.counts.upvotes = data.counts.upvotes;
|
||||
found.counts.downvotes = data.counts.downvotes;
|
||||
found.counts.score = data.counts.score;
|
||||
}
|
||||
}
|
||||
|
||||
export function saveCommentRes(data: CommentResponse, comments: Comment[]) {
|
||||
let found = comments.find(c => c.id == data.comment.id);
|
||||
export function saveCommentRes(data: CommentView, comments: CommentView[]) {
|
||||
let found = comments.find(c => c.comment.id == data.comment.id);
|
||||
if (found) {
|
||||
found.saved = data.comment.saved;
|
||||
found.saved = data.saved;
|
||||
}
|
||||
}
|
||||
|
||||
export function createCommentLikeRes(
|
||||
data: CommentResponse,
|
||||
comments: Comment[]
|
||||
data: CommentView,
|
||||
comments: CommentView[]
|
||||
) {
|
||||
let found: Comment = comments.find(c => c.id === data.comment.id);
|
||||
let found = comments.find(c => c.comment.id === data.comment.id);
|
||||
if (found) {
|
||||
found.score = data.comment.score;
|
||||
found.upvotes = data.comment.upvotes;
|
||||
found.downvotes = data.comment.downvotes;
|
||||
if (data.comment.my_vote !== null) {
|
||||
found.my_vote = data.comment.my_vote;
|
||||
found.counts.score = data.counts.score;
|
||||
found.counts.upvotes = data.counts.upvotes;
|
||||
found.counts.downvotes = data.counts.downvotes;
|
||||
if (data.my_vote !== null) {
|
||||
found.my_vote = data.my_vote;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function createPostLikeFindRes(data: PostResponse, posts: Post[]) {
|
||||
let found = posts.find(c => c.id == data.post.id);
|
||||
export function createPostLikeFindRes(data: PostView, posts: PostView[]) {
|
||||
let found = posts.find(p => p.post.id == data.post.id);
|
||||
if (found) {
|
||||
createPostLikeRes(data, found);
|
||||
}
|
||||
}
|
||||
|
||||
export function createPostLikeRes(data: PostResponse, post: Post) {
|
||||
if (post) {
|
||||
post.score = data.post.score;
|
||||
post.upvotes = data.post.upvotes;
|
||||
post.downvotes = data.post.downvotes;
|
||||
if (data.post.my_vote !== null) {
|
||||
post.my_vote = data.post.my_vote;
|
||||
export function createPostLikeRes(data: PostView, post_view: PostView) {
|
||||
if (post_view) {
|
||||
post_view.counts.score = data.counts.score;
|
||||
post_view.counts.upvotes = data.counts.upvotes;
|
||||
post_view.counts.downvotes = data.counts.downvotes;
|
||||
if (data.my_vote !== null) {
|
||||
post_view.my_vote = data.my_vote;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function editPostFindRes(data: PostResponse, posts: Post[]) {
|
||||
let found = posts.find(c => c.id == data.post.id);
|
||||
export function editPostFindRes(data: PostView, posts: PostView[]) {
|
||||
let found = posts.find(p => p.post.id == data.post.id);
|
||||
if (found) {
|
||||
editPostRes(data, found);
|
||||
}
|
||||
}
|
||||
|
||||
export function editPostRes(data: PostResponse, post: Post) {
|
||||
export function editPostRes(data: PostView, post: PostView) {
|
||||
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;
|
||||
post.saved = data.post.saved;
|
||||
post.post.url = data.post.url;
|
||||
post.post.name = data.post.name;
|
||||
post.post.nsfw = data.post.nsfw;
|
||||
post.post.deleted = data.post.deleted;
|
||||
post.post.removed = data.post.removed;
|
||||
post.post.stickied = data.post.stickied;
|
||||
post.post.body = data.post.body;
|
||||
post.post.locked = data.post.locked;
|
||||
post.saved = data.saved;
|
||||
}
|
||||
}
|
||||
|
||||
export function commentsToFlatNodes(comments: Comment[]): CommentNodeI[] {
|
||||
export function commentsToFlatNodes(comments: CommentView[]): CommentNodeI[] {
|
||||
let nodes: CommentNodeI[] = [];
|
||||
for (let comment of comments) {
|
||||
nodes.push({ comment: comment });
|
||||
nodes.push({ comment_view: comment });
|
||||
}
|
||||
return nodes;
|
||||
}
|
||||
|
@ -927,30 +919,34 @@ export function commentSort(tree: CommentNodeI[], sort: CommentSortType) {
|
|||
if (sort == CommentSortType.Top) {
|
||||
tree.sort(
|
||||
(a, b) =>
|
||||
+a.comment.removed - +b.comment.removed ||
|
||||
+a.comment.deleted - +b.comment.deleted ||
|
||||
b.comment.score - a.comment.score
|
||||
+a.comment_view.comment.removed - +b.comment_view.comment.removed ||
|
||||
+a.comment_view.comment.deleted - +b.comment_view.comment.deleted ||
|
||||
b.comment_view.counts.score - a.comment_view.counts.score
|
||||
);
|
||||
} else if (sort == CommentSortType.New) {
|
||||
tree.sort(
|
||||
(a, b) =>
|
||||
+a.comment.removed - +b.comment.removed ||
|
||||
+a.comment.deleted - +b.comment.deleted ||
|
||||
b.comment.published.localeCompare(a.comment.published)
|
||||
+a.comment_view.comment.removed - +b.comment_view.comment.removed ||
|
||||
+a.comment_view.comment.deleted - +b.comment_view.comment.deleted ||
|
||||
b.comment_view.comment.published.localeCompare(
|
||||
a.comment_view.comment.published
|
||||
)
|
||||
);
|
||||
} else if (sort == CommentSortType.Old) {
|
||||
tree.sort(
|
||||
(a, b) =>
|
||||
+a.comment.removed - +b.comment.removed ||
|
||||
+a.comment.deleted - +b.comment.deleted ||
|
||||
a.comment.published.localeCompare(b.comment.published)
|
||||
+a.comment_view.comment.removed - +b.comment_view.comment.removed ||
|
||||
+a.comment_view.comment.deleted - +b.comment_view.comment.deleted ||
|
||||
a.comment_view.comment.published.localeCompare(
|
||||
b.comment_view.comment.published
|
||||
)
|
||||
);
|
||||
} else if (sort == CommentSortType.Hot) {
|
||||
tree.sort(
|
||||
(a, b) =>
|
||||
+a.comment.removed - +b.comment.removed ||
|
||||
+a.comment.deleted - +b.comment.deleted ||
|
||||
hotRankComment(b.comment) - hotRankComment(a.comment)
|
||||
+a.comment_view.comment.removed - +b.comment_view.comment.removed ||
|
||||
+a.comment_view.comment.deleted - +b.comment_view.comment.deleted ||
|
||||
hotRankComment(b.comment_view) - hotRankComment(a.comment_view)
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -985,7 +981,7 @@ function convertCommentSortType(sort: SortType): CommentSortType {
|
|||
}
|
||||
|
||||
export function postSort(
|
||||
posts: Post[],
|
||||
posts: PostView[],
|
||||
sort: SortType,
|
||||
communityType: boolean
|
||||
) {
|
||||
|
@ -999,34 +995,34 @@ export function postSort(
|
|||
) {
|
||||
posts.sort(
|
||||
(a, b) =>
|
||||
+a.removed - +b.removed ||
|
||||
+a.deleted - +b.deleted ||
|
||||
(communityType && +b.stickied - +a.stickied) ||
|
||||
b.score - a.score
|
||||
+a.post.removed - +b.post.removed ||
|
||||
+a.post.deleted - +b.post.deleted ||
|
||||
(communityType && +b.post.stickied - +a.post.stickied) ||
|
||||
b.counts.score - a.counts.score
|
||||
);
|
||||
} else if (sort == SortType.New) {
|
||||
posts.sort(
|
||||
(a, b) =>
|
||||
+a.removed - +b.removed ||
|
||||
+a.deleted - +b.deleted ||
|
||||
(communityType && +b.stickied - +a.stickied) ||
|
||||
b.published.localeCompare(a.published)
|
||||
+a.post.removed - +b.post.removed ||
|
||||
+a.post.deleted - +b.post.deleted ||
|
||||
(communityType && +b.post.stickied - +a.post.stickied) ||
|
||||
b.post.published.localeCompare(a.post.published)
|
||||
);
|
||||
} else if (sort == SortType.Hot) {
|
||||
posts.sort(
|
||||
(a, b) =>
|
||||
+a.removed - +b.removed ||
|
||||
+a.deleted - +b.deleted ||
|
||||
(communityType && +b.stickied - +a.stickied) ||
|
||||
b.hot_rank - a.hot_rank
|
||||
+a.post.removed - +b.post.removed ||
|
||||
+a.post.deleted - +b.post.deleted ||
|
||||
(communityType && +b.post.stickied - +a.post.stickied) ||
|
||||
hotRankPost(b) - hotRankPost(a)
|
||||
);
|
||||
} else if (sort == SortType.Active) {
|
||||
posts.sort(
|
||||
(a, b) =>
|
||||
+a.removed - +b.removed ||
|
||||
+a.deleted - +b.deleted ||
|
||||
(communityType && +b.stickied - +a.stickied) ||
|
||||
b.hot_rank_active - a.hot_rank_active
|
||||
+a.post.removed - +b.post.removed ||
|
||||
+a.post.deleted - +b.post.deleted ||
|
||||
(communityType && +b.post.stickied - +a.post.stickied) ||
|
||||
hotRankActivePost(b) - hotRankActivePost(a)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -1094,12 +1090,6 @@ export function isBrowser() {
|
|||
return typeof window !== 'undefined';
|
||||
}
|
||||
|
||||
export function setAuth(obj: any, auth: string) {
|
||||
if (auth) {
|
||||
obj.auth = auth;
|
||||
}
|
||||
}
|
||||
|
||||
export function setIsoData(context: any): IsoData {
|
||||
let isoData: IsoData = isBrowser()
|
||||
? window.isoData
|
||||
|
|
|
@ -5518,10 +5518,10 @@ lcid@^1.0.0:
|
|||
dependencies:
|
||||
invert-kv "^1.0.0"
|
||||
|
||||
lemmy-js-client@^1.0.16:
|
||||
version "1.0.16"
|
||||
resolved "https://registry.yarnpkg.com/lemmy-js-client/-/lemmy-js-client-1.0.16.tgz#84bf094c246d987f2f192bfac75340430821fee9"
|
||||
integrity sha512-WvEEGrYNA2dzfzlufWB9LhUcll0O06WaUjSfBn5lYY/SFFsvBW5ImD42P/QwvN8Sgj6xVQiboe+Z8T++iAjKVw==
|
||||
lemmy-js-client@1.0.17-beta5:
|
||||
version "1.0.17-beta5"
|
||||
resolved "https://registry.yarnpkg.com/lemmy-js-client/-/lemmy-js-client-1.0.17-beta5.tgz#b8d128ef3a6a17bc3ac4eea8e30618b68ea4f2df"
|
||||
integrity sha512-Z/8HV8tG9aB75GjDX1U2b3pFZnysGIymeVO+oepOkYfhHRB8SKmLS9ATuIw9OW1NjJduxbpGGgDH+bkf0Sx7dA==
|
||||
|
||||
leven@^3.1.0:
|
||||
version "3.1.0"
|
||||
|
|
Loading…
Reference in a new issue