mirror of
https://github.com/LemmyNet/lemmy-ui.git
synced 2024-12-23 03:11:25 +00:00
Feature/user community block (#362)
* Extracting user settings and profile page. - Auto-collapsing dropdown and navbar on link clicks. - Fixes #180 * Adding User and Community blocking. Fixes #295 - Added a new settings page. - Switched to myUserInfo. - Removing GetFollowedCommunities endpoint * Fixing blocks
This commit is contained in:
parent
2356b0d62f
commit
b27d982a7b
31 changed files with 2217 additions and 1603 deletions
|
@ -69,7 +69,7 @@
|
||||||
"husky": "^7.0.1",
|
"husky": "^7.0.1",
|
||||||
"import-sort-style-module": "^6.0.0",
|
"import-sort-style-module": "^6.0.0",
|
||||||
"iso-639-1": "^2.1.9",
|
"iso-639-1": "^2.1.9",
|
||||||
"lemmy-js-client": "0.11.4-rc.12",
|
"lemmy-js-client": "0.11.4-rc.14",
|
||||||
"lint-staged": "^11.0.1",
|
"lint-staged": "^11.0.1",
|
||||||
"mini-css-extract-plugin": "^2.1.0",
|
"mini-css-extract-plugin": "^2.1.0",
|
||||||
"node-fetch": "^2.6.1",
|
"node-fetch": "^2.6.1",
|
||||||
|
|
|
@ -152,7 +152,11 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.dropdown-menu {
|
.dropdown-content {
|
||||||
|
position: absolute;
|
||||||
|
background-color: var(--light);
|
||||||
|
min-width: 160px;
|
||||||
|
box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2);
|
||||||
z-index: 2000;
|
z-index: 2000;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,7 @@ export class App extends Component<AppProps, any> {
|
||||||
<>
|
<>
|
||||||
<Provider i18next={i18n}>
|
<Provider i18next={i18n}>
|
||||||
<div>
|
<div>
|
||||||
<Theme localUserView={siteRes.my_user} />
|
<Theme myUserInfo={siteRes.my_user} />
|
||||||
{siteRes &&
|
{siteRes &&
|
||||||
siteRes.site_view &&
|
siteRes.site_view &&
|
||||||
this.props.siteRes.site_view.site.icon && (
|
this.props.siteRes.site_view.site.icon && (
|
||||||
|
|
|
@ -50,6 +50,7 @@ interface NavbarState {
|
||||||
unreadCount: number;
|
unreadCount: number;
|
||||||
searchParam: string;
|
searchParam: string;
|
||||||
toggleSearch: boolean;
|
toggleSearch: boolean;
|
||||||
|
showDropdown: boolean;
|
||||||
onSiteBanner?(url: string): any;
|
onSiteBanner?(url: string): any;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,6 +68,7 @@ export class Navbar extends Component<NavbarProps, NavbarState> {
|
||||||
expanded: false,
|
expanded: false,
|
||||||
searchParam: "",
|
searchParam: "",
|
||||||
toggleSearch: false,
|
toggleSearch: false,
|
||||||
|
showDropdown: false,
|
||||||
};
|
};
|
||||||
subscription: any;
|
subscription: any;
|
||||||
|
|
||||||
|
@ -122,15 +124,17 @@ export class Navbar extends Component<NavbarProps, NavbarState> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
handleSearchParam(i: Navbar, event: any) {
|
componentWillUnmount() {
|
||||||
i.state.searchParam = event.target.value;
|
this.wsSub.unsubscribe();
|
||||||
i.setState(i.state);
|
this.userSub.unsubscribe();
|
||||||
|
this.unreadCountSub.unsubscribe();
|
||||||
}
|
}
|
||||||
|
|
||||||
updateUrl() {
|
updateUrl() {
|
||||||
const searchParam = this.state.searchParam;
|
const searchParam = this.state.searchParam;
|
||||||
this.setState({ searchParam: "" });
|
this.setState({ searchParam: "" });
|
||||||
this.setState({ toggleSearch: false });
|
this.setState({ toggleSearch: false });
|
||||||
|
this.setState({ showDropdown: false, expanded: false });
|
||||||
if (searchParam === "") {
|
if (searchParam === "") {
|
||||||
this.context.router.history.push(`/search/`);
|
this.context.router.history.push(`/search/`);
|
||||||
} else {
|
} else {
|
||||||
|
@ -141,54 +145,26 @@ export class Navbar extends Component<NavbarProps, NavbarState> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
handleSearchSubmit(i: Navbar, event: any) {
|
|
||||||
event.preventDefault();
|
|
||||||
i.updateUrl();
|
|
||||||
}
|
|
||||||
|
|
||||||
handleSearchBtn(i: Navbar, event: any) {
|
|
||||||
event.preventDefault();
|
|
||||||
i.setState({ toggleSearch: true });
|
|
||||||
|
|
||||||
i.searchTextField.current.focus();
|
|
||||||
const offsetWidth = i.searchTextField.current.offsetWidth;
|
|
||||||
if (i.state.searchParam && offsetWidth > 100) {
|
|
||||||
i.updateUrl();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
handleSearchBlur(i: Navbar, event: any) {
|
|
||||||
if (!(event.relatedTarget && event.relatedTarget.name !== "search-btn")) {
|
|
||||||
i.state.toggleSearch = false;
|
|
||||||
i.setState(i.state);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return this.navbar();
|
return this.navbar();
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillUnmount() {
|
|
||||||
this.wsSub.unsubscribe();
|
|
||||||
this.userSub.unsubscribe();
|
|
||||||
this.unreadCountSub.unsubscribe();
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO class active corresponding to current page
|
// TODO class active corresponding to current page
|
||||||
navbar() {
|
navbar() {
|
||||||
let localUserView =
|
let myUserInfo =
|
||||||
UserService.Instance.localUserView || this.props.site_res.my_user;
|
UserService.Instance.myUserInfo || this.props.site_res.my_user;
|
||||||
|
let person = myUserInfo?.local_user_view.person;
|
||||||
return (
|
return (
|
||||||
<nav class="navbar navbar-expand-lg navbar-light shadow-sm p-0 px-3">
|
<nav class="navbar navbar-expand-lg navbar-light shadow-sm p-0 px-3">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
{this.props.site_res.site_view && (
|
{this.props.site_res.site_view && (
|
||||||
<Link
|
<button
|
||||||
title={
|
title={
|
||||||
this.props.site_res.site_view.site.description ||
|
this.props.site_res.site_view.site.description ||
|
||||||
this.props.site_res.site_view.site.name
|
this.props.site_res.site_view.site.name
|
||||||
}
|
}
|
||||||
className="d-flex align-items-center navbar-brand mr-md-3"
|
className="d-flex align-items-center navbar-brand mr-md-3 btn btn-link"
|
||||||
to="/"
|
onClick={linkEvent(this, this.handleGotoHome)}
|
||||||
>
|
>
|
||||||
{this.props.site_res.site_view.site.icon && showAvatars() && (
|
{this.props.site_res.site_view.site.icon && showAvatars() && (
|
||||||
<PictrsImage
|
<PictrsImage
|
||||||
|
@ -197,12 +173,12 @@ export class Navbar extends Component<NavbarProps, NavbarState> {
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{this.props.site_res.site_view.site.name}
|
{this.props.site_res.site_view.site.name}
|
||||||
</Link>
|
</button>
|
||||||
)}
|
)}
|
||||||
{this.state.isLoggedIn && (
|
{this.state.isLoggedIn && (
|
||||||
<Link
|
<button
|
||||||
className="ml-auto p-1 navbar-toggler nav-link border-0"
|
className="ml-auto p-1 navbar-toggler nav-link border-0 btn btn-link"
|
||||||
to="/inbox"
|
onClick={linkEvent(this, this.handleGotoInbox)}
|
||||||
title={i18n.t("inbox")}
|
title={i18n.t("inbox")}
|
||||||
>
|
>
|
||||||
<Icon icon="bell" />
|
<Icon icon="bell" />
|
||||||
|
@ -216,7 +192,7 @@ export class Navbar extends Component<NavbarProps, NavbarState> {
|
||||||
{this.state.unreadCount}
|
{this.state.unreadCount}
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
</Link>
|
</button>
|
||||||
)}
|
)}
|
||||||
<button
|
<button
|
||||||
class="navbar-toggler border-0 p-1"
|
class="navbar-toggler border-0 p-1"
|
||||||
|
@ -232,35 +208,32 @@ export class Navbar extends Component<NavbarProps, NavbarState> {
|
||||||
>
|
>
|
||||||
<ul class="navbar-nav my-2 mr-auto">
|
<ul class="navbar-nav my-2 mr-auto">
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<Link
|
<button
|
||||||
className="nav-link"
|
className="nav-link btn btn-link"
|
||||||
to="/communities"
|
onClick={linkEvent(this, this.handleGotoCommunities)}
|
||||||
title={i18n.t("communities")}
|
title={i18n.t("communities")}
|
||||||
>
|
>
|
||||||
{i18n.t("communities")}
|
{i18n.t("communities")}
|
||||||
</Link>
|
</button>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<Link
|
<button
|
||||||
className="nav-link"
|
className="nav-link btn btn-link"
|
||||||
to={{
|
onClick={linkEvent(this, this.handleGotoCreatePost)}
|
||||||
pathname: "/create_post",
|
|
||||||
state: { prevPath: this.currentLocation },
|
|
||||||
}}
|
|
||||||
title={i18n.t("create_post")}
|
title={i18n.t("create_post")}
|
||||||
>
|
>
|
||||||
{i18n.t("create_post")}
|
{i18n.t("create_post")}
|
||||||
</Link>
|
</button>
|
||||||
</li>
|
</li>
|
||||||
{this.canCreateCommunity && (
|
{this.canCreateCommunity && (
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<Link
|
<button
|
||||||
className="nav-link"
|
className="nav-link btn btn-link"
|
||||||
to="/create_community"
|
onClick={linkEvent(this, this.handleGotoCreateCommunity)}
|
||||||
title={i18n.t("create_community")}
|
title={i18n.t("create_community")}
|
||||||
>
|
>
|
||||||
{i18n.t("create_community")}
|
{i18n.t("create_community")}
|
||||||
</Link>
|
</button>
|
||||||
</li>
|
</li>
|
||||||
)}
|
)}
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
|
@ -276,13 +249,13 @@ export class Navbar extends Component<NavbarProps, NavbarState> {
|
||||||
<ul class="navbar-nav my-2">
|
<ul class="navbar-nav my-2">
|
||||||
{this.canAdmin && (
|
{this.canAdmin && (
|
||||||
<li className="nav-item">
|
<li className="nav-item">
|
||||||
<Link
|
<button
|
||||||
className="nav-link"
|
className="nav-link btn btn-link"
|
||||||
to={`/admin`}
|
onClick={linkEvent(this, this.handleGotoAdmin)}
|
||||||
title={i18n.t("admin_settings")}
|
title={i18n.t("admin_settings")}
|
||||||
>
|
>
|
||||||
<Icon icon="settings" />
|
<Icon icon="settings" />
|
||||||
</Link>
|
</button>
|
||||||
</li>
|
</li>
|
||||||
)}
|
)}
|
||||||
</ul>
|
</ul>
|
||||||
|
@ -343,34 +316,73 @@ export class Navbar extends Component<NavbarProps, NavbarState> {
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<ul class="navbar-nav">
|
<ul class="navbar-nav">
|
||||||
<li className="nav-item">
|
<li class="nav-item dropdown">
|
||||||
<Link
|
<button
|
||||||
className="nav-link"
|
class="nav-link btn btn-link dropdown-toggle"
|
||||||
to={`/u/${localUserView.person.name}`}
|
onClick={linkEvent(this, this.handleShowDropdown)}
|
||||||
title={i18n.t("settings")}
|
id="navbarDropdown"
|
||||||
|
role="button"
|
||||||
|
aria-expanded="false"
|
||||||
>
|
>
|
||||||
<span>
|
<span>
|
||||||
{localUserView.person.avatar && showAvatars() && (
|
{person.avatar && showAvatars() && (
|
||||||
<PictrsImage src={localUserView.person.avatar} icon />
|
<PictrsImage src={person.avatar} icon />
|
||||||
)}
|
)}
|
||||||
{localUserView.person.display_name
|
{person.display_name
|
||||||
? localUserView.person.display_name
|
? person.display_name
|
||||||
: localUserView.person.name}
|
: person.name}
|
||||||
</span>
|
</span>
|
||||||
</Link>
|
</button>
|
||||||
|
{this.state.showDropdown && (
|
||||||
|
<div class="dropdown-content">
|
||||||
|
<li className="nav-item">
|
||||||
|
<button
|
||||||
|
className="nav-link btn btn-link"
|
||||||
|
onClick={linkEvent(this, this.handleGotoProfile)}
|
||||||
|
title={i18n.t("profile")}
|
||||||
|
>
|
||||||
|
<Icon icon="user" classes="mr-1" />
|
||||||
|
{i18n.t("profile")}
|
||||||
|
</button>
|
||||||
|
</li>
|
||||||
|
<li className="nav-item">
|
||||||
|
<button
|
||||||
|
className="nav-link btn btn-link"
|
||||||
|
onClick={linkEvent(this, this.handleGotoSettings)}
|
||||||
|
title={i18n.t("settings")}
|
||||||
|
>
|
||||||
|
<Icon icon="settings" classes="mr-1" />
|
||||||
|
{i18n.t("settings")}
|
||||||
|
</button>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<hr class="dropdown-divider" />
|
||||||
|
</li>
|
||||||
|
<li className="nav-item">
|
||||||
|
<button
|
||||||
|
className="nav-link btn btn-link"
|
||||||
|
onClick={linkEvent(this, this.handleLogoutClick)}
|
||||||
|
title="test"
|
||||||
|
>
|
||||||
|
<Icon icon="log-out" classes="mr-1" />
|
||||||
|
{i18n.t("logout")}
|
||||||
|
</button>
|
||||||
|
</li>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<ul class="navbar-nav my-2">
|
<ul class="navbar-nav my-2">
|
||||||
<li className="ml-2 nav-item">
|
<li className="ml-2 nav-item">
|
||||||
<Link
|
<button
|
||||||
className="btn btn-success"
|
className="btn btn-success"
|
||||||
to="/login"
|
onClick={linkEvent(this, this.handleGotoLogin)}
|
||||||
title={i18n.t("login_sign_up")}
|
title={i18n.t("login_sign_up")}
|
||||||
>
|
>
|
||||||
{i18n.t("login_sign_up")}
|
{i18n.t("login_sign_up")}
|
||||||
</Link>
|
</button>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
)}
|
)}
|
||||||
|
@ -385,6 +397,95 @@ export class Navbar extends Component<NavbarProps, NavbarState> {
|
||||||
i.setState(i.state);
|
i.setState(i.state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
handleSearchParam(i: Navbar, event: any) {
|
||||||
|
i.state.searchParam = event.target.value;
|
||||||
|
i.setState(i.state);
|
||||||
|
}
|
||||||
|
|
||||||
|
handleSearchSubmit(i: Navbar, event: any) {
|
||||||
|
event.preventDefault();
|
||||||
|
i.updateUrl();
|
||||||
|
}
|
||||||
|
|
||||||
|
handleSearchBtn(i: Navbar, event: any) {
|
||||||
|
event.preventDefault();
|
||||||
|
i.setState({ toggleSearch: true });
|
||||||
|
|
||||||
|
i.searchTextField.current.focus();
|
||||||
|
const offsetWidth = i.searchTextField.current.offsetWidth;
|
||||||
|
if (i.state.searchParam && offsetWidth > 100) {
|
||||||
|
i.updateUrl();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
handleSearchBlur(i: Navbar, event: any) {
|
||||||
|
if (!(event.relatedTarget && event.relatedTarget.name !== "search-btn")) {
|
||||||
|
i.state.toggleSearch = false;
|
||||||
|
i.setState(i.state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
handleLogoutClick(i: Navbar) {
|
||||||
|
i.setState({ showDropdown: false, expanded: false });
|
||||||
|
UserService.Instance.logout();
|
||||||
|
i.context.router.history.push("/");
|
||||||
|
location.reload();
|
||||||
|
}
|
||||||
|
|
||||||
|
handleGotoSettings(i: Navbar) {
|
||||||
|
i.setState({ showDropdown: false, expanded: false });
|
||||||
|
i.context.router.history.push("/settings");
|
||||||
|
}
|
||||||
|
|
||||||
|
handleGotoProfile(i: Navbar) {
|
||||||
|
i.setState({ showDropdown: false, expanded: false });
|
||||||
|
i.context.router.history.push(
|
||||||
|
`/u/${UserService.Instance.myUserInfo.local_user_view.person.name}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
handleGotoCreatePost(i: Navbar) {
|
||||||
|
i.setState({ showDropdown: false, expanded: false });
|
||||||
|
i.context.router.history.push("/create_post", {
|
||||||
|
prevPath: i.currentLocation,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
handleGotoCreateCommunity(i: Navbar) {
|
||||||
|
i.setState({ showDropdown: false, expanded: false });
|
||||||
|
i.context.router.history.push(`/create_community`);
|
||||||
|
}
|
||||||
|
|
||||||
|
handleGotoCommunities(i: Navbar) {
|
||||||
|
i.setState({ showDropdown: false, expanded: false });
|
||||||
|
i.context.router.history.push(`/communities`);
|
||||||
|
}
|
||||||
|
|
||||||
|
handleGotoHome(i: Navbar) {
|
||||||
|
i.setState({ showDropdown: false, expanded: false });
|
||||||
|
i.context.router.history.push(`/`);
|
||||||
|
}
|
||||||
|
|
||||||
|
handleGotoInbox(i: Navbar) {
|
||||||
|
i.setState({ showDropdown: false, expanded: false });
|
||||||
|
i.context.router.history.push(`/inbox`);
|
||||||
|
}
|
||||||
|
|
||||||
|
handleGotoAdmin(i: Navbar) {
|
||||||
|
i.setState({ showDropdown: false, expanded: false });
|
||||||
|
i.context.router.history.push(`/admin`);
|
||||||
|
}
|
||||||
|
|
||||||
|
handleGotoLogin(i: Navbar) {
|
||||||
|
i.setState({ showDropdown: false, expanded: false });
|
||||||
|
i.context.router.history.push(`/login`);
|
||||||
|
}
|
||||||
|
|
||||||
|
handleShowDropdown(i: Navbar) {
|
||||||
|
i.state.showDropdown = !i.state.showDropdown;
|
||||||
|
i.setState(i.state);
|
||||||
|
}
|
||||||
|
|
||||||
parseMessage(msg: any) {
|
parseMessage(msg: any) {
|
||||||
let op = wsUserOp(msg);
|
let op = wsUserOp(msg);
|
||||||
console.log(msg);
|
console.log(msg);
|
||||||
|
@ -432,8 +533,10 @@ export class Navbar extends Component<NavbarProps, NavbarState> {
|
||||||
// This is only called on a successful login
|
// This is only called on a successful login
|
||||||
let data = wsJsonToRes<GetSiteResponse>(msg).data;
|
let data = wsJsonToRes<GetSiteResponse>(msg).data;
|
||||||
console.log(data.my_user);
|
console.log(data.my_user);
|
||||||
UserService.Instance.localUserView = data.my_user;
|
UserService.Instance.myUserInfo = data.my_user;
|
||||||
setTheme(UserService.Instance.localUserView.local_user.theme);
|
setTheme(
|
||||||
|
UserService.Instance.myUserInfo.local_user_view.local_user.theme
|
||||||
|
);
|
||||||
i18n.changeLanguage(getLanguage());
|
i18n.changeLanguage(getLanguage());
|
||||||
this.state.isLoggedIn = true;
|
this.state.isLoggedIn = true;
|
||||||
this.setState(this.state);
|
this.setState(this.state);
|
||||||
|
@ -443,7 +546,7 @@ export class Navbar extends Component<NavbarProps, NavbarState> {
|
||||||
if (this.state.isLoggedIn) {
|
if (this.state.isLoggedIn) {
|
||||||
if (
|
if (
|
||||||
data.recipient_ids.includes(
|
data.recipient_ids.includes(
|
||||||
UserService.Instance.localUserView.local_user.id
|
UserService.Instance.myUserInfo.local_user_view.local_user.id
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
this.state.replies.push(data.comment_view);
|
this.state.replies.push(data.comment_view);
|
||||||
|
@ -459,7 +562,7 @@ export class Navbar extends Component<NavbarProps, NavbarState> {
|
||||||
if (this.state.isLoggedIn) {
|
if (this.state.isLoggedIn) {
|
||||||
if (
|
if (
|
||||||
data.private_message_view.recipient.id ==
|
data.private_message_view.recipient.id ==
|
||||||
UserService.Instance.localUserView.person.id
|
UserService.Instance.myUserInfo.local_user_view.person.id
|
||||||
) {
|
) {
|
||||||
this.state.messages.push(data.private_message_view);
|
this.state.messages.push(data.private_message_view);
|
||||||
this.state.unreadCount++;
|
this.state.unreadCount++;
|
||||||
|
@ -525,10 +628,10 @@ export class Navbar extends Component<NavbarProps, NavbarState> {
|
||||||
|
|
||||||
get canAdmin(): boolean {
|
get canAdmin(): boolean {
|
||||||
return (
|
return (
|
||||||
UserService.Instance.localUserView &&
|
UserService.Instance.myUserInfo &&
|
||||||
this.props.site_res.admins
|
this.props.site_res.admins
|
||||||
.map(a => a.person.id)
|
.map(a => a.person.id)
|
||||||
.includes(UserService.Instance.localUserView.person.id)
|
.includes(UserService.Instance.myUserInfo.local_user_view.person.id)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -547,7 +650,7 @@ export class Navbar extends Component<NavbarProps, NavbarState> {
|
||||||
}
|
}
|
||||||
|
|
||||||
requestNotificationPermission() {
|
requestNotificationPermission() {
|
||||||
if (UserService.Instance.localUserView) {
|
if (UserService.Instance.myUserInfo) {
|
||||||
document.addEventListener("DOMContentLoaded", function () {
|
document.addEventListener("DOMContentLoaded", function () {
|
||||||
if (!Notification) {
|
if (!Notification) {
|
||||||
toast(i18n.t("notifications_error"), "danger");
|
toast(i18n.t("notifications_error"), "danger");
|
||||||
|
|
|
@ -1,15 +1,15 @@
|
||||||
import { Component } from "inferno";
|
import { Component } from "inferno";
|
||||||
import { Helmet } from "inferno-helmet";
|
import { Helmet } from "inferno-helmet";
|
||||||
import { LocalUserSettingsView } from "lemmy-js-client";
|
import { MyUserInfo } from "lemmy-js-client";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
localUserView: LocalUserSettingsView | undefined;
|
myUserInfo: MyUserInfo | undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Theme extends Component<Props> {
|
export class Theme extends Component<Props> {
|
||||||
render() {
|
render() {
|
||||||
let user = this.props.localUserView;
|
let user = this.props.myUserInfo;
|
||||||
let hasTheme = user && user.local_user.theme !== "browser";
|
let hasTheme = user && user.local_user_view.local_user.theme !== "browser";
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Helmet>
|
<Helmet>
|
||||||
|
@ -17,7 +17,7 @@ export class Theme extends Component<Props> {
|
||||||
<link
|
<link
|
||||||
rel="stylesheet"
|
rel="stylesheet"
|
||||||
type="text/css"
|
type="text/css"
|
||||||
href={`/static/assets/css/themes/${user.local_user.theme}.min.css`}
|
href={`/static/assets/css/themes/${user.local_user_view.local_user.theme}.min.css`}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
[
|
[
|
||||||
|
|
|
@ -68,7 +68,7 @@ export class CommentForm extends Component<CommentFormProps, CommentFormState> {
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
{UserService.Instance.localUserView ? (
|
{UserService.Instance.myUserInfo ? (
|
||||||
<MarkdownTextArea
|
<MarkdownTextArea
|
||||||
initialContent={
|
initialContent={
|
||||||
this.props.edit
|
this.props.edit
|
||||||
|
@ -135,7 +135,7 @@ export class CommentForm extends Component<CommentFormProps, CommentFormState> {
|
||||||
console.log(msg);
|
console.log(msg);
|
||||||
|
|
||||||
// Only do the showing and hiding if logged in
|
// Only do the showing and hiding if logged in
|
||||||
if (UserService.Instance.localUserView) {
|
if (UserService.Instance.myUserInfo) {
|
||||||
if (
|
if (
|
||||||
op == UserOperation.CreateComment ||
|
op == UserOperation.CreateComment ||
|
||||||
op == UserOperation.EditComment
|
op == UserOperation.EditComment
|
||||||
|
|
|
@ -5,6 +5,7 @@ import {
|
||||||
AddModToCommunity,
|
AddModToCommunity,
|
||||||
BanFromCommunity,
|
BanFromCommunity,
|
||||||
BanPerson,
|
BanPerson,
|
||||||
|
BlockPerson,
|
||||||
CommentView,
|
CommentView,
|
||||||
CommunityModeratorView,
|
CommunityModeratorView,
|
||||||
CreateCommentLike,
|
CreateCommentLike,
|
||||||
|
@ -279,7 +280,7 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
|
||||||
)}
|
)}
|
||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
{UserService.Instance.localUserView && !this.props.viewOnly && (
|
{UserService.Instance.myUserInfo && !this.props.viewOnly && (
|
||||||
<>
|
<>
|
||||||
<button
|
<button
|
||||||
className={`btn btn-link btn-animate ${
|
className={`btn btn-link btn-animate ${
|
||||||
|
@ -333,15 +334,28 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
{!this.myComment && (
|
{!this.myComment && (
|
||||||
<button class="btn btn-link btn-animate">
|
<>
|
||||||
<Link
|
<button class="btn btn-link btn-animate">
|
||||||
className="text-muted"
|
<Link
|
||||||
to={`/create_private_message/recipient/${cv.creator.id}`}
|
className="text-muted"
|
||||||
title={i18n.t("message").toLowerCase()}
|
to={`/create_private_message/recipient/${cv.creator.id}`}
|
||||||
|
title={i18n.t("message").toLowerCase()}
|
||||||
|
>
|
||||||
|
<Icon icon="mail" />
|
||||||
|
</Link>
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
class="btn btn-link btn-animate text-muted"
|
||||||
|
onClick={linkEvent(
|
||||||
|
this,
|
||||||
|
this.handleBlockUserClick
|
||||||
|
)}
|
||||||
|
data-tippy-content={i18n.t("block_user")}
|
||||||
|
aria-label={i18n.t("block_user")}
|
||||||
>
|
>
|
||||||
<Icon icon="mail" />
|
<Icon icon="slash" />
|
||||||
</Link>
|
</button>
|
||||||
</button>
|
</>
|
||||||
)}
|
)}
|
||||||
<button
|
<button
|
||||||
class="btn btn-link btn-animate text-muted"
|
class="btn btn-link btn-animate text-muted"
|
||||||
|
@ -829,7 +843,7 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
|
||||||
get myComment(): boolean {
|
get myComment(): boolean {
|
||||||
return (
|
return (
|
||||||
this.props.node.comment_view.creator.id ==
|
this.props.node.comment_view.creator.id ==
|
||||||
UserService.Instance.localUserView?.person.id
|
UserService.Instance.myUserInfo?.local_user_view.person.id
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -864,7 +878,7 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
|
||||||
.concat(this.props.moderators.map(m => m.moderator.id));
|
.concat(this.props.moderators.map(m => m.moderator.id));
|
||||||
|
|
||||||
return canMod(
|
return canMod(
|
||||||
UserService.Instance.localUserView,
|
UserService.Instance.myUserInfo,
|
||||||
adminsThenMods,
|
adminsThenMods,
|
||||||
this.props.node.comment_view.creator.id
|
this.props.node.comment_view.creator.id
|
||||||
);
|
);
|
||||||
|
@ -877,7 +891,7 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
|
||||||
return (
|
return (
|
||||||
this.props.admins &&
|
this.props.admins &&
|
||||||
canMod(
|
canMod(
|
||||||
UserService.Instance.localUserView,
|
UserService.Instance.myUserInfo,
|
||||||
this.props.admins.map(a => a.person.id),
|
this.props.admins.map(a => a.person.id),
|
||||||
this.props.node.comment_view.creator.id
|
this.props.node.comment_view.creator.id
|
||||||
)
|
)
|
||||||
|
@ -887,10 +901,10 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
|
||||||
get amCommunityCreator(): boolean {
|
get amCommunityCreator(): boolean {
|
||||||
return (
|
return (
|
||||||
this.props.moderators &&
|
this.props.moderators &&
|
||||||
UserService.Instance.localUserView &&
|
UserService.Instance.myUserInfo &&
|
||||||
this.props.node.comment_view.creator.id !=
|
this.props.node.comment_view.creator.id !=
|
||||||
UserService.Instance.localUserView.person.id &&
|
UserService.Instance.myUserInfo.local_user_view.person.id &&
|
||||||
UserService.Instance.localUserView.person.id ==
|
UserService.Instance.myUserInfo.local_user_view.person.id ==
|
||||||
this.props.moderators[0].moderator.id
|
this.props.moderators[0].moderator.id
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -898,10 +912,10 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
|
||||||
get amSiteCreator(): boolean {
|
get amSiteCreator(): boolean {
|
||||||
return (
|
return (
|
||||||
this.props.admins &&
|
this.props.admins &&
|
||||||
UserService.Instance.localUserView &&
|
UserService.Instance.myUserInfo &&
|
||||||
this.props.node.comment_view.creator.id !=
|
this.props.node.comment_view.creator.id !=
|
||||||
UserService.Instance.localUserView.person.id &&
|
UserService.Instance.myUserInfo.local_user_view.person.id &&
|
||||||
UserService.Instance.localUserView.person.id ==
|
UserService.Instance.myUserInfo.local_user_view.person.id ==
|
||||||
this.props.admins[0].person.id
|
this.props.admins[0].person.id
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -925,6 +939,15 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
|
||||||
i.setState(i.state);
|
i.setState(i.state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
handleBlockUserClick(i: CommentNode) {
|
||||||
|
let blockUserForm: BlockPerson = {
|
||||||
|
person_id: i.props.node.comment_view.creator.id,
|
||||||
|
block: true,
|
||||||
|
auth: authField(),
|
||||||
|
};
|
||||||
|
WebSocketService.Instance.send(wsClient.blockPerson(blockUserForm));
|
||||||
|
}
|
||||||
|
|
||||||
handleDeleteClick(i: CommentNode) {
|
handleDeleteClick(i: CommentNode) {
|
||||||
let comment = i.props.node.comment_view.comment;
|
let comment = i.props.node.comment_view.comment;
|
||||||
let deleteForm: DeleteComment = {
|
let deleteForm: DeleteComment = {
|
||||||
|
|
|
@ -65,7 +65,7 @@ export class ImageUploadForm extends Component<
|
||||||
accept="image/*,video/*"
|
accept="image/*,video/*"
|
||||||
name={this.id}
|
name={this.id}
|
||||||
class="d-none"
|
class="d-none"
|
||||||
disabled={!UserService.Instance.localUserView}
|
disabled={!UserService.Instance.myUserInfo}
|
||||||
onChange={linkEvent(this, this.handleImageUpload)}
|
onChange={linkEvent(this, this.handleImageUpload)}
|
||||||
/>
|
/>
|
||||||
</form>
|
</form>
|
||||||
|
|
|
@ -44,7 +44,7 @@ export class ListingTypeSelect extends Component<
|
||||||
className={`btn btn-outline-secondary
|
className={`btn btn-outline-secondary
|
||||||
${this.state.type_ == ListingType.Subscribed && "active"}
|
${this.state.type_ == ListingType.Subscribed && "active"}
|
||||||
${
|
${
|
||||||
UserService.Instance.localUserView == undefined
|
UserService.Instance.myUserInfo == undefined
|
||||||
? "disabled"
|
? "disabled"
|
||||||
: "pointer"
|
: "pointer"
|
||||||
}
|
}
|
||||||
|
@ -56,7 +56,7 @@ export class ListingTypeSelect extends Component<
|
||||||
value={ListingType.Subscribed}
|
value={ListingType.Subscribed}
|
||||||
checked={this.state.type_ == ListingType.Subscribed}
|
checked={this.state.type_ == ListingType.Subscribed}
|
||||||
onChange={linkEvent(this, this.handleTypeChange)}
|
onChange={linkEvent(this, this.handleTypeChange)}
|
||||||
disabled={UserService.Instance.localUserView == undefined}
|
disabled={UserService.Instance.myUserInfo == undefined}
|
||||||
/>
|
/>
|
||||||
{i18n.t("subscribed")}
|
{i18n.t("subscribed")}
|
||||||
</label>
|
</label>
|
||||||
|
|
|
@ -209,7 +209,7 @@ export class MarkdownTextArea extends Component<
|
||||||
<label
|
<label
|
||||||
htmlFor={`file-upload-${this.id}`}
|
htmlFor={`file-upload-${this.id}`}
|
||||||
className={`mb-0 ${
|
className={`mb-0 ${
|
||||||
UserService.Instance.localUserView && "pointer"
|
UserService.Instance.myUserInfo && "pointer"
|
||||||
}`}
|
}`}
|
||||||
data-tippy-content={i18n.t("upload_image")}
|
data-tippy-content={i18n.t("upload_image")}
|
||||||
>
|
>
|
||||||
|
@ -225,7 +225,7 @@ export class MarkdownTextArea extends Component<
|
||||||
accept="image/*,video/*"
|
accept="image/*,video/*"
|
||||||
name="file"
|
name="file"
|
||||||
class="d-none"
|
class="d-none"
|
||||||
disabled={!UserService.Instance.localUserView}
|
disabled={!UserService.Instance.myUserInfo}
|
||||||
onChange={linkEvent(this, this.handleImageUpload)}
|
onChange={linkEvent(this, this.handleImageUpload)}
|
||||||
/>
|
/>
|
||||||
</form>
|
</form>
|
||||||
|
|
|
@ -12,6 +12,15 @@ export const SYMBOLS = (
|
||||||
xmlnsXlink="http://www.w3.org/1999/xlink"
|
xmlnsXlink="http://www.w3.org/1999/xlink"
|
||||||
>
|
>
|
||||||
<defs>
|
<defs>
|
||||||
|
<symbol id="icon-log-out" viewBox="0 0 24 24">
|
||||||
|
<path d="M9 20h-4c-0.276 0-0.525-0.111-0.707-0.293s-0.293-0.431-0.293-0.707v-14c0-0.276 0.111-0.525 0.293-0.707s0.431-0.293 0.707-0.293h4c0.552 0 1-0.448 1-1s-0.448-1-1-1h-4c-0.828 0-1.58 0.337-2.121 0.879s-0.879 1.293-0.879 2.121v14c0 0.828 0.337 1.58 0.879 2.121s1.293 0.879 2.121 0.879h4c0.552 0 1-0.448 1-1s-0.448-1-1-1zM18.586 11h-9.586c-0.552 0-1 0.448-1 1s0.448 1 1 1h9.586l-3.293 3.293c-0.391 0.391-0.391 1.024 0 1.414s1.024 0.391 1.414 0l5-5c0.092-0.092 0.166-0.202 0.217-0.324 0.15-0.362 0.078-0.795-0.217-1.090l-5-5c-0.391-0.391-1.024-0.391-1.414 0s-0.391 1.024 0 1.414z"></path>
|
||||||
|
</symbol>
|
||||||
|
<symbol id="icon-user" viewBox="0 0 24 24">
|
||||||
|
<path d="M21 21v-2c0-1.38-0.561-2.632-1.464-3.536s-2.156-1.464-3.536-1.464h-8c-1.38 0-2.632 0.561-3.536 1.464s-1.464 2.156-1.464 3.536v2c0 0.552 0.448 1 1 1s1-0.448 1-1v-2c0-0.829 0.335-1.577 0.879-2.121s1.292-0.879 2.121-0.879h8c0.829 0 1.577 0.335 2.121 0.879s0.879 1.292 0.879 2.121v2c0 0.552 0.448 1 1 1s1-0.448 1-1zM17 7c0-1.38-0.561-2.632-1.464-3.536s-2.156-1.464-3.536-1.464-2.632 0.561-3.536 1.464-1.464 2.156-1.464 3.536 0.561 2.632 1.464 3.536 2.156 1.464 3.536 1.464 2.632-0.561 3.536-1.464 1.464-2.156 1.464-3.536zM15 7c0 0.829-0.335 1.577-0.879 2.121s-1.292 0.879-2.121 0.879-1.577-0.335-2.121-0.879-0.879-1.292-0.879-2.121 0.335-1.577 0.879-2.121 1.292-0.879 2.121-0.879 1.577 0.335 2.121 0.879 0.879 1.292 0.879 2.121z"></path>
|
||||||
|
</symbol>
|
||||||
|
<symbol id="icon-slash" viewBox="0 0 24 24">
|
||||||
|
<path d="M23 12c0-3.037-1.232-5.789-3.222-7.778s-4.741-3.222-7.778-3.222-5.789 1.232-7.778 3.222-3.222 4.741-3.222 7.778 1.232 5.789 3.222 7.778 4.741 3.222 7.778 3.222 5.789-1.232 7.778-3.222 3.222-4.741 3.222-7.778zM19.032 17.618l-12.65-12.65c1.54-1.232 3.493-1.968 5.618-1.968 2.486 0 4.734 1.006 6.364 2.636s2.636 3.878 2.636 6.364c0 2.125-0.736 4.078-1.968 5.618zM4.968 6.382l12.65 12.65c-1.54 1.232-3.493 1.968-5.618 1.968-2.486 0-4.734-1.006-6.364-2.636s-2.636-3.878-2.636-6.364c0-2.125 0.736-4.078 1.968-5.618z"></path>
|
||||||
|
</symbol>
|
||||||
<symbol id="icon-menu" viewBox="0 0 24 24">
|
<symbol id="icon-menu" viewBox="0 0 24 24">
|
||||||
<path d="M3 13h18c0.552 0 1-0.448 1-1s-0.448-1-1-1h-18c-0.552 0-1 0.448-1 1s0.448 1 1 1zM3 7h18c0.552 0 1-0.448 1-1s-0.448-1-1-1h-18c-0.552 0-1 0.448-1 1s0.448 1 1 1zM3 19h18c0.552 0 1-0.448 1-1s-0.448-1-1-1h-18c-0.552 0-1 0.448-1 1s0.448 1 1 1z"></path>
|
<path d="M3 13h18c0.552 0 1-0.448 1-1s-0.448-1-1-1h-18c-0.552 0-1 0.448-1 1s0.448 1 1 1zM3 7h18c0.552 0 1-0.448 1-1s-0.448-1-1-1h-18c-0.552 0-1 0.448-1 1s0.448 1 1 1zM3 19h18c0.552 0 1-0.448 1-1s-0.448-1-1-1h-18c-0.552 0-1 0.448-1 1s0.448 1 1 1z"></path>
|
||||||
</symbol>
|
</symbol>
|
||||||
|
|
|
@ -9,7 +9,7 @@ import {
|
||||||
} from "lemmy-js-client";
|
} from "lemmy-js-client";
|
||||||
import { Subscription } from "rxjs";
|
import { Subscription } from "rxjs";
|
||||||
import { i18n } from "../../i18next";
|
import { i18n } from "../../i18next";
|
||||||
import { WebSocketService } from "../../services";
|
import { UserService, WebSocketService } from "../../services";
|
||||||
import {
|
import {
|
||||||
authField,
|
authField,
|
||||||
capitalizeFirstLetter,
|
capitalizeFirstLetter,
|
||||||
|
@ -321,10 +321,39 @@ export class CommunityForm extends Component<
|
||||||
let data = wsJsonToRes<CommunityResponse>(msg).data;
|
let data = wsJsonToRes<CommunityResponse>(msg).data;
|
||||||
this.state.loading = false;
|
this.state.loading = false;
|
||||||
this.props.onCreate(data.community_view);
|
this.props.onCreate(data.community_view);
|
||||||
|
|
||||||
|
// Update myUserInfo
|
||||||
|
let community = data.community_view.community;
|
||||||
|
let person = UserService.Instance.myUserInfo.local_user_view.person;
|
||||||
|
UserService.Instance.myUserInfo.follows.push({
|
||||||
|
community,
|
||||||
|
follower: person,
|
||||||
|
});
|
||||||
|
UserService.Instance.myUserInfo.moderates.push({
|
||||||
|
community,
|
||||||
|
moderator: person,
|
||||||
|
});
|
||||||
} else if (op == UserOperation.EditCommunity) {
|
} else if (op == UserOperation.EditCommunity) {
|
||||||
let data = wsJsonToRes<CommunityResponse>(msg).data;
|
let data = wsJsonToRes<CommunityResponse>(msg).data;
|
||||||
this.state.loading = false;
|
this.state.loading = false;
|
||||||
this.props.onEdit(data.community_view);
|
this.props.onEdit(data.community_view);
|
||||||
|
let community = data.community_view.community;
|
||||||
|
|
||||||
|
let followFound = UserService.Instance.myUserInfo.follows.findIndex(
|
||||||
|
f => f.community.id == community.id
|
||||||
|
);
|
||||||
|
if (followFound) {
|
||||||
|
UserService.Instance.myUserInfo.follows[followFound].community =
|
||||||
|
community;
|
||||||
|
}
|
||||||
|
|
||||||
|
let moderatesFound = UserService.Instance.myUserInfo.moderates.findIndex(
|
||||||
|
f => f.community.id == community.id
|
||||||
|
);
|
||||||
|
if (moderatesFound) {
|
||||||
|
UserService.Instance.myUserInfo.moderates[moderatesFound].community =
|
||||||
|
community;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ import { Component, linkEvent } from "inferno";
|
||||||
import {
|
import {
|
||||||
AddModToCommunityResponse,
|
AddModToCommunityResponse,
|
||||||
BanFromCommunityResponse,
|
BanFromCommunityResponse,
|
||||||
|
BlockPersonResponse,
|
||||||
CommentResponse,
|
CommentResponse,
|
||||||
CommentView,
|
CommentView,
|
||||||
CommunityResponse,
|
CommunityResponse,
|
||||||
|
@ -42,6 +43,7 @@ import {
|
||||||
setOptionalAuth,
|
setOptionalAuth,
|
||||||
setupTippy,
|
setupTippy,
|
||||||
toast,
|
toast,
|
||||||
|
updatePersonBlock,
|
||||||
wsClient,
|
wsClient,
|
||||||
wsJsonToRes,
|
wsJsonToRes,
|
||||||
wsSubscribe,
|
wsSubscribe,
|
||||||
|
@ -178,9 +180,10 @@ export class Community extends Component<any, State> {
|
||||||
|
|
||||||
let sort: SortType = pathSplit[6]
|
let sort: SortType = pathSplit[6]
|
||||||
? SortType[pathSplit[6]]
|
? SortType[pathSplit[6]]
|
||||||
: UserService.Instance.localUserView
|
: UserService.Instance.myUserInfo
|
||||||
? Object.values(SortType)[
|
? Object.values(SortType)[
|
||||||
UserService.Instance.localUserView.local_user.default_sort_type
|
UserService.Instance.myUserInfo.local_user_view.local_user
|
||||||
|
.default_sort_type
|
||||||
]
|
]
|
||||||
: SortType.Active;
|
: SortType.Active;
|
||||||
|
|
||||||
|
@ -490,7 +493,10 @@ export class Community extends Component<any, State> {
|
||||||
} else if (op == UserOperation.CreatePost) {
|
} else if (op == UserOperation.CreatePost) {
|
||||||
let data = wsJsonToRes<PostResponse>(msg).data;
|
let data = wsJsonToRes<PostResponse>(msg).data;
|
||||||
this.state.posts.unshift(data.post_view);
|
this.state.posts.unshift(data.post_view);
|
||||||
if (UserService.Instance.localUserView?.local_user.show_new_post_notifs) {
|
if (
|
||||||
|
UserService.Instance.myUserInfo?.local_user_view.local_user
|
||||||
|
.show_new_post_notifs
|
||||||
|
) {
|
||||||
notifyPost(data.post_view, this.context.router);
|
notifyPost(data.post_view, this.context.router);
|
||||||
}
|
}
|
||||||
this.setState(this.state);
|
this.setState(this.state);
|
||||||
|
@ -540,6 +546,9 @@ export class Community extends Component<any, State> {
|
||||||
let data = wsJsonToRes<CommentResponse>(msg).data;
|
let data = wsJsonToRes<CommentResponse>(msg).data;
|
||||||
createCommentLikeRes(data.comment_view, this.state.comments);
|
createCommentLikeRes(data.comment_view, this.state.comments);
|
||||||
this.setState(this.state);
|
this.setState(this.state);
|
||||||
|
} else if (op == UserOperation.BlockPerson) {
|
||||||
|
let data = wsJsonToRes<BlockPersonResponse>(msg).data;
|
||||||
|
updatePersonBlock(data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,7 +28,7 @@ export class CreateCommunity extends Component<any, CreateCommunityState> {
|
||||||
this.parseMessage = this.parseMessage.bind(this);
|
this.parseMessage = this.parseMessage.bind(this);
|
||||||
this.subscription = wsSubscribe(this.parseMessage);
|
this.subscription = wsSubscribe(this.parseMessage);
|
||||||
|
|
||||||
if (!UserService.Instance.localUserView && isBrowser()) {
|
if (!UserService.Instance.myUserInfo && isBrowser()) {
|
||||||
toast(i18n.t("not_logged_in"), "danger");
|
toast(i18n.t("not_logged_in"), "danger");
|
||||||
this.context.router.history.push(`/login`);
|
this.context.router.history.push(`/login`);
|
||||||
}
|
}
|
||||||
|
|
|
@ -104,7 +104,7 @@ export class Sidebar extends Component<SidebarProps, SidebarState> {
|
||||||
<a
|
<a
|
||||||
class="btn btn-secondary btn-sm mr-2"
|
class="btn btn-secondary btn-sm mr-2"
|
||||||
href="#"
|
href="#"
|
||||||
onClick={linkEvent(community.id, this.handleUnsubscribe)}
|
onClick={linkEvent(this, this.handleUnsubscribe)}
|
||||||
>
|
>
|
||||||
<Icon icon="check" classes="icon-inline text-success mr-1" />
|
<Icon icon="check" classes="icon-inline text-success mr-1" />
|
||||||
{i18n.t("joined")}
|
{i18n.t("joined")}
|
||||||
|
@ -257,10 +257,7 @@ export class Sidebar extends Component<SidebarProps, SidebarState> {
|
||||||
<a
|
<a
|
||||||
class="btn btn-secondary btn-block"
|
class="btn btn-secondary btn-block"
|
||||||
href="#"
|
href="#"
|
||||||
onClick={linkEvent(
|
onClick={linkEvent(this, this.handleSubscribe)}
|
||||||
community_view.community.id,
|
|
||||||
this.handleSubscribe
|
|
||||||
)}
|
|
||||||
>
|
>
|
||||||
{i18n.t("subscribe")}
|
{i18n.t("subscribe")}
|
||||||
</a>
|
</a>
|
||||||
|
@ -447,7 +444,7 @@ export class Sidebar extends Component<SidebarProps, SidebarState> {
|
||||||
|
|
||||||
handleLeaveModTeamClick(i: Sidebar) {
|
handleLeaveModTeamClick(i: Sidebar) {
|
||||||
let form: AddModToCommunity = {
|
let form: AddModToCommunity = {
|
||||||
person_id: UserService.Instance.localUserView.person.id,
|
person_id: UserService.Instance.myUserInfo.local_user_view.person.id,
|
||||||
community_id: i.props.community_view.community.id,
|
community_id: i.props.community_view.community.id,
|
||||||
added: false,
|
added: false,
|
||||||
auth: authField(),
|
auth: authField(),
|
||||||
|
@ -462,48 +459,62 @@ export class Sidebar extends Component<SidebarProps, SidebarState> {
|
||||||
i.setState(i.state);
|
i.setState(i.state);
|
||||||
}
|
}
|
||||||
|
|
||||||
handleUnsubscribe(communityId: number, event: any) {
|
handleUnsubscribe(i: Sidebar, event: any) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
let community_id = i.props.community_view.community.id;
|
||||||
let form: FollowCommunity = {
|
let form: FollowCommunity = {
|
||||||
community_id: communityId,
|
community_id,
|
||||||
follow: false,
|
follow: false,
|
||||||
auth: authField(),
|
auth: authField(),
|
||||||
};
|
};
|
||||||
WebSocketService.Instance.send(wsClient.followCommunity(form));
|
WebSocketService.Instance.send(wsClient.followCommunity(form));
|
||||||
|
|
||||||
|
// Update myUserInfo
|
||||||
|
UserService.Instance.myUserInfo.follows =
|
||||||
|
UserService.Instance.myUserInfo.follows.filter(
|
||||||
|
i => i.community.id != community_id
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
handleSubscribe(communityId: number, event: any) {
|
handleSubscribe(i: Sidebar, event: any) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
let community_id = i.props.community_view.community.id;
|
||||||
let form: FollowCommunity = {
|
let form: FollowCommunity = {
|
||||||
community_id: communityId,
|
community_id,
|
||||||
follow: true,
|
follow: true,
|
||||||
auth: authField(),
|
auth: authField(),
|
||||||
};
|
};
|
||||||
WebSocketService.Instance.send(wsClient.followCommunity(form));
|
WebSocketService.Instance.send(wsClient.followCommunity(form));
|
||||||
|
|
||||||
|
// Update myUserInfo
|
||||||
|
UserService.Instance.myUserInfo.follows.push({
|
||||||
|
community: i.props.community_view.community,
|
||||||
|
follower: UserService.Instance.myUserInfo.local_user_view.person,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private get amTopMod(): boolean {
|
private get amTopMod(): boolean {
|
||||||
return (
|
return (
|
||||||
this.props.moderators[0].moderator.id ==
|
this.props.moderators[0].moderator.id ==
|
||||||
UserService.Instance.localUserView.person.id
|
UserService.Instance.myUserInfo.local_user_view.person.id
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
get canMod(): boolean {
|
get canMod(): boolean {
|
||||||
return (
|
return (
|
||||||
UserService.Instance.localUserView &&
|
UserService.Instance.myUserInfo &&
|
||||||
this.props.moderators
|
this.props.moderators
|
||||||
.map(m => m.moderator.id)
|
.map(m => m.moderator.id)
|
||||||
.includes(UserService.Instance.localUserView.person.id)
|
.includes(UserService.Instance.myUserInfo.local_user_view.person.id)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
get canAdmin(): boolean {
|
get canAdmin(): boolean {
|
||||||
return (
|
return (
|
||||||
UserService.Instance.localUserView &&
|
UserService.Instance.myUserInfo &&
|
||||||
this.props.admins
|
this.props.admins
|
||||||
.map(a => a.person.id)
|
.map(a => a.person.id)
|
||||||
.includes(UserService.Instance.localUserView.person.id)
|
.includes(UserService.Instance.myUserInfo.local_user_view.person.id)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,13 +4,12 @@ import { Link } from "inferno-router";
|
||||||
import {
|
import {
|
||||||
AddAdminResponse,
|
AddAdminResponse,
|
||||||
BanPersonResponse,
|
BanPersonResponse,
|
||||||
|
BlockPersonResponse,
|
||||||
CommentResponse,
|
CommentResponse,
|
||||||
CommentView,
|
CommentView,
|
||||||
CommunityFollowerView,
|
|
||||||
CommunityView,
|
CommunityView,
|
||||||
GetComments,
|
GetComments,
|
||||||
GetCommentsResponse,
|
GetCommentsResponse,
|
||||||
GetFollowedCommunitiesResponse,
|
|
||||||
GetPosts,
|
GetPosts,
|
||||||
GetPostsResponse,
|
GetPostsResponse,
|
||||||
GetSiteResponse,
|
GetSiteResponse,
|
||||||
|
@ -49,6 +48,7 @@ import {
|
||||||
setupTippy,
|
setupTippy,
|
||||||
showLocal,
|
showLocal,
|
||||||
toast,
|
toast,
|
||||||
|
updatePersonBlock,
|
||||||
wsClient,
|
wsClient,
|
||||||
wsJsonToRes,
|
wsJsonToRes,
|
||||||
wsSubscribe,
|
wsSubscribe,
|
||||||
|
@ -68,7 +68,6 @@ import { PostListings } from "../post/post-listings";
|
||||||
import { SiteForm } from "./site-form";
|
import { SiteForm } from "./site-form";
|
||||||
|
|
||||||
interface HomeState {
|
interface HomeState {
|
||||||
subscribedCommunities: CommunityFollowerView[];
|
|
||||||
trendingCommunities: CommunityView[];
|
trendingCommunities: CommunityView[];
|
||||||
siteRes: GetSiteResponse;
|
siteRes: GetSiteResponse;
|
||||||
showEditSite: boolean;
|
showEditSite: boolean;
|
||||||
|
@ -102,7 +101,6 @@ export class Home extends Component<any, HomeState> {
|
||||||
private isoData = setIsoData(this.context);
|
private isoData = setIsoData(this.context);
|
||||||
private subscription: Subscription;
|
private subscription: Subscription;
|
||||||
private emptyState: HomeState = {
|
private emptyState: HomeState = {
|
||||||
subscribedCommunities: [],
|
|
||||||
trendingCommunities: [],
|
trendingCommunities: [],
|
||||||
siteRes: this.isoData.site_res,
|
siteRes: this.isoData.site_res,
|
||||||
showEditSite: false,
|
showEditSite: false,
|
||||||
|
@ -139,21 +137,10 @@ export class Home extends Component<any, HomeState> {
|
||||||
this.state.comments = this.isoData.routeData[0].comments;
|
this.state.comments = this.isoData.routeData[0].comments;
|
||||||
}
|
}
|
||||||
this.state.trendingCommunities = this.isoData.routeData[1].communities;
|
this.state.trendingCommunities = this.isoData.routeData[1].communities;
|
||||||
if (UserService.Instance.localUserView) {
|
|
||||||
this.state.subscribedCommunities =
|
|
||||||
this.isoData.routeData[2].communities;
|
|
||||||
}
|
|
||||||
this.state.loading = false;
|
this.state.loading = false;
|
||||||
} else {
|
} else {
|
||||||
this.fetchTrendingCommunities();
|
this.fetchTrendingCommunities();
|
||||||
this.fetchData();
|
this.fetchData();
|
||||||
if (UserService.Instance.localUserView) {
|
|
||||||
WebSocketService.Instance.send(
|
|
||||||
wsClient.getFollowedCommunities({
|
|
||||||
auth: authField(),
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
setupTippy();
|
setupTippy();
|
||||||
|
@ -204,16 +191,18 @@ export class Home extends Component<any, HomeState> {
|
||||||
// TODO figure out auth default_listingType, default_sort_type
|
// TODO figure out auth default_listingType, default_sort_type
|
||||||
let type_: ListingType = pathSplit[5]
|
let type_: ListingType = pathSplit[5]
|
||||||
? ListingType[pathSplit[5]]
|
? ListingType[pathSplit[5]]
|
||||||
: UserService.Instance.localUserView
|
: UserService.Instance.myUserInfo
|
||||||
? Object.values(ListingType)[
|
? Object.values(ListingType)[
|
||||||
UserService.Instance.localUserView.local_user.default_listing_type
|
UserService.Instance.myUserInfo.local_user_view.local_user
|
||||||
|
.default_listing_type
|
||||||
]
|
]
|
||||||
: ListingType.Local;
|
: ListingType.Local;
|
||||||
let sort: SortType = pathSplit[7]
|
let sort: SortType = pathSplit[7]
|
||||||
? SortType[pathSplit[7]]
|
? SortType[pathSplit[7]]
|
||||||
: UserService.Instance.localUserView
|
: UserService.Instance.myUserInfo
|
||||||
? Object.values(SortType)[
|
? Object.values(SortType)[
|
||||||
UserService.Instance.localUserView.local_user.default_sort_type
|
UserService.Instance.myUserInfo.local_user_view.local_user
|
||||||
|
.default_sort_type
|
||||||
]
|
]
|
||||||
: SortType.Active;
|
: SortType.Active;
|
||||||
|
|
||||||
|
@ -250,10 +239,6 @@ export class Home extends Component<any, HomeState> {
|
||||||
};
|
};
|
||||||
promises.push(req.client.listCommunities(trendingCommunitiesForm));
|
promises.push(req.client.listCommunities(trendingCommunitiesForm));
|
||||||
|
|
||||||
if (req.auth) {
|
|
||||||
promises.push(req.client.getFollowedCommunities({ auth: req.auth }));
|
|
||||||
}
|
|
||||||
|
|
||||||
return promises;
|
return promises;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -303,8 +288,8 @@ export class Home extends Component<any, HomeState> {
|
||||||
return (
|
return (
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-12">
|
<div class="col-12">
|
||||||
{UserService.Instance.localUserView &&
|
{UserService.Instance.myUserInfo &&
|
||||||
this.state.subscribedCommunities.length > 0 && (
|
UserService.Instance.myUserInfo.follows.length > 0 && (
|
||||||
<button
|
<button
|
||||||
class="btn btn-secondary d-inline-block mb-2 mr-3"
|
class="btn btn-secondary d-inline-block mb-2 mr-3"
|
||||||
onClick={linkEvent(this, this.handleShowSubscribedMobile)}
|
onClick={linkEvent(this, this.handleShowSubscribedMobile)}
|
||||||
|
@ -377,8 +362,8 @@ export class Home extends Component<any, HomeState> {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{UserService.Instance.localUserView &&
|
{UserService.Instance.myUserInfo &&
|
||||||
this.state.subscribedCommunities.length > 0 && (
|
UserService.Instance.myUserInfo.follows.length > 0 && (
|
||||||
<div class="card border-secondary mb-3">
|
<div class="card border-secondary mb-3">
|
||||||
<div class="card-body">{this.subscribedCommunities()}</div>
|
<div class="card-body">{this.subscribedCommunities()}</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -443,7 +428,7 @@ export class Home extends Component<any, HomeState> {
|
||||||
</T>
|
</T>
|
||||||
</h5>
|
</h5>
|
||||||
<ul class="list-inline mb-0">
|
<ul class="list-inline mb-0">
|
||||||
{this.state.subscribedCommunities.map(cfv => (
|
{UserService.Instance.myUserInfo.follows.map(cfv => (
|
||||||
<li class="list-inline-item d-inline-block">
|
<li class="list-inline-item d-inline-block">
|
||||||
<CommunityLink community={cfv.community} />
|
<CommunityLink community={cfv.community} />
|
||||||
</li>
|
</li>
|
||||||
|
@ -704,7 +689,7 @@ export class Home extends Component<any, HomeState> {
|
||||||
<Icon icon="rss" classes="text-muted small" />
|
<Icon icon="rss" classes="text-muted small" />
|
||||||
</a>
|
</a>
|
||||||
)}
|
)}
|
||||||
{UserService.Instance.localUserView &&
|
{UserService.Instance.myUserInfo &&
|
||||||
this.state.listingType == ListingType.Subscribed && (
|
this.state.listingType == ListingType.Subscribed && (
|
||||||
<a
|
<a
|
||||||
href={`/feeds/front/${UserService.Instance.auth}.xml?sort=${this.state.sort}`}
|
href={`/feeds/front/${UserService.Instance.auth}.xml?sort=${this.state.sort}`}
|
||||||
|
@ -720,10 +705,10 @@ export class Home extends Component<any, HomeState> {
|
||||||
|
|
||||||
get canAdmin(): boolean {
|
get canAdmin(): boolean {
|
||||||
return (
|
return (
|
||||||
UserService.Instance.localUserView &&
|
UserService.Instance.myUserInfo &&
|
||||||
this.state.siteRes.admins
|
this.state.siteRes.admins
|
||||||
.map(a => a.person.id)
|
.map(a => a.person.id)
|
||||||
.includes(UserService.Instance.localUserView.person.id)
|
.includes(UserService.Instance.myUserInfo.local_user_view.person.id)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -807,10 +792,6 @@ export class Home extends Component<any, HomeState> {
|
||||||
wsClient.communityJoin({ community_id: 0 })
|
wsClient.communityJoin({ community_id: 0 })
|
||||||
);
|
);
|
||||||
this.fetchData();
|
this.fetchData();
|
||||||
} else if (op == UserOperation.GetFollowedCommunities) {
|
|
||||||
let data = wsJsonToRes<GetFollowedCommunitiesResponse>(msg).data;
|
|
||||||
this.state.subscribedCommunities = data.communities;
|
|
||||||
this.setState(this.state);
|
|
||||||
} else if (op == UserOperation.ListCommunities) {
|
} else if (op == UserOperation.ListCommunities) {
|
||||||
let data = wsJsonToRes<ListCommunitiesResponse>(msg).data;
|
let data = wsJsonToRes<ListCommunitiesResponse>(msg).data;
|
||||||
this.state.trendingCommunities = data.communities;
|
this.state.trendingCommunities = data.communities;
|
||||||
|
@ -836,21 +817,21 @@ export class Home extends Component<any, HomeState> {
|
||||||
let nsfwCheck =
|
let nsfwCheck =
|
||||||
!nsfw ||
|
!nsfw ||
|
||||||
(nsfw &&
|
(nsfw &&
|
||||||
UserService.Instance.localUserView &&
|
UserService.Instance.myUserInfo &&
|
||||||
UserService.Instance.localUserView.local_user.show_nsfw);
|
UserService.Instance.myUserInfo.local_user_view.local_user.show_nsfw);
|
||||||
|
|
||||||
// Only push these if you're on the first page, and you pass the nsfw check
|
// Only push these if you're on the first page, and you pass the nsfw check
|
||||||
if (this.state.page == 1 && nsfwCheck) {
|
if (this.state.page == 1 && nsfwCheck) {
|
||||||
// If you're on subscribed, only push it if you're subscribed.
|
// If you're on subscribed, only push it if you're subscribed.
|
||||||
if (this.state.listingType == ListingType.Subscribed) {
|
if (this.state.listingType == ListingType.Subscribed) {
|
||||||
if (
|
if (
|
||||||
this.state.subscribedCommunities
|
UserService.Instance.myUserInfo.follows
|
||||||
.map(c => c.community.id)
|
.map(c => c.community.id)
|
||||||
.includes(data.post_view.community.id)
|
.includes(data.post_view.community.id)
|
||||||
) {
|
) {
|
||||||
this.state.posts.unshift(data.post_view);
|
this.state.posts.unshift(data.post_view);
|
||||||
if (
|
if (
|
||||||
UserService.Instance.localUserView?.local_user
|
UserService.Instance.myUserInfo?.local_user_view.local_user
|
||||||
.show_new_post_notifs
|
.show_new_post_notifs
|
||||||
) {
|
) {
|
||||||
notifyPost(data.post_view, this.context.router);
|
notifyPost(data.post_view, this.context.router);
|
||||||
|
@ -861,7 +842,7 @@ export class Home extends Component<any, HomeState> {
|
||||||
if (data.post_view.post.local) {
|
if (data.post_view.post.local) {
|
||||||
this.state.posts.unshift(data.post_view);
|
this.state.posts.unshift(data.post_view);
|
||||||
if (
|
if (
|
||||||
UserService.Instance.localUserView?.local_user
|
UserService.Instance.myUserInfo?.local_user_view.local_user
|
||||||
.show_new_post_notifs
|
.show_new_post_notifs
|
||||||
) {
|
) {
|
||||||
notifyPost(data.post_view, this.context.router);
|
notifyPost(data.post_view, this.context.router);
|
||||||
|
@ -870,7 +851,8 @@ export class Home extends Component<any, HomeState> {
|
||||||
} else {
|
} else {
|
||||||
this.state.posts.unshift(data.post_view);
|
this.state.posts.unshift(data.post_view);
|
||||||
if (
|
if (
|
||||||
UserService.Instance.localUserView?.local_user.show_new_post_notifs
|
UserService.Instance.myUserInfo?.local_user_view.local_user
|
||||||
|
.show_new_post_notifs
|
||||||
) {
|
) {
|
||||||
notifyPost(data.post_view, this.context.router);
|
notifyPost(data.post_view, this.context.router);
|
||||||
}
|
}
|
||||||
|
@ -937,7 +919,7 @@ export class Home extends Component<any, HomeState> {
|
||||||
// If you're on subscribed, only push it if you're subscribed.
|
// If you're on subscribed, only push it if you're subscribed.
|
||||||
if (this.state.listingType == ListingType.Subscribed) {
|
if (this.state.listingType == ListingType.Subscribed) {
|
||||||
if (
|
if (
|
||||||
this.state.subscribedCommunities
|
UserService.Instance.myUserInfo.follows
|
||||||
.map(c => c.community.id)
|
.map(c => c.community.id)
|
||||||
.includes(data.comment_view.community.id)
|
.includes(data.comment_view.community.id)
|
||||||
) {
|
) {
|
||||||
|
@ -956,6 +938,9 @@ export class Home extends Component<any, HomeState> {
|
||||||
let data = wsJsonToRes<CommentResponse>(msg).data;
|
let data = wsJsonToRes<CommentResponse>(msg).data;
|
||||||
createCommentLikeRes(data.comment_view, this.state.comments);
|
createCommentLikeRes(data.comment_view, this.state.comments);
|
||||||
this.setState(this.state);
|
this.setState(this.state);
|
||||||
|
} else if (op == UserOperation.BlockPerson) {
|
||||||
|
let data = wsJsonToRes<BlockPersonResponse>(msg).data;
|
||||||
|
updatePersonBlock(data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -409,16 +409,16 @@ export class Modlog extends Component<any, ModlogState> {
|
||||||
|
|
||||||
get isAdminOrMod(): boolean {
|
get isAdminOrMod(): boolean {
|
||||||
let isAdmin =
|
let isAdmin =
|
||||||
UserService.Instance.localUserView &&
|
UserService.Instance.myUserInfo &&
|
||||||
this.isoData.site_res.admins
|
this.isoData.site_res.admins
|
||||||
.map(a => a.person.id)
|
.map(a => a.person.id)
|
||||||
.includes(UserService.Instance.localUserView.person.id);
|
.includes(UserService.Instance.myUserInfo.local_user_view.person.id);
|
||||||
let isMod =
|
let isMod =
|
||||||
UserService.Instance.localUserView &&
|
UserService.Instance.myUserInfo &&
|
||||||
this.state.communityMods &&
|
this.state.communityMods &&
|
||||||
this.state.communityMods
|
this.state.communityMods
|
||||||
.map(m => m.moderator.id)
|
.map(m => m.moderator.id)
|
||||||
.includes(UserService.Instance.localUserView.person.id);
|
.includes(UserService.Instance.myUserInfo.local_user_view.person.id);
|
||||||
return isAdmin || isMod;
|
return isAdmin || isMod;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import { Component, linkEvent } from "inferno";
|
import { Component, linkEvent } from "inferno";
|
||||||
import {
|
import {
|
||||||
|
BlockPersonResponse,
|
||||||
CommentResponse,
|
CommentResponse,
|
||||||
CommentView,
|
CommentView,
|
||||||
GetPersonMentions,
|
GetPersonMentions,
|
||||||
|
@ -31,6 +32,7 @@ import {
|
||||||
setIsoData,
|
setIsoData,
|
||||||
setupTippy,
|
setupTippy,
|
||||||
toast,
|
toast,
|
||||||
|
updatePersonBlock,
|
||||||
wsClient,
|
wsClient,
|
||||||
wsJsonToRes,
|
wsJsonToRes,
|
||||||
wsSubscribe,
|
wsSubscribe,
|
||||||
|
@ -103,7 +105,7 @@ export class Inbox extends Component<any, InboxState> {
|
||||||
this.handleSortChange = this.handleSortChange.bind(this);
|
this.handleSortChange = this.handleSortChange.bind(this);
|
||||||
this.handlePageChange = this.handlePageChange.bind(this);
|
this.handlePageChange = this.handlePageChange.bind(this);
|
||||||
|
|
||||||
if (!UserService.Instance.localUserView && isBrowser()) {
|
if (!UserService.Instance.myUserInfo && isBrowser()) {
|
||||||
toast(i18n.t("not_logged_in"), "danger");
|
toast(i18n.t("not_logged_in"), "danger");
|
||||||
this.context.router.history.push(`/login`);
|
this.context.router.history.push(`/login`);
|
||||||
}
|
}
|
||||||
|
@ -130,9 +132,9 @@ export class Inbox extends Component<any, InboxState> {
|
||||||
}
|
}
|
||||||
|
|
||||||
get documentTitle(): string {
|
get documentTitle(): string {
|
||||||
return `@${UserService.Instance.localUserView.person.name} ${i18n.t(
|
return `@${
|
||||||
"inbox"
|
UserService.Instance.myUserInfo.local_user_view.person.name
|
||||||
)} - ${this.state.site_view.site.name}`;
|
} ${i18n.t("inbox")} - ${this.state.site_view.site.name}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
@ -722,7 +724,7 @@ export class Inbox extends Component<any, InboxState> {
|
||||||
|
|
||||||
if (
|
if (
|
||||||
data.recipient_ids.includes(
|
data.recipient_ids.includes(
|
||||||
UserService.Instance.localUserView.local_user.id
|
UserService.Instance.myUserInfo.local_user_view.local_user.id
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
this.state.replies.unshift(data.comment_view);
|
this.state.replies.unshift(data.comment_view);
|
||||||
|
@ -730,7 +732,7 @@ export class Inbox extends Component<any, InboxState> {
|
||||||
this.setState(this.state);
|
this.setState(this.state);
|
||||||
} else if (
|
} else if (
|
||||||
data.comment_view.creator.id ==
|
data.comment_view.creator.id ==
|
||||||
UserService.Instance.localUserView.person.id
|
UserService.Instance.myUserInfo.local_user_view.person.id
|
||||||
) {
|
) {
|
||||||
// TODO this seems wrong, you should be using form_id
|
// TODO this seems wrong, you should be using form_id
|
||||||
toast(i18n.t("reply_sent"));
|
toast(i18n.t("reply_sent"));
|
||||||
|
@ -739,7 +741,7 @@ export class Inbox extends Component<any, InboxState> {
|
||||||
let data = wsJsonToRes<PrivateMessageResponse>(msg).data;
|
let data = wsJsonToRes<PrivateMessageResponse>(msg).data;
|
||||||
if (
|
if (
|
||||||
data.private_message_view.recipient.id ==
|
data.private_message_view.recipient.id ==
|
||||||
UserService.Instance.localUserView.person.id
|
UserService.Instance.myUserInfo.local_user_view.person.id
|
||||||
) {
|
) {
|
||||||
this.state.messages.unshift(data.private_message_view);
|
this.state.messages.unshift(data.private_message_view);
|
||||||
this.state.combined.unshift(
|
this.state.combined.unshift(
|
||||||
|
@ -756,6 +758,9 @@ export class Inbox extends Component<any, InboxState> {
|
||||||
let data = wsJsonToRes<CommentResponse>(msg).data;
|
let data = wsJsonToRes<CommentResponse>(msg).data;
|
||||||
createCommentLikeRes(data.comment_view, this.state.replies);
|
createCommentLikeRes(data.comment_view, this.state.replies);
|
||||||
this.setState(this.state);
|
this.setState(this.state);
|
||||||
|
} else if (op == UserOperation.BlockPerson) {
|
||||||
|
let data = wsJsonToRes<BlockPersonResponse>(msg).data;
|
||||||
|
updatePersonBlock(data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -769,10 +774,11 @@ export class Inbox extends Component<any, InboxState> {
|
||||||
this.state.mentions.filter(r => !r.person_mention.read).length +
|
this.state.mentions.filter(r => !r.person_mention.read).length +
|
||||||
this.state.messages.filter(
|
this.state.messages.filter(
|
||||||
r =>
|
r =>
|
||||||
UserService.Instance.localUserView &&
|
UserService.Instance.myUserInfo &&
|
||||||
!r.private_message.read &&
|
!r.private_message.read &&
|
||||||
// TODO also seems very strange and wrong
|
// TODO also seems very strange and wrong
|
||||||
r.creator.id !== UserService.Instance.localUserView.person.id
|
r.creator.id !==
|
||||||
|
UserService.Instance.myUserInfo.local_user_view.person.id
|
||||||
).length
|
).length
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load diff
583
src/shared/components/person/profile.tsx
Normal file
583
src/shared/components/person/profile.tsx
Normal file
|
@ -0,0 +1,583 @@
|
||||||
|
import { Component, linkEvent } from "inferno";
|
||||||
|
import { Link } from "inferno-router";
|
||||||
|
import {
|
||||||
|
AddAdminResponse,
|
||||||
|
BanPersonResponse,
|
||||||
|
BlockPersonResponse,
|
||||||
|
CommentResponse,
|
||||||
|
GetPersonDetails,
|
||||||
|
GetPersonDetailsResponse,
|
||||||
|
GetSiteResponse,
|
||||||
|
PostResponse,
|
||||||
|
SortType,
|
||||||
|
UserOperation,
|
||||||
|
} from "lemmy-js-client";
|
||||||
|
import moment from "moment";
|
||||||
|
import { Subscription } from "rxjs";
|
||||||
|
import { i18n } from "../../i18next";
|
||||||
|
import { InitialFetchRequest, PersonDetailsView } from "../../interfaces";
|
||||||
|
import { UserService, WebSocketService } from "../../services";
|
||||||
|
import {
|
||||||
|
authField,
|
||||||
|
createCommentLikeRes,
|
||||||
|
createPostLikeFindRes,
|
||||||
|
editCommentRes,
|
||||||
|
editPostFindRes,
|
||||||
|
fetchLimit,
|
||||||
|
getUsernameFromProps,
|
||||||
|
mdToHtml,
|
||||||
|
previewLines,
|
||||||
|
restoreScrollPosition,
|
||||||
|
routeSortTypeToEnum,
|
||||||
|
saveCommentRes,
|
||||||
|
saveScrollPosition,
|
||||||
|
setIsoData,
|
||||||
|
setOptionalAuth,
|
||||||
|
setupTippy,
|
||||||
|
toast,
|
||||||
|
updatePersonBlock,
|
||||||
|
wsClient,
|
||||||
|
wsJsonToRes,
|
||||||
|
wsSubscribe,
|
||||||
|
wsUserOp,
|
||||||
|
} from "../../utils";
|
||||||
|
import { BannerIconHeader } from "../common/banner-icon-header";
|
||||||
|
import { HtmlTags } from "../common/html-tags";
|
||||||
|
import { Icon, Spinner } from "../common/icon";
|
||||||
|
import { MomentTime } from "../common/moment-time";
|
||||||
|
import { SortSelect } from "../common/sort-select";
|
||||||
|
import { CommunityLink } from "../community/community-link";
|
||||||
|
import { PersonDetails } from "./person-details";
|
||||||
|
import { PersonListing } from "./person-listing";
|
||||||
|
|
||||||
|
interface ProfileState {
|
||||||
|
personRes: GetPersonDetailsResponse;
|
||||||
|
userName: string;
|
||||||
|
view: PersonDetailsView;
|
||||||
|
sort: SortType;
|
||||||
|
page: number;
|
||||||
|
loading: boolean;
|
||||||
|
siteRes: GetSiteResponse;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ProfileProps {
|
||||||
|
view: PersonDetailsView;
|
||||||
|
sort: SortType;
|
||||||
|
page: number;
|
||||||
|
person_id: number | null;
|
||||||
|
username: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface UrlParams {
|
||||||
|
view?: string;
|
||||||
|
sort?: SortType;
|
||||||
|
page?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Profile extends Component<any, ProfileState> {
|
||||||
|
private isoData = setIsoData(this.context);
|
||||||
|
private subscription: Subscription;
|
||||||
|
private emptyState: ProfileState = {
|
||||||
|
personRes: undefined,
|
||||||
|
userName: getUsernameFromProps(this.props),
|
||||||
|
loading: true,
|
||||||
|
view: Profile.getViewFromProps(this.props.match.view),
|
||||||
|
sort: Profile.getSortTypeFromProps(this.props.match.sort),
|
||||||
|
page: Profile.getPageFromProps(this.props.match.page),
|
||||||
|
siteRes: this.isoData.site_res,
|
||||||
|
};
|
||||||
|
|
||||||
|
constructor(props: any, context: any) {
|
||||||
|
super(props, context);
|
||||||
|
|
||||||
|
this.state = this.emptyState;
|
||||||
|
this.handleSortChange = this.handleSortChange.bind(this);
|
||||||
|
|
||||||
|
this.parseMessage = this.parseMessage.bind(this);
|
||||||
|
this.subscription = wsSubscribe(this.parseMessage);
|
||||||
|
|
||||||
|
// Only fetch the data if coming from another route
|
||||||
|
if (this.isoData.path == this.context.router.route.match.url) {
|
||||||
|
this.state.personRes = this.isoData.routeData[0];
|
||||||
|
this.state.loading = false;
|
||||||
|
} else {
|
||||||
|
this.fetchUserData();
|
||||||
|
}
|
||||||
|
|
||||||
|
setupTippy();
|
||||||
|
}
|
||||||
|
|
||||||
|
fetchUserData() {
|
||||||
|
let form: GetPersonDetails = {
|
||||||
|
username: this.state.userName,
|
||||||
|
sort: this.state.sort,
|
||||||
|
saved_only: this.state.view === PersonDetailsView.Saved,
|
||||||
|
page: this.state.page,
|
||||||
|
limit: fetchLimit,
|
||||||
|
auth: authField(false),
|
||||||
|
};
|
||||||
|
WebSocketService.Instance.send(wsClient.getPersonDetails(form));
|
||||||
|
}
|
||||||
|
|
||||||
|
get isCurrentUser() {
|
||||||
|
return (
|
||||||
|
UserService.Instance.myUserInfo?.local_user_view.person.id ==
|
||||||
|
this.state.personRes.person_view.person.id
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static getViewFromProps(view: string): PersonDetailsView {
|
||||||
|
return view ? PersonDetailsView[view] : PersonDetailsView.Overview;
|
||||||
|
}
|
||||||
|
|
||||||
|
static getSortTypeFromProps(sort: string): SortType {
|
||||||
|
return sort ? routeSortTypeToEnum(sort) : SortType.New;
|
||||||
|
}
|
||||||
|
|
||||||
|
static getPageFromProps(page: number): number {
|
||||||
|
return page ? Number(page) : 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static fetchInitialData(req: InitialFetchRequest): Promise<any>[] {
|
||||||
|
let pathSplit = req.path.split("/");
|
||||||
|
let promises: Promise<any>[] = [];
|
||||||
|
|
||||||
|
// It can be /u/me, or /username/1
|
||||||
|
let idOrName = pathSplit[2];
|
||||||
|
let person_id: number;
|
||||||
|
let username: string;
|
||||||
|
if (isNaN(Number(idOrName))) {
|
||||||
|
username = idOrName;
|
||||||
|
} else {
|
||||||
|
person_id = Number(idOrName);
|
||||||
|
}
|
||||||
|
|
||||||
|
let view = this.getViewFromProps(pathSplit[4]);
|
||||||
|
let sort = this.getSortTypeFromProps(pathSplit[6]);
|
||||||
|
let page = this.getPageFromProps(Number(pathSplit[8]));
|
||||||
|
|
||||||
|
let form: GetPersonDetails = {
|
||||||
|
sort,
|
||||||
|
saved_only: view === PersonDetailsView.Saved,
|
||||||
|
page,
|
||||||
|
limit: fetchLimit,
|
||||||
|
};
|
||||||
|
setOptionalAuth(form, req.auth);
|
||||||
|
this.setIdOrName(form, person_id, username);
|
||||||
|
promises.push(req.client.getPersonDetails(form));
|
||||||
|
return promises;
|
||||||
|
}
|
||||||
|
|
||||||
|
static setIdOrName(obj: any, id: number, name_: string) {
|
||||||
|
if (id) {
|
||||||
|
obj.person_id = id;
|
||||||
|
} else {
|
||||||
|
obj.username = name_;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillUnmount() {
|
||||||
|
this.subscription.unsubscribe();
|
||||||
|
saveScrollPosition(this.context);
|
||||||
|
}
|
||||||
|
|
||||||
|
static getDerivedStateFromProps(props: any): ProfileProps {
|
||||||
|
return {
|
||||||
|
view: this.getViewFromProps(props.match.params.view),
|
||||||
|
sort: this.getSortTypeFromProps(props.match.params.sort),
|
||||||
|
page: this.getPageFromProps(props.match.params.page),
|
||||||
|
person_id: Number(props.match.params.id) || null,
|
||||||
|
username: props.match.params.username,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidUpdate(lastProps: any) {
|
||||||
|
// Necessary if you are on a post and you click another post (same route)
|
||||||
|
if (
|
||||||
|
lastProps.location.pathname.split("/")[2] !==
|
||||||
|
lastProps.history.location.pathname.split("/")[2]
|
||||||
|
) {
|
||||||
|
// Couldnt get a refresh working. This does for now.
|
||||||
|
location.reload();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
get documentTitle(): string {
|
||||||
|
return `@${this.state.personRes.person_view.person.name} - ${this.state.siteRes.site_view.site.name}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
get bioTag(): string {
|
||||||
|
return this.state.personRes.person_view.person.bio
|
||||||
|
? previewLines(this.state.personRes.person_view.person.bio)
|
||||||
|
: undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div class="container">
|
||||||
|
{this.state.loading ? (
|
||||||
|
<h5>
|
||||||
|
<Spinner large />
|
||||||
|
</h5>
|
||||||
|
) : (
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-12 col-md-8">
|
||||||
|
<>
|
||||||
|
<HtmlTags
|
||||||
|
title={this.documentTitle}
|
||||||
|
path={this.context.router.route.match.url}
|
||||||
|
description={this.bioTag}
|
||||||
|
image={this.state.personRes.person_view.person.avatar}
|
||||||
|
/>
|
||||||
|
{this.userInfo()}
|
||||||
|
<hr />
|
||||||
|
</>
|
||||||
|
{!this.state.loading && this.selects()}
|
||||||
|
<PersonDetails
|
||||||
|
personRes={this.state.personRes}
|
||||||
|
admins={this.state.siteRes.admins}
|
||||||
|
sort={this.state.sort}
|
||||||
|
page={this.state.page}
|
||||||
|
limit={fetchLimit}
|
||||||
|
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}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{!this.state.loading && (
|
||||||
|
<div class="col-12 col-md-4">
|
||||||
|
{this.moderates()}
|
||||||
|
{UserService.Instance.myUserInfo && this.follows()}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
viewRadios() {
|
||||||
|
return (
|
||||||
|
<div class="btn-group btn-group-toggle flex-wrap mb-2">
|
||||||
|
<label
|
||||||
|
className={`btn btn-outline-secondary pointer
|
||||||
|
${this.state.view == PersonDetailsView.Overview && "active"}
|
||||||
|
`}
|
||||||
|
>
|
||||||
|
<input
|
||||||
|
type="radio"
|
||||||
|
value={PersonDetailsView.Overview}
|
||||||
|
checked={this.state.view === PersonDetailsView.Overview}
|
||||||
|
onChange={linkEvent(this, this.handleViewChange)}
|
||||||
|
/>
|
||||||
|
{i18n.t("overview")}
|
||||||
|
</label>
|
||||||
|
<label
|
||||||
|
className={`btn btn-outline-secondary pointer
|
||||||
|
${this.state.view == PersonDetailsView.Comments && "active"}
|
||||||
|
`}
|
||||||
|
>
|
||||||
|
<input
|
||||||
|
type="radio"
|
||||||
|
value={PersonDetailsView.Comments}
|
||||||
|
checked={this.state.view == PersonDetailsView.Comments}
|
||||||
|
onChange={linkEvent(this, this.handleViewChange)}
|
||||||
|
/>
|
||||||
|
{i18n.t("comments")}
|
||||||
|
</label>
|
||||||
|
<label
|
||||||
|
className={`btn btn-outline-secondary pointer
|
||||||
|
${this.state.view == PersonDetailsView.Posts && "active"}
|
||||||
|
`}
|
||||||
|
>
|
||||||
|
<input
|
||||||
|
type="radio"
|
||||||
|
value={PersonDetailsView.Posts}
|
||||||
|
checked={this.state.view == PersonDetailsView.Posts}
|
||||||
|
onChange={linkEvent(this, this.handleViewChange)}
|
||||||
|
/>
|
||||||
|
{i18n.t("posts")}
|
||||||
|
</label>
|
||||||
|
<label
|
||||||
|
className={`btn btn-outline-secondary pointer
|
||||||
|
${this.state.view == PersonDetailsView.Saved && "active"}
|
||||||
|
`}
|
||||||
|
>
|
||||||
|
<input
|
||||||
|
type="radio"
|
||||||
|
value={PersonDetailsView.Saved}
|
||||||
|
checked={this.state.view == PersonDetailsView.Saved}
|
||||||
|
onChange={linkEvent(this, this.handleViewChange)}
|
||||||
|
/>
|
||||||
|
{i18n.t("saved")}
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
selects() {
|
||||||
|
return (
|
||||||
|
<div className="mb-2">
|
||||||
|
<span class="mr-3">{this.viewRadios()}</span>
|
||||||
|
<SortSelect
|
||||||
|
sort={this.state.sort}
|
||||||
|
onChange={this.handleSortChange}
|
||||||
|
hideHot
|
||||||
|
hideMostComments
|
||||||
|
/>
|
||||||
|
<a
|
||||||
|
href={`/feeds/u/${this.state.userName}.xml?sort=${this.state.sort}`}
|
||||||
|
rel="noopener"
|
||||||
|
title="RSS"
|
||||||
|
>
|
||||||
|
<Icon icon="rss" classes="text-muted small mx-2" />
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
userInfo() {
|
||||||
|
let pv = this.state.personRes?.person_view;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<BannerIconHeader banner={pv.person.banner} icon={pv.person.avatar} />
|
||||||
|
<div class="mb-3">
|
||||||
|
<div class="">
|
||||||
|
<div class="mb-0 d-flex flex-wrap">
|
||||||
|
<div>
|
||||||
|
{pv.person.display_name && (
|
||||||
|
<h5 class="mb-0">{pv.person.display_name}</h5>
|
||||||
|
)}
|
||||||
|
<ul class="list-inline mb-2">
|
||||||
|
<li className="list-inline-item">
|
||||||
|
<PersonListing
|
||||||
|
person={pv.person}
|
||||||
|
realLink
|
||||||
|
useApubName
|
||||||
|
muted
|
||||||
|
hideAvatar
|
||||||
|
/>
|
||||||
|
</li>
|
||||||
|
{pv.person.banned && (
|
||||||
|
<li className="list-inline-item badge badge-danger">
|
||||||
|
{i18n.t("banned")}
|
||||||
|
</li>
|
||||||
|
)}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div className="flex-grow-1 unselectable pointer mx-2"></div>
|
||||||
|
{!this.isCurrentUser && (
|
||||||
|
<>
|
||||||
|
<a
|
||||||
|
className={`d-flex align-self-start btn btn-secondary mr-2 ${
|
||||||
|
!pv.person.matrix_user_id && "invisible"
|
||||||
|
}`}
|
||||||
|
rel="noopener"
|
||||||
|
href={`https://matrix.to/#/${pv.person.matrix_user_id}`}
|
||||||
|
>
|
||||||
|
{i18n.t("send_secure_message")}
|
||||||
|
</a>
|
||||||
|
<Link
|
||||||
|
className={"d-flex align-self-start btn btn-secondary"}
|
||||||
|
to={`/create_private_message/recipient/${pv.person.id}`}
|
||||||
|
>
|
||||||
|
{i18n.t("send_message")}
|
||||||
|
</Link>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
{pv.person.bio && (
|
||||||
|
<div className="d-flex align-items-center mb-2">
|
||||||
|
<div
|
||||||
|
className="md-div"
|
||||||
|
dangerouslySetInnerHTML={mdToHtml(pv.person.bio)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
<div>
|
||||||
|
<ul class="list-inline mb-2">
|
||||||
|
<li className="list-inline-item badge badge-light">
|
||||||
|
{i18n.t("number_of_posts", { count: pv.counts.post_count })}
|
||||||
|
</li>
|
||||||
|
<li className="list-inline-item badge badge-light">
|
||||||
|
{i18n.t("number_of_comments", {
|
||||||
|
count: pv.counts.comment_count,
|
||||||
|
})}
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div class="text-muted">
|
||||||
|
{i18n.t("joined")}{" "}
|
||||||
|
<MomentTime data={pv.person} showAgo ignoreUpdated />
|
||||||
|
</div>
|
||||||
|
<div className="d-flex align-items-center text-muted mb-2">
|
||||||
|
<Icon icon="cake" />
|
||||||
|
<span className="ml-2">
|
||||||
|
{i18n.t("cake_day_title")}{" "}
|
||||||
|
{moment.utc(pv.person.published).local().format("MMM DD, YYYY")}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
moderates() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
{this.state.personRes.moderates.length > 0 && (
|
||||||
|
<div class="card border-secondary mb-3">
|
||||||
|
<div class="card-body">
|
||||||
|
<h5>{i18n.t("moderates")}</h5>
|
||||||
|
<ul class="list-unstyled mb-0">
|
||||||
|
{this.state.personRes.moderates.map(cmv => (
|
||||||
|
<li>
|
||||||
|
<CommunityLink community={cmv.community} />
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
follows() {
|
||||||
|
let follows = UserService.Instance.myUserInfo.follows;
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
{follows.length > 0 && (
|
||||||
|
<div class="card border-secondary mb-3">
|
||||||
|
<div class="card-body">
|
||||||
|
<h5>{i18n.t("subscribed")}</h5>
|
||||||
|
<ul class="list-unstyled mb-0">
|
||||||
|
{follows.map(cfv => (
|
||||||
|
<li>
|
||||||
|
<CommunityLink community={cfv.community} />
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
updateUrl(paramUpdates: UrlParams) {
|
||||||
|
const page = paramUpdates.page || this.state.page;
|
||||||
|
const viewStr = paramUpdates.view || PersonDetailsView[this.state.view];
|
||||||
|
const sortStr = paramUpdates.sort || this.state.sort;
|
||||||
|
|
||||||
|
let typeView = `/u/${this.state.userName}`;
|
||||||
|
|
||||||
|
this.props.history.push(
|
||||||
|
`${typeView}/view/${viewStr}/sort/${sortStr}/page/${page}`
|
||||||
|
);
|
||||||
|
this.state.loading = true;
|
||||||
|
this.setState(this.state);
|
||||||
|
this.fetchUserData();
|
||||||
|
}
|
||||||
|
|
||||||
|
handlePageChange(page: number) {
|
||||||
|
this.updateUrl({ page });
|
||||||
|
}
|
||||||
|
|
||||||
|
handleSortChange(val: SortType) {
|
||||||
|
this.updateUrl({ sort: val, page: 1 });
|
||||||
|
}
|
||||||
|
|
||||||
|
handleViewChange(i: Profile, event: any) {
|
||||||
|
i.updateUrl({
|
||||||
|
view: PersonDetailsView[Number(event.target.value)],
|
||||||
|
page: 1,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
parseMessage(msg: any) {
|
||||||
|
let op = wsUserOp(msg);
|
||||||
|
console.log(msg);
|
||||||
|
if (msg.error) {
|
||||||
|
toast(i18n.t(msg.error), "danger");
|
||||||
|
if (msg.error == "couldnt_find_that_username_or_email") {
|
||||||
|
this.context.router.history.push("/");
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
} else if (msg.reconnect) {
|
||||||
|
this.fetchUserData();
|
||||||
|
} else if (op == UserOperation.GetPersonDetails) {
|
||||||
|
// Since the PersonDetails 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
|
||||||
|
let data = wsJsonToRes<GetPersonDetailsResponse>(msg).data;
|
||||||
|
this.state.personRes = data;
|
||||||
|
console.log(data);
|
||||||
|
this.state.loading = false;
|
||||||
|
this.setState(this.state);
|
||||||
|
restoreScrollPosition(this.context);
|
||||||
|
} else if (op == UserOperation.AddAdmin) {
|
||||||
|
let data = wsJsonToRes<AddAdminResponse>(msg).data;
|
||||||
|
this.state.siteRes.admins = data.admins;
|
||||||
|
this.setState(this.state);
|
||||||
|
} else if (op == UserOperation.CreateCommentLike) {
|
||||||
|
let data = wsJsonToRes<CommentResponse>(msg).data;
|
||||||
|
createCommentLikeRes(data.comment_view, this.state.personRes.comments);
|
||||||
|
this.setState(this.state);
|
||||||
|
} else if (
|
||||||
|
op == UserOperation.EditComment ||
|
||||||
|
op == UserOperation.DeleteComment ||
|
||||||
|
op == UserOperation.RemoveComment
|
||||||
|
) {
|
||||||
|
let data = wsJsonToRes<CommentResponse>(msg).data;
|
||||||
|
editCommentRes(data.comment_view, this.state.personRes.comments);
|
||||||
|
this.setState(this.state);
|
||||||
|
} else if (op == UserOperation.CreateComment) {
|
||||||
|
let data = wsJsonToRes<CommentResponse>(msg).data;
|
||||||
|
if (
|
||||||
|
UserService.Instance.myUserInfo &&
|
||||||
|
data.comment_view.creator.id ==
|
||||||
|
UserService.Instance.myUserInfo.local_user_view.person.id
|
||||||
|
) {
|
||||||
|
toast(i18n.t("reply_sent"));
|
||||||
|
}
|
||||||
|
} else if (op == UserOperation.SaveComment) {
|
||||||
|
let data = wsJsonToRes<CommentResponse>(msg).data;
|
||||||
|
saveCommentRes(data.comment_view, this.state.personRes.comments);
|
||||||
|
this.setState(this.state);
|
||||||
|
} else if (
|
||||||
|
op == UserOperation.EditPost ||
|
||||||
|
op == UserOperation.DeletePost ||
|
||||||
|
op == UserOperation.RemovePost ||
|
||||||
|
op == UserOperation.LockPost ||
|
||||||
|
op == UserOperation.StickyPost ||
|
||||||
|
op == UserOperation.SavePost
|
||||||
|
) {
|
||||||
|
let data = wsJsonToRes<PostResponse>(msg).data;
|
||||||
|
editPostFindRes(data.post_view, this.state.personRes.posts);
|
||||||
|
this.setState(this.state);
|
||||||
|
} else if (op == UserOperation.CreatePostLike) {
|
||||||
|
let data = wsJsonToRes<PostResponse>(msg).data;
|
||||||
|
createPostLikeFindRes(data.post_view, this.state.personRes.posts);
|
||||||
|
this.setState(this.state);
|
||||||
|
} else if (op == UserOperation.BanPerson) {
|
||||||
|
let data = wsJsonToRes<BanPersonResponse>(msg).data;
|
||||||
|
this.state.personRes.comments
|
||||||
|
.filter(c => c.creator.id == data.person_view.person.id)
|
||||||
|
.forEach(c => (c.creator.banned = data.banned));
|
||||||
|
this.state.personRes.posts
|
||||||
|
.filter(c => c.creator.id == data.person_view.person.id)
|
||||||
|
.forEach(c => (c.creator.banned = data.banned));
|
||||||
|
this.setState(this.state);
|
||||||
|
} else if (op == UserOperation.BlockPerson) {
|
||||||
|
let data = wsJsonToRes<BlockPersonResponse>(msg).data;
|
||||||
|
updatePersonBlock(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
1118
src/shared/components/person/settings.tsx
Normal file
1118
src/shared/components/person/settings.tsx
Normal file
File diff suppressed because it is too large
Load diff
|
@ -51,7 +51,7 @@ export class CreatePost extends Component<any, CreatePostState> {
|
||||||
this.handlePostCreate = this.handlePostCreate.bind(this);
|
this.handlePostCreate = this.handlePostCreate.bind(this);
|
||||||
this.state = this.emptyState;
|
this.state = this.emptyState;
|
||||||
|
|
||||||
if (!UserService.Instance.localUserView && isBrowser()) {
|
if (!UserService.Instance.myUserInfo && isBrowser()) {
|
||||||
toast(i18n.t("not_logged_in"), "danger");
|
toast(i18n.t("not_logged_in"), "danger");
|
||||||
this.context.router.history.push(`/login`);
|
this.context.router.history.push(`/login`);
|
||||||
}
|
}
|
||||||
|
|
|
@ -194,7 +194,7 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
|
||||||
<label
|
<label
|
||||||
htmlFor="file-upload"
|
htmlFor="file-upload"
|
||||||
className={`${
|
className={`${
|
||||||
UserService.Instance.localUserView && "pointer"
|
UserService.Instance.myUserInfo && "pointer"
|
||||||
} d-inline-block float-right text-muted font-weight-bold`}
|
} d-inline-block float-right text-muted font-weight-bold`}
|
||||||
data-tippy-content={i18n.t("upload_image")}
|
data-tippy-content={i18n.t("upload_image")}
|
||||||
>
|
>
|
||||||
|
@ -206,7 +206,7 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
|
||||||
accept="image/*,video/*"
|
accept="image/*,video/*"
|
||||||
name="file"
|
name="file"
|
||||||
class="d-none"
|
class="d-none"
|
||||||
disabled={!UserService.Instance.localUserView}
|
disabled={!UserService.Instance.myUserInfo}
|
||||||
onChange={linkEvent(this, this.handleImageUpload)}
|
onChange={linkEvent(this, this.handleImageUpload)}
|
||||||
/>
|
/>
|
||||||
</form>
|
</form>
|
||||||
|
@ -601,7 +601,7 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
|
||||||
let data = wsJsonToRes<PostResponse>(msg).data;
|
let data = wsJsonToRes<PostResponse>(msg).data;
|
||||||
if (
|
if (
|
||||||
data.post_view.creator.id ==
|
data.post_view.creator.id ==
|
||||||
UserService.Instance.localUserView.person.id
|
UserService.Instance.myUserInfo.local_user_view.person.id
|
||||||
) {
|
) {
|
||||||
this.state.loading = false;
|
this.state.loading = false;
|
||||||
this.props.onCreate(data.post_view);
|
this.props.onCreate(data.post_view);
|
||||||
|
@ -610,7 +610,7 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
|
||||||
let data = wsJsonToRes<PostResponse>(msg).data;
|
let data = wsJsonToRes<PostResponse>(msg).data;
|
||||||
if (
|
if (
|
||||||
data.post_view.creator.id ==
|
data.post_view.creator.id ==
|
||||||
UserService.Instance.localUserView.person.id
|
UserService.Instance.myUserInfo.local_user_view.person.id
|
||||||
) {
|
) {
|
||||||
this.state.loading = false;
|
this.state.loading = false;
|
||||||
this.props.onEdit(data.post_view);
|
this.props.onEdit(data.post_view);
|
||||||
|
|
|
@ -5,6 +5,7 @@ import {
|
||||||
AddModToCommunity,
|
AddModToCommunity,
|
||||||
BanFromCommunity,
|
BanFromCommunity,
|
||||||
BanPerson,
|
BanPerson,
|
||||||
|
BlockPerson,
|
||||||
CommunityModeratorView,
|
CommunityModeratorView,
|
||||||
CreatePostLike,
|
CreatePostLike,
|
||||||
DeletePost,
|
DeletePost,
|
||||||
|
@ -285,6 +286,9 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
|
||||||
post_view.creator.banned) && (
|
post_view.creator.banned) && (
|
||||||
<span className="mx-1 badge badge-danger">{i18n.t("banned")}</span>
|
<span className="mx-1 badge badge-danger">{i18n.t("banned")}</span>
|
||||||
)}
|
)}
|
||||||
|
{post_view.creator_blocked && (
|
||||||
|
<span className="mx-1 badge badge-danger">{"blocked"}</span>
|
||||||
|
)}
|
||||||
{this.props.showCommunity && (
|
{this.props.showCommunity && (
|
||||||
<span>
|
<span>
|
||||||
<span class="mx-1"> {i18n.t("to")} </span>
|
<span class="mx-1"> {i18n.t("to")} </span>
|
||||||
|
@ -627,7 +631,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
|
||||||
postActions(mobile = false) {
|
postActions(mobile = false) {
|
||||||
let post_view = this.props.post_view;
|
let post_view = this.props.post_view;
|
||||||
return (
|
return (
|
||||||
UserService.Instance.localUserView && (
|
UserService.Instance.myUserInfo && (
|
||||||
<>
|
<>
|
||||||
{this.showBody && (
|
{this.showBody && (
|
||||||
<>
|
<>
|
||||||
|
@ -655,6 +659,16 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
|
||||||
>
|
>
|
||||||
<Icon icon="copy" classes="icon-inline" />
|
<Icon icon="copy" classes="icon-inline" />
|
||||||
</Link>
|
</Link>
|
||||||
|
{!this.myPost && (
|
||||||
|
<button
|
||||||
|
class="btn btn-link btn-animate text-muted py-0"
|
||||||
|
onClick={linkEvent(this, this.handleBlockUserClick)}
|
||||||
|
data-tippy-content={i18n.t("block_user")}
|
||||||
|
aria-label={i18n.t("block_user")}
|
||||||
|
>
|
||||||
|
<Icon icon="slash" classes="icon-inline" />
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
{this.myPost && this.showBody && (
|
{this.myPost && this.showBody && (
|
||||||
|
@ -1113,9 +1127,9 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
|
||||||
|
|
||||||
private get myPost(): boolean {
|
private get myPost(): boolean {
|
||||||
return (
|
return (
|
||||||
UserService.Instance.localUserView &&
|
UserService.Instance.myUserInfo &&
|
||||||
this.props.post_view.creator.id ==
|
this.props.post_view.creator.id ==
|
||||||
UserService.Instance.localUserView.person.id
|
UserService.Instance.myUserInfo.local_user_view.person.id
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1146,7 +1160,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
|
||||||
.concat(this.props.moderators.map(m => m.moderator.id));
|
.concat(this.props.moderators.map(m => m.moderator.id));
|
||||||
|
|
||||||
return canMod(
|
return canMod(
|
||||||
UserService.Instance.localUserView,
|
UserService.Instance.myUserInfo,
|
||||||
adminsThenMods,
|
adminsThenMods,
|
||||||
this.props.post_view.creator.id
|
this.props.post_view.creator.id
|
||||||
);
|
);
|
||||||
|
@ -1162,7 +1176,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
|
||||||
.concat(this.props.moderators.map(m => m.moderator.id));
|
.concat(this.props.moderators.map(m => m.moderator.id));
|
||||||
|
|
||||||
return canMod(
|
return canMod(
|
||||||
UserService.Instance.localUserView,
|
UserService.Instance.myUserInfo,
|
||||||
adminsThenMods,
|
adminsThenMods,
|
||||||
this.props.post_view.creator.id,
|
this.props.post_view.creator.id,
|
||||||
true
|
true
|
||||||
|
@ -1176,7 +1190,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
|
||||||
return (
|
return (
|
||||||
this.props.admins &&
|
this.props.admins &&
|
||||||
canMod(
|
canMod(
|
||||||
UserService.Instance.localUserView,
|
UserService.Instance.myUserInfo,
|
||||||
this.props.admins.map(a => a.person.id),
|
this.props.admins.map(a => a.person.id),
|
||||||
this.props.post_view.creator.id
|
this.props.post_view.creator.id
|
||||||
)
|
)
|
||||||
|
@ -1186,10 +1200,10 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
|
||||||
get amCommunityCreator(): boolean {
|
get amCommunityCreator(): boolean {
|
||||||
return (
|
return (
|
||||||
this.props.moderators &&
|
this.props.moderators &&
|
||||||
UserService.Instance.localUserView &&
|
UserService.Instance.myUserInfo &&
|
||||||
this.props.post_view.creator.id !=
|
this.props.post_view.creator.id !=
|
||||||
UserService.Instance.localUserView.person.id &&
|
UserService.Instance.myUserInfo.local_user_view.person.id &&
|
||||||
UserService.Instance.localUserView.person.id ==
|
UserService.Instance.myUserInfo.local_user_view.person.id ==
|
||||||
this.props.moderators[0].moderator.id
|
this.props.moderators[0].moderator.id
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1197,17 +1211,17 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
|
||||||
get amSiteCreator(): boolean {
|
get amSiteCreator(): boolean {
|
||||||
return (
|
return (
|
||||||
this.props.admins &&
|
this.props.admins &&
|
||||||
UserService.Instance.localUserView &&
|
UserService.Instance.myUserInfo &&
|
||||||
this.props.post_view.creator.id !=
|
this.props.post_view.creator.id !=
|
||||||
UserService.Instance.localUserView.person.id &&
|
UserService.Instance.myUserInfo.local_user_view.person.id &&
|
||||||
UserService.Instance.localUserView.person.id ==
|
UserService.Instance.myUserInfo.local_user_view.person.id ==
|
||||||
this.props.admins[0].person.id
|
this.props.admins[0].person.id
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
handlePostLike(i: PostListing, event: any) {
|
handlePostLike(i: PostListing, event: any) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
if (!UserService.Instance.localUserView) {
|
if (!UserService.Instance.myUserInfo) {
|
||||||
this.context.router.history.push(`/login`);
|
this.context.router.history.push(`/login`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1240,7 +1254,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
|
||||||
|
|
||||||
handlePostDisLike(i: PostListing, event: any) {
|
handlePostDisLike(i: PostListing, event: any) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
if (!UserService.Instance.localUserView) {
|
if (!UserService.Instance.myUserInfo) {
|
||||||
this.context.router.history.push(`/login`);
|
this.context.router.history.push(`/login`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1287,6 +1301,15 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
|
||||||
this.setState(this.state);
|
this.setState(this.state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
handleBlockUserClick(i: PostListing) {
|
||||||
|
let blockUserForm: BlockPerson = {
|
||||||
|
person_id: i.props.post_view.creator.id,
|
||||||
|
block: true,
|
||||||
|
auth: authField(),
|
||||||
|
};
|
||||||
|
WebSocketService.Instance.send(wsClient.blockPerson(blockUserForm));
|
||||||
|
}
|
||||||
|
|
||||||
handleDeleteClick(i: PostListing) {
|
handleDeleteClick(i: PostListing) {
|
||||||
let deleteForm: DeletePost = {
|
let deleteForm: DeletePost = {
|
||||||
post_id: i.props.post_view.post.id,
|
post_id: i.props.post_view.post.id,
|
||||||
|
|
|
@ -5,6 +5,7 @@ import {
|
||||||
AddModToCommunityResponse,
|
AddModToCommunityResponse,
|
||||||
BanFromCommunityResponse,
|
BanFromCommunityResponse,
|
||||||
BanPersonResponse,
|
BanPersonResponse,
|
||||||
|
BlockPersonResponse,
|
||||||
CommentResponse,
|
CommentResponse,
|
||||||
CommunityResponse,
|
CommunityResponse,
|
||||||
GetCommunityResponse,
|
GetCommunityResponse,
|
||||||
|
@ -50,6 +51,7 @@ import {
|
||||||
setOptionalAuth,
|
setOptionalAuth,
|
||||||
setupTippy,
|
setupTippy,
|
||||||
toast,
|
toast,
|
||||||
|
updatePersonBlock,
|
||||||
wsClient,
|
wsClient,
|
||||||
wsJsonToRes,
|
wsJsonToRes,
|
||||||
wsSubscribe,
|
wsSubscribe,
|
||||||
|
@ -237,8 +239,9 @@ export class Post extends Component<any, PostState> {
|
||||||
: this.state.postRes.post_view.creator.id;
|
: this.state.postRes.post_view.creator.id;
|
||||||
|
|
||||||
if (
|
if (
|
||||||
UserService.Instance.localUserView &&
|
UserService.Instance.myUserInfo &&
|
||||||
UserService.Instance.localUserView.person.id == parent_person_id
|
UserService.Instance.myUserInfo.local_user_view.person.id ==
|
||||||
|
parent_person_id
|
||||||
) {
|
) {
|
||||||
let form: MarkCommentAsRead = {
|
let form: MarkCommentAsRead = {
|
||||||
comment_id: found.comment.id,
|
comment_id: found.comment.id,
|
||||||
|
@ -617,6 +620,9 @@ export class Post extends Component<any, PostState> {
|
||||||
this.state.postRes.post_view.community = data.community_view.community;
|
this.state.postRes.post_view.community = data.community_view.community;
|
||||||
this.state.postRes.moderators = data.moderators;
|
this.state.postRes.moderators = data.moderators;
|
||||||
this.setState(this.state);
|
this.setState(this.state);
|
||||||
|
} else if (op == UserOperation.BlockPerson) {
|
||||||
|
let data = wsJsonToRes<BlockPersonResponse>(msg).data;
|
||||||
|
updatePersonBlock(data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,7 +54,7 @@ export class CreatePrivateMessage extends Component<
|
||||||
this.parseMessage = this.parseMessage.bind(this);
|
this.parseMessage = this.parseMessage.bind(this);
|
||||||
this.subscription = wsSubscribe(this.parseMessage);
|
this.subscription = wsSubscribe(this.parseMessage);
|
||||||
|
|
||||||
if (!UserService.Instance.localUserView) {
|
if (!UserService.Instance.myUserInfo) {
|
||||||
toast(i18n.t("not_logged_in"), "danger");
|
toast(i18n.t("not_logged_in"), "danger");
|
||||||
this.context.router.history.push(`/login`);
|
this.context.router.history.push(`/login`);
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,8 +47,8 @@ export class PrivateMessage extends Component<
|
||||||
|
|
||||||
get mine(): boolean {
|
get mine(): boolean {
|
||||||
return (
|
return (
|
||||||
UserService.Instance.localUserView &&
|
UserService.Instance.myUserInfo &&
|
||||||
UserService.Instance.localUserView.person.id ==
|
UserService.Instance.myUserInfo.local_user_view.person.id ==
|
||||||
this.props.private_message_view.creator.id
|
this.props.private_message_view.creator.id
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -272,8 +272,9 @@ export class PrivateMessage extends Component<
|
||||||
|
|
||||||
handlePrivateMessageCreate(message: PrivateMessageView) {
|
handlePrivateMessageCreate(message: PrivateMessageView) {
|
||||||
if (
|
if (
|
||||||
UserService.Instance.localUserView &&
|
UserService.Instance.myUserInfo &&
|
||||||
message.creator.id == UserService.Instance.localUserView.person.id
|
message.creator.id ==
|
||||||
|
UserService.Instance.myUserInfo.local_user_view.person.id
|
||||||
) {
|
) {
|
||||||
this.state.showReply = false;
|
this.state.showReply = false;
|
||||||
this.setState(this.state);
|
this.setState(this.state);
|
||||||
|
|
|
@ -10,7 +10,8 @@ import { PasswordChange } from "./components/home/password_change";
|
||||||
import { Setup } from "./components/home/setup";
|
import { Setup } from "./components/home/setup";
|
||||||
import { Modlog } from "./components/modlog";
|
import { Modlog } from "./components/modlog";
|
||||||
import { Inbox } from "./components/person/inbox";
|
import { Inbox } from "./components/person/inbox";
|
||||||
import { Person } from "./components/person/person";
|
import { Profile } from "./components/person/profile";
|
||||||
|
import { Settings } from "./components/person/settings";
|
||||||
import { CreatePost } from "./components/post/create-post";
|
import { CreatePost } from "./components/post/create-post";
|
||||||
import { Post } from "./components/post/post";
|
import { Post } from "./components/post/post";
|
||||||
import { CreatePrivateMessage } from "./components/private_message/create-private-message";
|
import { CreatePrivateMessage } from "./components/private_message/create-private-message";
|
||||||
|
@ -83,19 +84,23 @@ export const routes: IRoutePropsWithFetch[] = [
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: `/u/:username/view/:view/sort/:sort/page/:page`,
|
path: `/u/:username/view/:view/sort/:sort/page/:page`,
|
||||||
component: Person,
|
component: Profile,
|
||||||
fetchInitialData: req => Person.fetchInitialData(req),
|
fetchInitialData: req => Profile.fetchInitialData(req),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: `/u/:username`,
|
path: `/u/:username`,
|
||||||
component: Person,
|
component: Profile,
|
||||||
fetchInitialData: req => Person.fetchInitialData(req),
|
fetchInitialData: req => Profile.fetchInitialData(req),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: `/inbox`,
|
path: `/inbox`,
|
||||||
component: Inbox,
|
component: Inbox,
|
||||||
fetchInitialData: req => Inbox.fetchInitialData(req),
|
fetchInitialData: req => Inbox.fetchInitialData(req),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: `/settings`,
|
||||||
|
component: Settings,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: `/modlog/community/:community_id`,
|
path: `/modlog/community/:community_id`,
|
||||||
component: Modlog,
|
component: Modlog,
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
// import Cookies from 'js-cookie';
|
// import Cookies from 'js-cookie';
|
||||||
import IsomorphicCookie from "isomorphic-cookie";
|
import IsomorphicCookie from "isomorphic-cookie";
|
||||||
import jwt_decode from "jwt-decode";
|
import jwt_decode from "jwt-decode";
|
||||||
import { LocalUserSettingsView, LoginResponse } from "lemmy-js-client";
|
import { LoginResponse, MyUserInfo } from "lemmy-js-client";
|
||||||
import { BehaviorSubject, Subject } from "rxjs";
|
import { BehaviorSubject, Subject } from "rxjs";
|
||||||
|
|
||||||
interface Claims {
|
interface Claims {
|
||||||
|
@ -12,7 +12,7 @@ interface Claims {
|
||||||
|
|
||||||
export class UserService {
|
export class UserService {
|
||||||
private static _instance: UserService;
|
private static _instance: UserService;
|
||||||
public localUserView: LocalUserSettingsView;
|
public myUserInfo: MyUserInfo;
|
||||||
public claims: Claims;
|
public claims: Claims;
|
||||||
public jwtSub: Subject<string> = new Subject<string>();
|
public jwtSub: Subject<string> = new Subject<string>();
|
||||||
public unreadCountSub: BehaviorSubject<number> = new BehaviorSubject<number>(
|
public unreadCountSub: BehaviorSubject<number> = new BehaviorSubject<number>(
|
||||||
|
@ -39,7 +39,7 @@ export class UserService {
|
||||||
public logout() {
|
public logout() {
|
||||||
IsomorphicCookie.remove("jwt", { secure: false });
|
IsomorphicCookie.remove("jwt", { secure: false });
|
||||||
this.claims = undefined;
|
this.claims = undefined;
|
||||||
this.localUserView = undefined;
|
this.myUserInfo = undefined;
|
||||||
// setTheme();
|
// setTheme();
|
||||||
this.jwtSub.next("");
|
this.jwtSub.next("");
|
||||||
console.log("Logged out.");
|
console.log("Logged out.");
|
||||||
|
|
|
@ -1,13 +1,17 @@
|
||||||
import emojiShortName from "emoji-short-name";
|
import emojiShortName from "emoji-short-name";
|
||||||
import {
|
import {
|
||||||
|
BlockCommunityResponse,
|
||||||
|
BlockPersonResponse,
|
||||||
CommentView,
|
CommentView,
|
||||||
|
CommunityBlockView,
|
||||||
CommunityView,
|
CommunityView,
|
||||||
GetSiteMetadata,
|
GetSiteMetadata,
|
||||||
GetSiteResponse,
|
GetSiteResponse,
|
||||||
LemmyHttp,
|
LemmyHttp,
|
||||||
LemmyWebsocket,
|
LemmyWebsocket,
|
||||||
ListingType,
|
ListingType,
|
||||||
LocalUserSettingsView,
|
MyUserInfo,
|
||||||
|
PersonBlockView,
|
||||||
PersonViewSafe,
|
PersonViewSafe,
|
||||||
PostView,
|
PostView,
|
||||||
PrivateMessageView,
|
PrivateMessageView,
|
||||||
|
@ -249,14 +253,16 @@ export function getUnixTime(text: string): number {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function canMod(
|
export function canMod(
|
||||||
localUserView: LocalUserSettingsView,
|
myUserInfo: MyUserInfo,
|
||||||
modIds: number[],
|
modIds: number[],
|
||||||
creator_id: number,
|
creator_id: number,
|
||||||
onSelf = false
|
onSelf = false
|
||||||
): boolean {
|
): boolean {
|
||||||
// You can do moderator actions only on the mods added after you.
|
// You can do moderator actions only on the mods added after you.
|
||||||
if (localUserView) {
|
if (myUserInfo) {
|
||||||
let yourIndex = modIds.findIndex(id => id == localUserView.person.id);
|
let yourIndex = modIds.findIndex(
|
||||||
|
id => id == myUserInfo.local_user_view.person.id
|
||||||
|
);
|
||||||
if (yourIndex == -1) {
|
if (yourIndex == -1) {
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
|
@ -380,11 +386,11 @@ export function debounce(func: any, wait = 1000, immediate = false) {
|
||||||
|
|
||||||
// TODO
|
// TODO
|
||||||
export function getLanguage(override?: string): string {
|
export function getLanguage(override?: string): string {
|
||||||
let localUserView = UserService.Instance.localUserView;
|
let myUserInfo = UserService.Instance.myUserInfo;
|
||||||
let lang =
|
let lang =
|
||||||
override ||
|
override ||
|
||||||
(localUserView?.local_user.lang
|
(myUserInfo?.local_user_view.local_user.lang
|
||||||
? localUserView.local_user.lang
|
? myUserInfo.local_user_view.local_user.lang
|
||||||
: "browser");
|
: "browser");
|
||||||
|
|
||||||
if (lang == "browser" && isBrowser()) {
|
if (lang == "browser" && isBrowser()) {
|
||||||
|
@ -537,15 +543,15 @@ export function objectFlip(obj: any) {
|
||||||
|
|
||||||
export function showAvatars(): boolean {
|
export function showAvatars(): boolean {
|
||||||
return (
|
return (
|
||||||
UserService.Instance.localUserView?.local_user.show_avatars ||
|
UserService.Instance.myUserInfo?.local_user_view.local_user.show_avatars ||
|
||||||
!UserService.Instance.localUserView
|
!UserService.Instance.myUserInfo
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function showScores(): boolean {
|
export function showScores(): boolean {
|
||||||
return (
|
return (
|
||||||
UserService.Instance.localUserView?.local_user.show_scores ||
|
UserService.Instance.myUserInfo?.local_user_view.local_user.show_scores ||
|
||||||
!UserService.Instance.localUserView
|
!UserService.Instance.myUserInfo
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -850,9 +856,10 @@ function communitySearch(
|
||||||
export function getListingTypeFromProps(props: any): ListingType {
|
export function getListingTypeFromProps(props: any): ListingType {
|
||||||
return props.match.params.listing_type
|
return props.match.params.listing_type
|
||||||
? routeListingTypeToEnum(props.match.params.listing_type)
|
? routeListingTypeToEnum(props.match.params.listing_type)
|
||||||
: UserService.Instance.localUserView
|
: UserService.Instance.myUserInfo
|
||||||
? Object.values(ListingType)[
|
? Object.values(ListingType)[
|
||||||
UserService.Instance.localUserView.local_user.default_listing_type
|
UserService.Instance.myUserInfo.local_user_view.local_user
|
||||||
|
.default_listing_type
|
||||||
]
|
]
|
||||||
: ListingType.Local;
|
: ListingType.Local;
|
||||||
}
|
}
|
||||||
|
@ -873,9 +880,10 @@ export function getDataTypeFromProps(props: any): DataType {
|
||||||
export function getSortTypeFromProps(props: any): SortType {
|
export function getSortTypeFromProps(props: any): SortType {
|
||||||
return props.match.params.sort
|
return props.match.params.sort
|
||||||
? routeSortTypeToEnum(props.match.params.sort)
|
? routeSortTypeToEnum(props.match.params.sort)
|
||||||
: UserService.Instance.localUserView
|
: UserService.Instance.myUserInfo
|
||||||
? Object.values(SortType)[
|
? Object.values(SortType)[
|
||||||
UserService.Instance.localUserView.local_user.default_sort_type
|
UserService.Instance.myUserInfo.local_user_view.local_user
|
||||||
|
.default_sort_type
|
||||||
]
|
]
|
||||||
: SortType.Active;
|
: SortType.Active;
|
||||||
}
|
}
|
||||||
|
@ -922,6 +930,44 @@ export function saveCommentRes(data: CommentView, comments: CommentView[]) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function updatePersonBlock(
|
||||||
|
data: BlockPersonResponse
|
||||||
|
): PersonBlockView[] {
|
||||||
|
if (data.blocked) {
|
||||||
|
UserService.Instance.myUserInfo.person_blocks.push({
|
||||||
|
person: UserService.Instance.myUserInfo.local_user_view.person,
|
||||||
|
target: data.person_view.person,
|
||||||
|
});
|
||||||
|
toast(`${i18n.t("blocked")} ${data.person_view.person.name}`);
|
||||||
|
} else {
|
||||||
|
UserService.Instance.myUserInfo.person_blocks =
|
||||||
|
UserService.Instance.myUserInfo.person_blocks.filter(
|
||||||
|
i => i.target.id != data.person_view.person.id
|
||||||
|
);
|
||||||
|
toast(`${i18n.t("unblocked")} ${data.person_view.person.name}`);
|
||||||
|
}
|
||||||
|
return UserService.Instance.myUserInfo.person_blocks;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function updateCommunityBlock(
|
||||||
|
data: BlockCommunityResponse
|
||||||
|
): CommunityBlockView[] {
|
||||||
|
if (data.blocked) {
|
||||||
|
UserService.Instance.myUserInfo.community_blocks.push({
|
||||||
|
person: UserService.Instance.myUserInfo.local_user_view.person,
|
||||||
|
community: data.community_view.community,
|
||||||
|
});
|
||||||
|
toast(`${i18n.t("blocked")} ${data.community_view.community.name}`);
|
||||||
|
} else {
|
||||||
|
UserService.Instance.myUserInfo.community_blocks =
|
||||||
|
UserService.Instance.myUserInfo.community_blocks.filter(
|
||||||
|
i => i.community.id != data.community_view.community.id
|
||||||
|
);
|
||||||
|
toast(`${i18n.t("unblocked")} ${data.community_view.community.name}`);
|
||||||
|
}
|
||||||
|
return UserService.Instance.myUserInfo.community_blocks;
|
||||||
|
}
|
||||||
|
|
||||||
export function createCommentLikeRes(
|
export function createCommentLikeRes(
|
||||||
data: CommentView,
|
data: CommentView,
|
||||||
comments: CommentView[]
|
comments: CommentView[]
|
||||||
|
@ -1065,9 +1111,13 @@ export function buildCommentsTree(
|
||||||
let tree: CommentNodeI[] = [];
|
let tree: CommentNodeI[] = [];
|
||||||
for (let comment_view of comments) {
|
for (let comment_view of comments) {
|
||||||
let child = map.get(comment_view.comment.id);
|
let child = map.get(comment_view.comment.id);
|
||||||
if (comment_view.comment.parent_id) {
|
let parent_id = comment_view.comment.parent_id;
|
||||||
let parent_ = map.get(comment_view.comment.parent_id);
|
if (parent_id) {
|
||||||
parent_.children.push(child);
|
let parent = map.get(parent_id);
|
||||||
|
// Necessary because blocked comment might not exist
|
||||||
|
if (parent) {
|
||||||
|
parent.children.push(child);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
tree.push(child);
|
tree.push(child);
|
||||||
}
|
}
|
||||||
|
@ -1315,14 +1365,14 @@ export const choicesConfig = {
|
||||||
searchResultLimit: fetchLimit,
|
searchResultLimit: fetchLimit,
|
||||||
classNames: {
|
classNames: {
|
||||||
containerOuter: "choices",
|
containerOuter: "choices",
|
||||||
containerInner: "choices__inner bg-light border-0",
|
containerInner: "choices__inner bg-secondary border-0",
|
||||||
input: "form-control",
|
input: "form-control",
|
||||||
inputCloned: "choices__input--cloned",
|
inputCloned: "choices__input--cloned",
|
||||||
list: "choices__list",
|
list: "choices__list",
|
||||||
listItems: "choices__list--multiple",
|
listItems: "choices__list--multiple",
|
||||||
listSingle: "choices__list--single",
|
listSingle: "choices__list--single",
|
||||||
listDropdown: "choices__list--dropdown",
|
listDropdown: "choices__list--dropdown",
|
||||||
item: "choices__item bg-light",
|
item: "choices__item bg-secondary",
|
||||||
itemSelectable: "choices__item--selectable",
|
itemSelectable: "choices__item--selectable",
|
||||||
itemDisabled: "choices__item--disabled",
|
itemDisabled: "choices__item--disabled",
|
||||||
itemChoice: "choices__item--choice",
|
itemChoice: "choices__item--choice",
|
||||||
|
@ -1356,6 +1406,6 @@ export function personSelectName(pvs: PersonViewSafe): string {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function initializeSite(site: GetSiteResponse) {
|
export function initializeSite(site: GetSiteResponse) {
|
||||||
UserService.Instance.localUserView = site.my_user;
|
UserService.Instance.myUserInfo = site.my_user;
|
||||||
i18n.changeLanguage(getLanguage());
|
i18n.changeLanguage(getLanguage());
|
||||||
}
|
}
|
||||||
|
|
14
yarn.lock
14
yarn.lock
|
@ -2863,9 +2863,9 @@ ee-first@1.1.1:
|
||||||
integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=
|
integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=
|
||||||
|
|
||||||
electron-to-chromium@^1.3.811:
|
electron-to-chromium@^1.3.811:
|
||||||
version "1.3.812"
|
version "1.3.813"
|
||||||
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.812.tgz#4c4fb407e0e1335056097f172e9f2c0a09efe77d"
|
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.813.tgz#751a007d71c00faed8b5e9edaf3634c14b9c5a1f"
|
||||||
integrity sha512-7KiUHsKAWtSrjVoTSzxQ0nPLr/a+qoxNZwkwd9LkylTOgOXSVXkQbpIVT0WAUQcI5gXq3SwOTCrK+WfINHOXQg==
|
integrity sha512-YcSRImHt6JZZ2sSuQ4Bzajtk98igQ0iKkksqlzZLzbh4p0OIyJRSvUbsgqfcR8txdfsoYCc4ym306t4p2kP/aw==
|
||||||
|
|
||||||
emoji-regex@^7.0.1:
|
emoji-regex@^7.0.1:
|
||||||
version "7.0.3"
|
version "7.0.3"
|
||||||
|
@ -4996,10 +4996,10 @@ lcid@^1.0.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
invert-kv "^1.0.0"
|
invert-kv "^1.0.0"
|
||||||
|
|
||||||
lemmy-js-client@0.11.4-rc.12:
|
lemmy-js-client@0.11.4-rc.14:
|
||||||
version "0.11.4-rc.12"
|
version "0.11.4-rc.14"
|
||||||
resolved "https://registry.yarnpkg.com/lemmy-js-client/-/lemmy-js-client-0.11.4-rc.12.tgz#a238da35dbde18c9fc8f6f14cb6849d541d0051b"
|
resolved "https://registry.yarnpkg.com/lemmy-js-client/-/lemmy-js-client-0.11.4-rc.14.tgz#dcac5b8dc78c3b04e6b3630ff9351a94aa73e109"
|
||||||
integrity sha512-PzIFA/Q2j8i0ZXOWo0u/rR/RTt97v+G8a8jObHplq8UyyI3EzNIWZ5AS9514H5AoCIAMcDbwP4c/CQPiYf8yhA==
|
integrity sha512-R8M+myyriNQljQlTweVqtUKGBpgmaM7RI4ebYb7N7sYr5Bk5Ip6v2qTNvKAV6BlsDOCTWANOonfeoz/cIerLEg==
|
||||||
|
|
||||||
levn@^0.4.1:
|
levn@^0.4.1:
|
||||||
version "0.4.1"
|
version "0.4.1"
|
||||||
|
|
Loading…
Reference in a new issue