mirror of
https://github.com/LemmyNet/lemmy-ui.git
synced 2024-11-27 00:09:38 +00:00
About 1/3rd done with adding redux.
This commit is contained in:
parent
fc234716b0
commit
4298c3fb91
|
@ -43,6 +43,7 @@
|
|||
"@babel/preset-typescript": "^7.21.5",
|
||||
"@babel/runtime": "^7.21.5",
|
||||
"@emoji-mart/data": "^1.1.0",
|
||||
"@reduxjs/toolkit": "^2.0.1",
|
||||
"@shortcm/qr-image": "^9.0.2",
|
||||
"autosize": "^6.0.1",
|
||||
"babel-loader": "^9.1.3",
|
||||
|
@ -67,6 +68,7 @@
|
|||
"inferno-helmet": "^5.2.1",
|
||||
"inferno-hydrate": "^8.2.2",
|
||||
"inferno-i18next-dess": "0.0.2",
|
||||
"inferno-redux": "^8.2.2",
|
||||
"inferno-router": "^8.2.2",
|
||||
"inferno-server": "^8.2.2",
|
||||
"jwt-decode": "^4.0.0",
|
||||
|
@ -83,6 +85,7 @@
|
|||
"markdown-it-sub": "^1.0.0",
|
||||
"markdown-it-sup": "^1.0.0",
|
||||
"mini-css-extract-plugin": "^2.7.5",
|
||||
"redux": "^5.0.0",
|
||||
"register-service-worker": "^1.7.2",
|
||||
"run-node-webpack-plugin": "^1.3.0",
|
||||
"rxjs": "^7.8.1",
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { initializeSite, setupDateFns } from "@utils/app";
|
||||
import { initializeSite, setupDateFns, setupRedux } from "@utils/app";
|
||||
import { hydrate } from "inferno-hydrate";
|
||||
import { BrowserRouter } from "inferno-router";
|
||||
import { App } from "../shared/components/app/app";
|
||||
|
@ -6,16 +6,24 @@ import { App } from "../shared/components/app/app";
|
|||
import "bootstrap/js/dist/collapse";
|
||||
import "bootstrap/js/dist/dropdown";
|
||||
import "bootstrap/js/dist/modal";
|
||||
import { Provider } from "inferno-redux";
|
||||
|
||||
async function startClient() {
|
||||
initializeSite(window.isoData.site_res);
|
||||
const windowData = window.isoData;
|
||||
delete window.isoData;
|
||||
|
||||
initializeSite(windowData?.site_res);
|
||||
|
||||
await setupDateFns();
|
||||
|
||||
const store = setupRedux(windowData);
|
||||
|
||||
const wrapper = (
|
||||
<BrowserRouter>
|
||||
<App />
|
||||
</BrowserRouter>
|
||||
<Provider store={store}>
|
||||
<BrowserRouter>
|
||||
<App />
|
||||
</BrowserRouter>
|
||||
</Provider>
|
||||
);
|
||||
|
||||
const root = document.getElementById("root");
|
||||
|
|
|
@ -20,6 +20,8 @@ import { createSsrHtml } from "../utils/create-ssr-html";
|
|||
import { getErrorPageData } from "../utils/get-error-page-data";
|
||||
import { setForwardedHeaders } from "../utils/set-forwarded-headers";
|
||||
import { getJwtCookie } from "../utils/has-jwt-cookie";
|
||||
import { Provider } from "inferno-redux";
|
||||
import { configureStore, createSlice } from "@reduxjs/toolkit";
|
||||
|
||||
export default async (req: Request, res: Response) => {
|
||||
try {
|
||||
|
@ -108,10 +110,19 @@ export default async (req: Request, res: Response) => {
|
|||
errorPageData,
|
||||
};
|
||||
|
||||
const slice = createSlice({
|
||||
name: "isoData",
|
||||
initialState: { value: isoData },
|
||||
reducers: {},
|
||||
});
|
||||
const store = configureStore({ reducer: slice.reducer });
|
||||
|
||||
const wrapper = (
|
||||
<StaticRouter location={url} context={isoData}>
|
||||
<App />
|
||||
</StaticRouter>
|
||||
<Provider store={store}>
|
||||
<StaticRouter location={url} context={{}}>
|
||||
<App />
|
||||
</StaticRouter>
|
||||
</Provider>
|
||||
);
|
||||
|
||||
const root = renderToString(wrapper);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { isAnonymousPath, isAuthPath, setIsoData } from "@utils/app";
|
||||
import { isAnonymousPath, isAuthPath } from "@utils/app";
|
||||
import { dataBsTheme } from "@utils/browser";
|
||||
import { Component, RefObject, createRef, linkEvent } from "inferno";
|
||||
import { Provider } from "inferno-i18next-dess";
|
||||
|
@ -17,20 +17,20 @@ import AnonymousGuard from "../common/anonymous-guard";
|
|||
import { CodeTheme } from "./code-theme";
|
||||
|
||||
export class App extends Component<any, any> {
|
||||
private isoData: IsoDataOptionalSite = setIsoData(this.context);
|
||||
private readonly mainContentRef: RefObject<HTMLElement>;
|
||||
constructor(props: any, context: any) {
|
||||
super(props, context);
|
||||
this.mainContentRef = createRef();
|
||||
}
|
||||
|
||||
handleJumpToContent(event) {
|
||||
handleJumpToContent(event: any) {
|
||||
event.preventDefault();
|
||||
this.mainContentRef.current?.focus();
|
||||
}
|
||||
|
||||
render() {
|
||||
const siteRes = this.isoData.site_res;
|
||||
const reduxState: IsoDataOptionalSite = this.context.store.getState().value;
|
||||
const siteRes = reduxState.site_res;
|
||||
const siteView = siteRes?.site_view;
|
||||
|
||||
return (
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import { setIsoData } from "@utils/app";
|
||||
import { Component } from "inferno";
|
||||
import { T } from "inferno-i18next-dess";
|
||||
import { Link } from "inferno-router";
|
||||
|
@ -6,14 +5,13 @@ import { IsoDataOptionalSite } from "../../interfaces";
|
|||
import { I18NextService } from "../../services";
|
||||
|
||||
export class ErrorPage extends Component<any, any> {
|
||||
private isoData: IsoDataOptionalSite = setIsoData(this.context);
|
||||
|
||||
constructor(props: any, context: any) {
|
||||
super(props, context);
|
||||
}
|
||||
|
||||
render() {
|
||||
const { errorPageData } = this.isoData;
|
||||
const reduxState: IsoDataOptionalSite = this.context.store.getState();
|
||||
const errorPageData = reduxState.errorPageData;
|
||||
|
||||
return (
|
||||
<div className="error-page container-lg text-center">
|
||||
|
@ -41,8 +39,7 @@ export class ErrorPage extends Component<any, any> {
|
|||
<div>
|
||||
{I18NextService.i18n.t("error_page_admin_matrix", {
|
||||
instance:
|
||||
this.isoData.site_res?.site_view.site.name ??
|
||||
"this instance",
|
||||
reduxState.site_res?.site_view.site.name ?? "this instance",
|
||||
})}
|
||||
</div>
|
||||
<ul className="mx-auto mt-2" style={{ width: "fit-content" }}>
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
import { showAvatars } from "@utils/app";
|
||||
import { isBrowser } from "@utils/browser";
|
||||
import { numToSI } from "@utils/helpers";
|
||||
import { amAdmin, canCreateCommunity } from "@utils/roles";
|
||||
import { amAdmin, canCreateCommunity, moderatesSomething } from "@utils/roles";
|
||||
import { Component, createRef, linkEvent } from "inferno";
|
||||
import { NavLink } from "inferno-router";
|
||||
import { GetSiteResponse } from "lemmy-js-client";
|
||||
import { donateLemmyUrl } from "../../config";
|
||||
import {
|
||||
I18NextService,
|
||||
UserService,
|
||||
UnreadCounterService,
|
||||
HttpService,
|
||||
} from "../../services";
|
||||
import { toast } from "../../toast";
|
||||
import { Icon } from "../common/icon";
|
||||
|
@ -38,7 +38,7 @@ function handleCollapseClick(i: Navbar) {
|
|||
}
|
||||
|
||||
function handleLogOut(i: Navbar) {
|
||||
UserService.Instance.logout();
|
||||
HttpService._Instance.logout();
|
||||
handleCollapseClick(i);
|
||||
}
|
||||
|
||||
|
@ -94,7 +94,7 @@ export class Navbar extends Component<NavbarProps, NavbarState> {
|
|||
// TODO class active corresponding to current pages
|
||||
render() {
|
||||
const siteView = this.props.siteRes?.site_view;
|
||||
const person = UserService.Instance.myUserInfo?.local_user_view.person;
|
||||
const person = this.props.siteRes?.my_user?.local_user_view.person;
|
||||
return (
|
||||
<div className="shadow-sm">
|
||||
<nav
|
||||
|
@ -108,9 +108,10 @@ export class Navbar extends Component<NavbarProps, NavbarState> {
|
|||
className="d-flex align-items-center navbar-brand me-md-3"
|
||||
onMouseUp={linkEvent(this, handleCollapseClick)}
|
||||
>
|
||||
{siteView?.site.icon && showAvatars() && (
|
||||
<PictrsImage src={siteView.site.icon} icon />
|
||||
)}
|
||||
{siteView?.site.icon &&
|
||||
showAvatars(this.props.siteRes?.my_user) && (
|
||||
<PictrsImage src={siteView.site.icon} icon />
|
||||
)}
|
||||
{siteView?.site.name}
|
||||
</NavLink>
|
||||
{person && (
|
||||
|
@ -133,7 +134,7 @@ export class Navbar extends Component<NavbarProps, NavbarState> {
|
|||
)}
|
||||
</NavLink>
|
||||
</li>
|
||||
{UserService.Instance.moderatesSomething && (
|
||||
{moderatesSomething(this.props.siteRes?.my_user) && (
|
||||
<li className="nav-item nav-item-icon">
|
||||
<NavLink
|
||||
to="/reports"
|
||||
|
@ -306,7 +307,7 @@ export class Navbar extends Component<NavbarProps, NavbarState> {
|
|||
)}
|
||||
</NavLink>
|
||||
</li>
|
||||
{UserService.Instance.moderatesSomething && (
|
||||
{moderatesSomething(this.props.siteRes?.my_user) && (
|
||||
<li id="navModeration" className="nav-item">
|
||||
<NavLink
|
||||
className="nav-link d-inline-flex align-items-center d-md-inline-block"
|
||||
|
@ -467,7 +468,7 @@ export class Navbar extends Component<NavbarProps, NavbarState> {
|
|||
}
|
||||
|
||||
requestNotificationPermission() {
|
||||
if (UserService.Instance.myUserInfo) {
|
||||
if (this.props.siteRes?.my_user) {
|
||||
document.addEventListener("DOMContentLoaded", function () {
|
||||
if (!Notification) {
|
||||
toast(I18NextService.i18n.t("notifications_error"), "danger");
|
||||
|
|
|
@ -1,14 +1,15 @@
|
|||
import { Component } from "inferno";
|
||||
import { Helmet } from "inferno-helmet";
|
||||
import { UserService } from "../../services";
|
||||
import { MyUserInfo } from "lemmy-js-client";
|
||||
|
||||
interface Props {
|
||||
defaultTheme: string;
|
||||
myUserInfo?: MyUserInfo;
|
||||
}
|
||||
|
||||
export class Theme extends Component<Props> {
|
||||
render() {
|
||||
const user = UserService.Instance.myUserInfo;
|
||||
const user = this.props.myUserInfo;
|
||||
const hasTheme = user?.local_user_view.local_user.theme !== "browser";
|
||||
|
||||
if (user && hasTheme) {
|
||||
|
|
|
@ -4,7 +4,7 @@ import { T } from "inferno-i18next-dess";
|
|||
import { Link } from "inferno-router";
|
||||
import { CreateComment, EditComment, Language } from "lemmy-js-client";
|
||||
import { CommentNodeI } from "../../interfaces";
|
||||
import { I18NextService, UserService } from "../../services";
|
||||
import { I18NextService } from "../../services";
|
||||
import { Icon } from "../common/icon";
|
||||
import { MarkdownTextArea } from "../common/markdown-textarea";
|
||||
|
||||
|
@ -13,6 +13,7 @@ interface CommentFormProps {
|
|||
* Can either be the parent, or the editable comment. The right side is a postId.
|
||||
*/
|
||||
node: CommentNodeI | number;
|
||||
loggedIn: boolean;
|
||||
finished?: boolean;
|
||||
edit?: boolean;
|
||||
disabled?: boolean;
|
||||
|
@ -45,7 +46,7 @@ export class CommentForm extends Component<CommentFormProps, any> {
|
|||
" ",
|
||||
)}
|
||||
>
|
||||
{UserService.Instance.myUserInfo ? (
|
||||
{this.props.loggedIn ? (
|
||||
<MarkdownTextArea
|
||||
initialContent={initialContent}
|
||||
showLanguage
|
||||
|
|
|
@ -27,6 +27,7 @@ import {
|
|||
Language,
|
||||
MarkCommentReplyAsRead,
|
||||
MarkPersonMentionAsRead,
|
||||
MyUserInfo,
|
||||
PersonMentionView,
|
||||
PersonView,
|
||||
PurgeComment,
|
||||
|
@ -45,7 +46,7 @@ import {
|
|||
VoteContentType,
|
||||
} from "../../interfaces";
|
||||
import { mdToHtml, mdToHtmlNoImages } from "../../markdown";
|
||||
import { I18NextService, UserService } from "../../services";
|
||||
import { I18NextService } from "../../services";
|
||||
import { setupTippy } from "../../tippy";
|
||||
import { Icon, PurgeWarning, Spinner } from "../common/icon";
|
||||
import { MomentTime } from "../common/moment-time";
|
||||
|
@ -97,6 +98,7 @@ interface CommentNodeState {
|
|||
|
||||
interface CommentNodeProps {
|
||||
node: CommentNodeI;
|
||||
myUserInfo?: MyUserInfo;
|
||||
moderators?: CommunityModeratorView[];
|
||||
admins?: PersonView[];
|
||||
noBorder?: boolean;
|
||||
|
@ -238,14 +240,18 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
|
|||
cv.creator.id,
|
||||
this.props.moderators,
|
||||
this.props.admins,
|
||||
UserService.Instance.myUserInfo,
|
||||
this.props.myUserInfo,
|
||||
true,
|
||||
);
|
||||
const canAdmin_ = canAdmin(cv.creator.id, this.props.admins);
|
||||
const canAdmin_ = canAdmin(
|
||||
cv.creator.id,
|
||||
this.props.admins,
|
||||
this.props.myUserInfo,
|
||||
);
|
||||
const canAdminOnSelf = canAdmin(
|
||||
cv.creator.id,
|
||||
this.props.admins,
|
||||
UserService.Instance.myUserInfo,
|
||||
this.props.myUserInfo,
|
||||
true,
|
||||
);
|
||||
const isMod_ = cv.creator_is_moderator;
|
||||
|
@ -253,6 +259,7 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
|
|||
const amCommunityCreator_ = amCommunityCreator(
|
||||
cv.creator.id,
|
||||
this.props.moderators,
|
||||
this.props.myUserInfo,
|
||||
);
|
||||
|
||||
const moreRepliesBorderColor = this.props.node.depth
|
||||
|
@ -327,7 +334,7 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
|
|||
{/* This is an expanding spacer for mobile */}
|
||||
<div className="me-lg-5 flex-grow-1 flex-lg-grow-0 unselectable pointer mx-2" />
|
||||
|
||||
{showScores() && (
|
||||
{showScores(this.props.myUserInfo) && (
|
||||
<>
|
||||
<span
|
||||
className={`me-1 fw-bold ${this.scoreColor}`}
|
||||
|
@ -352,6 +359,7 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
|
|||
{this.state.showEdit && (
|
||||
<CommentForm
|
||||
node={node}
|
||||
loggedIn={!!this.props.myUserInfo}
|
||||
edit
|
||||
onReplyCancel={this.handleReplyCancel}
|
||||
disabled={this.props.locked}
|
||||
|
@ -410,7 +418,7 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
|
|||
)}
|
||||
</button>
|
||||
)}
|
||||
{UserService.Instance.myUserInfo && !this.props.viewOnly && (
|
||||
{this.props.myUserInfo && !this.props.viewOnly && (
|
||||
<>
|
||||
<VoteButtonsCompact
|
||||
voteContentType={VoteContentType.Comment}
|
||||
|
@ -1067,6 +1075,7 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
|
|||
{this.state.showReply && (
|
||||
<CommentForm
|
||||
node={node}
|
||||
loggedIn={!!this.props.myUserInfo}
|
||||
onReplyCancel={this.handleReplyCancel}
|
||||
disabled={this.props.locked}
|
||||
finished={this.props.finished.get(
|
||||
|
@ -1082,6 +1091,7 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
|
|||
{!this.state.collapsed && node.children.length > 0 && (
|
||||
<CommentNodes
|
||||
nodes={node.children}
|
||||
myUserInfo={this.props.myUserInfo}
|
||||
locked={this.props.locked}
|
||||
moderators={this.props.moderators}
|
||||
admins={this.props.admins}
|
||||
|
@ -1166,7 +1176,7 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
|
|||
|
||||
get myComment(): boolean {
|
||||
return (
|
||||
UserService.Instance.myUserInfo?.local_user_view.person.id ===
|
||||
this.props.myUserInfo?.local_user_view.person.id ===
|
||||
this.commentView.creator.id
|
||||
);
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@ import {
|
|||
Language,
|
||||
MarkCommentReplyAsRead,
|
||||
MarkPersonMentionAsRead,
|
||||
MyUserInfo,
|
||||
PersonView,
|
||||
PurgeComment,
|
||||
PurgePerson,
|
||||
|
@ -31,6 +32,7 @@ import { CommentNode } from "./comment-node";
|
|||
|
||||
interface CommentNodesProps {
|
||||
nodes: CommentNodeI[];
|
||||
myUserInfo?: MyUserInfo;
|
||||
moderators?: CommunityModeratorView[];
|
||||
admins?: PersonView[];
|
||||
maxCommentsShown?: number;
|
||||
|
@ -99,6 +101,7 @@ export class CommentNodes extends Component<CommentNodesProps, any> {
|
|||
<CommentNode
|
||||
key={node.comment_view.comment.id}
|
||||
node={node}
|
||||
myUserInfo={this.props.myUserInfo}
|
||||
noBorder={this.props.noBorder}
|
||||
isTopLevel={this.props.isTopLevel}
|
||||
viewOnly={this.props.viewOnly}
|
||||
|
|
|
@ -3,6 +3,7 @@ import { T } from "inferno-i18next-dess";
|
|||
import {
|
||||
CommentReportView,
|
||||
CommentView,
|
||||
MyUserInfo,
|
||||
ResolveCommentReport,
|
||||
} from "lemmy-js-client";
|
||||
import { CommentNodeI, CommentViewType } from "../../interfaces";
|
||||
|
@ -14,6 +15,7 @@ import { EMPTY_REQUEST } from "../../services/HttpService";
|
|||
|
||||
interface CommentReportProps {
|
||||
report: CommentReportView;
|
||||
myUserInfo?: MyUserInfo;
|
||||
onResolveReport(form: ResolveCommentReport): void;
|
||||
}
|
||||
|
||||
|
@ -75,6 +77,7 @@ export class CommentReport extends Component<
|
|||
<div className="comment-report">
|
||||
<CommentNode
|
||||
node={node}
|
||||
myUserInfo={this.props.myUserInfo}
|
||||
viewType={CommentViewType.Flat}
|
||||
enableDownvotes={true}
|
||||
viewOnly={true}
|
||||
|
|
|
@ -1,17 +1,17 @@
|
|||
import { setIsoData } from "@utils/app";
|
||||
import { Component } from "inferno";
|
||||
import { ErrorPage } from "../app/error-page";
|
||||
import { IsoDataOptionalSite } from "../../interfaces";
|
||||
|
||||
class ErrorGuard extends Component<any, any> {
|
||||
private isoData = setIsoData(this.context);
|
||||
|
||||
constructor(props: any, context: any) {
|
||||
super(props, context);
|
||||
}
|
||||
|
||||
render() {
|
||||
const errorPageData = this.isoData.errorPageData;
|
||||
const siteRes = this.isoData.site_res;
|
||||
const reduxState: IsoDataOptionalSite = this.context.store.getState().value;
|
||||
const errorPageData = reduxState.errorPageData;
|
||||
const siteRes = reduxState.site_res;
|
||||
console.log(`error guard data: ${reduxState.path}`);
|
||||
|
||||
if (errorPageData || !siteRes) {
|
||||
return <ErrorPage />;
|
||||
|
|
|
@ -2,12 +2,13 @@ import { selectableLanguages } from "@utils/app";
|
|||
import { randomStr } from "@utils/helpers";
|
||||
import classNames from "classnames";
|
||||
import { Component, linkEvent } from "inferno";
|
||||
import { Language } from "lemmy-js-client";
|
||||
import { I18NextService, UserService } from "../../services";
|
||||
import { Language, MyUserInfo } from "lemmy-js-client";
|
||||
import { I18NextService } from "../../services";
|
||||
import { Icon } from "./icon";
|
||||
|
||||
interface LanguageSelectProps {
|
||||
allLanguages: Language[];
|
||||
myUserInfo?: MyUserInfo;
|
||||
siteLanguages: number[];
|
||||
selectedLanguageIds?: number[];
|
||||
multiple?: boolean;
|
||||
|
@ -97,7 +98,7 @@ export class LanguageSelect extends Component<LanguageSelectProps, any> {
|
|||
this.props.siteLanguages,
|
||||
this.props.showAll,
|
||||
this.props.showSite,
|
||||
UserService.Instance.myUserInfo,
|
||||
this.props.myUserInfo,
|
||||
);
|
||||
|
||||
return (
|
||||
|
|
|
@ -5,7 +5,7 @@ import classNames from "classnames";
|
|||
import { NoOptionI18nKeys } from "i18next";
|
||||
import { Component, linkEvent } from "inferno";
|
||||
import { Prompt } from "inferno-router";
|
||||
import { Language } from "lemmy-js-client";
|
||||
import { Language, MyUserInfo } from "lemmy-js-client";
|
||||
import {
|
||||
concurrentImageUpload,
|
||||
markdownFieldCharacterLimit,
|
||||
|
@ -14,7 +14,7 @@ import {
|
|||
relTags,
|
||||
} from "../../config";
|
||||
import { customEmojisLookup, mdToHtml, setupTribute } from "../../markdown";
|
||||
import { HttpService, I18NextService, UserService } from "../../services";
|
||||
import { HttpService, I18NextService } from "../../services";
|
||||
import { setupTippy } from "../../tippy";
|
||||
import { pictrsDeleteToast, toast } from "../../toast";
|
||||
import { EmojiPicker } from "./emoji-picker";
|
||||
|
@ -52,6 +52,7 @@ interface MarkdownTextAreaProps {
|
|||
onSubmit?(content: string, languageId?: number): void;
|
||||
allLanguages: Language[]; // TODO should probably be nullable
|
||||
siteLanguages: number[]; // TODO same
|
||||
myUserInfo?: MyUserInfo;
|
||||
}
|
||||
|
||||
interface ImageUploadStatus {
|
||||
|
@ -168,7 +169,7 @@ export class MarkdownTextArea extends Component<
|
|||
<label
|
||||
htmlFor={`file-upload-${this.id}`}
|
||||
className={classNames("mb-0", {
|
||||
pointer: UserService.Instance.myUserInfo,
|
||||
pointer: !!this.props.myUserInfo,
|
||||
})}
|
||||
data-tippy-content={I18NextService.i18n.t("upload_image")}
|
||||
>
|
||||
|
@ -195,7 +196,7 @@ export class MarkdownTextArea extends Component<
|
|||
name="file"
|
||||
className="d-none"
|
||||
multiple
|
||||
disabled={!UserService.Instance.myUserInfo}
|
||||
disabled={!this.props.myUserInfo}
|
||||
onChange={linkEvent(this, this.handleImageUpload)}
|
||||
/>
|
||||
{this.getFormatButton("header", this.handleInsertHeader)}
|
||||
|
@ -276,6 +277,7 @@ export class MarkdownTextArea extends Component<
|
|||
{this.props.showLanguage && (
|
||||
<LanguageSelect
|
||||
iconVersion
|
||||
myUserInfo={this.props.myUserInfo}
|
||||
allLanguages={this.props.allLanguages}
|
||||
selectedLanguageIds={
|
||||
languageId ? Array.of(languageId) : undefined
|
||||
|
|
|
@ -6,14 +6,16 @@ import {
|
|||
CommentAggregates,
|
||||
CreateCommentLike,
|
||||
CreatePostLike,
|
||||
MyUserInfo,
|
||||
PostAggregates,
|
||||
} from "lemmy-js-client";
|
||||
import { VoteContentType, VoteType } from "../../interfaces";
|
||||
import { I18NextService, UserService } from "../../services";
|
||||
import { I18NextService } from "../../services";
|
||||
import { Icon, Spinner } from "../common/icon";
|
||||
|
||||
interface VoteButtonsProps {
|
||||
voteContentType: VoteContentType;
|
||||
myUserInfo?: MyUserInfo;
|
||||
id: number;
|
||||
onVote: (i: CreateCommentLike | CreatePostLike) => void;
|
||||
enableDownvotes?: boolean;
|
||||
|
@ -113,7 +115,7 @@ export class VoteButtonsCompact extends Component<
|
|||
this.props.my_vote === 1 ? "text-info" : "text-muted"
|
||||
}`}
|
||||
data-tippy-content={tippy(this.props.counts)}
|
||||
disabled={!UserService.Instance.myUserInfo}
|
||||
disabled={!this.props.myUserInfo}
|
||||
onClick={linkEvent(this, handleUpvote)}
|
||||
aria-label={I18NextService.i18n.t("upvote")}
|
||||
aria-pressed={this.props.my_vote === 1}
|
||||
|
@ -123,7 +125,7 @@ export class VoteButtonsCompact extends Component<
|
|||
) : (
|
||||
<>
|
||||
<Icon icon="arrow-up1" classes="icon-inline small" />
|
||||
{showScores() && (
|
||||
{showScores(this.props.myUserInfo) && (
|
||||
<span className="ms-2">
|
||||
{numToSI(this.props.counts.upvotes)}
|
||||
</span>
|
||||
|
@ -137,7 +139,7 @@ export class VoteButtonsCompact extends Component<
|
|||
className={`ms-2 btn btn-sm btn-link btn-animate btn py-0 px-1 ${
|
||||
this.props.my_vote === -1 ? "text-danger" : "text-muted"
|
||||
}`}
|
||||
disabled={!UserService.Instance.myUserInfo}
|
||||
disabled={!this.props.myUserInfo}
|
||||
onClick={linkEvent(this, handleDownvote)}
|
||||
data-tippy-content={tippy(this.props.counts)}
|
||||
aria-label={I18NextService.i18n.t("downvote")}
|
||||
|
@ -148,7 +150,7 @@ export class VoteButtonsCompact extends Component<
|
|||
) : (
|
||||
<>
|
||||
<Icon icon="arrow-down1" classes="icon-inline small" />
|
||||
{showScores() && (
|
||||
{showScores(this.props.myUserInfo) && (
|
||||
<span
|
||||
className={classNames("ms-2", {
|
||||
invisible: this.props.counts.downvotes === 0,
|
||||
|
@ -193,7 +195,7 @@ export class VoteButtons extends Component<VoteButtonsProps, VoteButtonsState> {
|
|||
className={`btn-animate btn btn-link p-0 ${
|
||||
this.props.my_vote === 1 ? "text-info" : "text-muted"
|
||||
}`}
|
||||
disabled={!UserService.Instance.myUserInfo}
|
||||
disabled={!this.props.myUserInfo}
|
||||
onClick={linkEvent(this, handleUpvote)}
|
||||
data-tippy-content={I18NextService.i18n.t("upvote")}
|
||||
aria-label={I18NextService.i18n.t("upvote")}
|
||||
|
@ -205,7 +207,7 @@ export class VoteButtons extends Component<VoteButtonsProps, VoteButtonsState> {
|
|||
<Icon icon="arrow-up1" classes="upvote" />
|
||||
)}
|
||||
</button>
|
||||
{showScores() ? (
|
||||
{showScores(this.props.myUserInfo) ? (
|
||||
<div
|
||||
className="unselectable pointer text-muted post-score"
|
||||
data-tippy-content={tippy(this.props.counts)}
|
||||
|
@ -221,7 +223,7 @@ export class VoteButtons extends Component<VoteButtonsProps, VoteButtonsState> {
|
|||
className={`btn-animate btn btn-link p-0 ${
|
||||
this.props.my_vote === -1 ? "text-danger" : "text-muted"
|
||||
}`}
|
||||
disabled={!UserService.Instance.myUserInfo}
|
||||
disabled={!this.props.myUserInfo}
|
||||
onClick={linkEvent(this, handleDownvote)}
|
||||
data-tippy-content={I18NextService.i18n.t("downvote")}
|
||||
aria-label={I18NextService.i18n.t("downvote")}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { editCommunity, setIsoData, showLocal } from "@utils/app";
|
||||
import { editCommunity, showLocal } from "@utils/app";
|
||||
import {
|
||||
getPageFromString,
|
||||
getQueryParams,
|
||||
|
@ -17,7 +17,7 @@ import {
|
|||
ListingType,
|
||||
SortType,
|
||||
} from "lemmy-js-client";
|
||||
import { InitialFetchRequest } from "../../interfaces";
|
||||
import { InitialFetchRequest, IsoData } from "../../interfaces";
|
||||
import { FirstLoadService, I18NextService } from "../../services";
|
||||
import {
|
||||
EMPTY_REQUEST,
|
||||
|
@ -70,7 +70,9 @@ function getCommunitiesQueryParams() {
|
|||
}
|
||||
|
||||
export class Communities extends Component<any, CommunitiesState> {
|
||||
private isoData = setIsoData<CommunitiesData>(this.context);
|
||||
get isoData(): IsoData<CommunitiesData> {
|
||||
return this.context.store.getState().value;
|
||||
}
|
||||
state: CommunitiesState = {
|
||||
listCommunitiesResponse: EMPTY_REQUEST,
|
||||
siteRes: this.isoData.site_res,
|
||||
|
|
|
@ -243,6 +243,7 @@ export class CommunityForm extends Component<
|
|||
selectedLanguageIds={this.state.form.discussion_languages}
|
||||
multiple={true}
|
||||
onChange={this.handleDiscussionLanguageChange}
|
||||
myUserInfo={this.props.myUserInfo}
|
||||
/>
|
||||
<div className="mb-3 row">
|
||||
<div className="col-12">
|
||||
|
|
|
@ -2,12 +2,13 @@ import { showAvatars } from "@utils/app";
|
|||
import { hostname } from "@utils/helpers";
|
||||
import { Component } from "inferno";
|
||||
import { Link } from "inferno-router";
|
||||
import { Community } from "lemmy-js-client";
|
||||
import { Community, MyUserInfo } from "lemmy-js-client";
|
||||
import { relTags } from "../../config";
|
||||
import { PictrsImage } from "../common/pictrs-image";
|
||||
|
||||
interface CommunityLinkProps {
|
||||
community: Community;
|
||||
myUserInfo?: MyUserInfo;
|
||||
realLink?: boolean;
|
||||
useApubName?: boolean;
|
||||
muted?: boolean;
|
||||
|
@ -63,7 +64,7 @@ export class CommunityLink extends Component<CommunityLinkProps, any> {
|
|||
<>
|
||||
{!this.props.hideAvatar &&
|
||||
!this.props.community.removed &&
|
||||
showAvatars() &&
|
||||
showAvatars(this.props.myUserInfo) &&
|
||||
icon && <PictrsImage src={icon} icon nsfw={nsfw} />}
|
||||
<span className="overflow-wrap-anywhere">{displayName}</span>
|
||||
</>
|
||||
|
|
|
@ -9,7 +9,6 @@ import {
|
|||
getCommentParentId,
|
||||
getDataTypeString,
|
||||
postToCommentSortType,
|
||||
setIsoData,
|
||||
showLocal,
|
||||
updateCommunityBlock,
|
||||
updatePersonBlock,
|
||||
|
@ -58,6 +57,7 @@ import {
|
|||
LockPost,
|
||||
MarkCommentReplyAsRead,
|
||||
MarkPersonMentionAsRead,
|
||||
MyUserInfo,
|
||||
PaginationCursor,
|
||||
PostResponse,
|
||||
PurgeComment,
|
||||
|
@ -78,8 +78,9 @@ import {
|
|||
CommentViewType,
|
||||
DataType,
|
||||
InitialFetchRequest,
|
||||
IsoData,
|
||||
} from "../../interfaces";
|
||||
import { FirstLoadService, I18NextService, UserService } from "../../services";
|
||||
import { FirstLoadService, I18NextService } from "../../services";
|
||||
import {
|
||||
EMPTY_REQUEST,
|
||||
HttpService,
|
||||
|
@ -136,10 +137,11 @@ function getDataTypeFromQuery(type?: string): DataType {
|
|||
return type ? DataType[type] : DataType.Post;
|
||||
}
|
||||
|
||||
function getSortTypeFromQuery(type?: string): SortType {
|
||||
const mySortType =
|
||||
UserService.Instance.myUserInfo?.local_user_view.local_user
|
||||
.default_sort_type;
|
||||
function getSortTypeFromQuery(
|
||||
type?: string,
|
||||
myUserInfo?: MyUserInfo,
|
||||
): SortType {
|
||||
const mySortType = myUserInfo?.local_user_view.local_user.default_sort_type;
|
||||
|
||||
return type ? (type as SortType) : mySortType ?? "Active";
|
||||
}
|
||||
|
@ -148,7 +150,9 @@ export class Community extends Component<
|
|||
RouteComponentProps<{ name: string }>,
|
||||
State
|
||||
> {
|
||||
private isoData = setIsoData<CommunityData>(this.context);
|
||||
get isoData(): IsoData<CommunityData> {
|
||||
return this.context.store.getState().value;
|
||||
}
|
||||
state: State = {
|
||||
communityRes: EMPTY_REQUEST,
|
||||
postsRes: EMPTY_REQUEST,
|
||||
|
@ -463,6 +467,7 @@ export class Community extends Component<
|
|||
return (
|
||||
<CommentNodes
|
||||
nodes={commentsToFlatNodes(this.state.commentsRes.data.comments)}
|
||||
myUserInfo={this.isoData.site_res.my_user}
|
||||
viewType={CommentViewType.Flat}
|
||||
finished={this.state.finished}
|
||||
isTopLevel
|
||||
|
@ -642,7 +647,7 @@ export class Community extends Component<
|
|||
// Update myUserInfo
|
||||
if (followCommunityRes.state === "success") {
|
||||
const communityId = followCommunityRes.data.community_view.community.id;
|
||||
const mui = UserService.Instance.myUserInfo;
|
||||
const mui = this.isoData.site_res.my_user;
|
||||
if (mui) {
|
||||
mui.follows = mui.follows.filter(i => i.community.id !== communityId);
|
||||
}
|
||||
|
@ -672,7 +677,10 @@ export class Community extends Component<
|
|||
async handleBlockCommunity(form: BlockCommunity) {
|
||||
const blockCommunityRes = await HttpService.client.blockCommunity(form);
|
||||
if (blockCommunityRes.state === "success") {
|
||||
updateCommunityBlock(blockCommunityRes.data);
|
||||
updateCommunityBlock(
|
||||
blockCommunityRes.data,
|
||||
this.isoData.site_res.my_user,
|
||||
);
|
||||
this.setState(s => {
|
||||
if (s.communityRes.state === "success") {
|
||||
s.communityRes.data.community_view.blocked =
|
||||
|
@ -685,7 +693,7 @@ export class Community extends Component<
|
|||
async handleBlockPerson(form: BlockPerson) {
|
||||
const blockPersonRes = await HttpService.client.blockPerson(form);
|
||||
if (blockPersonRes.state === "success") {
|
||||
updatePersonBlock(blockPersonRes.data);
|
||||
updatePersonBlock(blockPersonRes.data, this.isoData.site_res.my_user);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { enableNsfw, setIsoData } from "@utils/app";
|
||||
import { enableNsfw } from "@utils/app";
|
||||
import { Component } from "inferno";
|
||||
import {
|
||||
CreateCommunity as CreateCommunityI,
|
||||
|
@ -7,6 +7,7 @@ import {
|
|||
import { HttpService, I18NextService } from "../../services";
|
||||
import { HtmlTags } from "../common/html-tags";
|
||||
import { CommunityForm } from "./community-form";
|
||||
import { IsoData } from "../../interfaces";
|
||||
|
||||
interface CreateCommunityState {
|
||||
siteRes: GetSiteResponse;
|
||||
|
@ -14,7 +15,9 @@ interface CreateCommunityState {
|
|||
}
|
||||
|
||||
export class CreateCommunity extends Component<any, CreateCommunityState> {
|
||||
private isoData = setIsoData(this.context);
|
||||
get isoData(): IsoData {
|
||||
return this.context.store.getState().value;
|
||||
}
|
||||
state: CreateCommunityState = {
|
||||
siteRes: this.isoData.site_res,
|
||||
loading: false,
|
||||
|
|
|
@ -12,12 +12,13 @@ import {
|
|||
EditCommunity,
|
||||
FollowCommunity,
|
||||
Language,
|
||||
MyUserInfo,
|
||||
PersonView,
|
||||
PurgeCommunity,
|
||||
RemoveCommunity,
|
||||
} from "lemmy-js-client";
|
||||
import { mdToHtml } from "../../markdown";
|
||||
import { I18NextService, UserService } from "../../services";
|
||||
import { I18NextService } from "../../services";
|
||||
import { Badges } from "../common/badges";
|
||||
import { BannerIconHeader } from "../common/banner-icon-header";
|
||||
import { Icon, PurgeWarning, Spinner } from "../common/icon";
|
||||
|
@ -28,6 +29,7 @@ import { PersonListing } from "../person/person-listing";
|
|||
|
||||
interface SidebarProps {
|
||||
community_view: CommunityView;
|
||||
myUserInfo?: MyUserInfo;
|
||||
moderators: CommunityModeratorView[];
|
||||
admins: PersonView[];
|
||||
allLanguages: Language[];
|
||||
|
@ -122,7 +124,7 @@ export class Sidebar extends Component<SidebarProps, SidebarState> {
|
|||
}
|
||||
|
||||
sidebar() {
|
||||
const myUSerInfo = UserService.Instance.myUserInfo;
|
||||
const myUserInfo = this.props.myUserInfo;
|
||||
const {
|
||||
community: { name, actor_id },
|
||||
} = this.props.community_view;
|
||||
|
@ -140,8 +142,8 @@ export class Sidebar extends Component<SidebarProps, SidebarState> {
|
|||
loading={this.state.followCommunityLoading}
|
||||
/>
|
||||
{this.canPost && this.createPost()}
|
||||
{myUSerInfo && this.blockCommunity()}
|
||||
{!myUSerInfo && (
|
||||
{myUserInfo && this.blockCommunity()}
|
||||
{!myUserInfo && (
|
||||
<div className="alert alert-info" role="alert">
|
||||
<T
|
||||
i18nKey="community_not_logged_in_alert"
|
||||
|
@ -268,7 +270,10 @@ export class Sidebar extends Component<SidebarProps, SidebarState> {
|
|||
return (
|
||||
<>
|
||||
<ul className="list-inline mb-1 text-muted fw-bold">
|
||||
{amMod(this.props.community_view.community.id) && (
|
||||
{amMod(
|
||||
this.props.community_view.community.id,
|
||||
this.props.myUserInfo,
|
||||
) && (
|
||||
<>
|
||||
<li className="list-inline-item-action">
|
||||
<button
|
||||
|
@ -280,7 +285,7 @@ export class Sidebar extends Component<SidebarProps, SidebarState> {
|
|||
<Icon icon="edit" classes="icon-inline" />
|
||||
</button>
|
||||
</li>
|
||||
{!amTopMod(this.props.moderators) &&
|
||||
{!amTopMod(this.props.moderators, this.props.myUserInfo) &&
|
||||
(!this.state.showConfirmLeaveModTeam ? (
|
||||
<li className="list-inline-item-action">
|
||||
<button
|
||||
|
@ -319,7 +324,7 @@ export class Sidebar extends Component<SidebarProps, SidebarState> {
|
|||
</li>
|
||||
</>
|
||||
))}
|
||||
{amTopMod(this.props.moderators) && (
|
||||
{amTopMod(this.props.moderators, this.props.myUserInfo) && (
|
||||
<li className="list-inline-item-action">
|
||||
<button
|
||||
className="btn btn-link text-muted d-inline-block"
|
||||
|
@ -468,8 +473,8 @@ export class Sidebar extends Component<SidebarProps, SidebarState> {
|
|||
get canPost(): boolean {
|
||||
return (
|
||||
!this.props.community_view.community.posting_restricted_to_mods ||
|
||||
amMod(this.props.community_view.community.id) ||
|
||||
amAdmin()
|
||||
amMod(this.props.community_view.community.id, this.props.myUserInfo) ||
|
||||
amAdmin(this.props.myUserInfo)
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -520,7 +525,7 @@ export class Sidebar extends Component<SidebarProps, SidebarState> {
|
|||
}
|
||||
|
||||
handleLeaveModTeam(i: Sidebar) {
|
||||
const myId = UserService.Instance.myUserInfo?.local_user_view.person.id;
|
||||
const myId = this.props.myUserInfo?.local_user_view.person.id;
|
||||
if (myId) {
|
||||
i.setState({ leaveModTeamLoading: true });
|
||||
i.props.onLeaveModTeam({
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { fetchThemeList, setIsoData, showLocal } from "@utils/app";
|
||||
import { fetchThemeList, showLocal } from "@utils/app";
|
||||
import { capitalizeFirstLetter } from "@utils/helpers";
|
||||
import { RouteDataResponse } from "@utils/types";
|
||||
import classNames from "classnames";
|
||||
|
@ -14,7 +14,7 @@ import {
|
|||
LemmyHttp,
|
||||
PersonView,
|
||||
} from "lemmy-js-client";
|
||||
import { InitialFetchRequest } from "../../interfaces";
|
||||
import { InitialFetchRequest, IsoData } from "../../interfaces";
|
||||
import { removeFromEmojiDataModel, updateEmojiDataModel } from "../../markdown";
|
||||
import { FirstLoadService, I18NextService } from "../../services";
|
||||
import {
|
||||
|
@ -53,7 +53,9 @@ interface AdminSettingsState {
|
|||
}
|
||||
|
||||
export class AdminSettings extends Component<any, AdminSettingsState> {
|
||||
private isoData = setIsoData<AdminSettingsData>(this.context);
|
||||
get isoData(): IsoData<AdminSettingsData> {
|
||||
return this.context.store.getState().value;
|
||||
}
|
||||
state: AdminSettingsState = {
|
||||
siteRes: this.isoData.site_res,
|
||||
banned: [],
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import { setIsoData } from "@utils/app";
|
||||
import { capitalizeFirstLetter } from "@utils/helpers";
|
||||
import { Component, linkEvent } from "inferno";
|
||||
import {
|
||||
|
@ -13,6 +12,7 @@ import { pictrsDeleteToast, toast } from "../../toast";
|
|||
import { EmojiMart } from "../common/emoji-mart";
|
||||
import { Icon, Spinner } from "../common/icon";
|
||||
import { Paginator } from "../common/paginator";
|
||||
import { IsoData } from "../../interfaces";
|
||||
|
||||
interface EmojiFormProps {
|
||||
onEdit(form: EditCustomEmoji): void;
|
||||
|
@ -39,7 +39,9 @@ interface CustomEmojiViewForm {
|
|||
}
|
||||
|
||||
export class EmojiForm extends Component<EmojiFormProps, EmojiFormState> {
|
||||
private isoData = setIsoData(this.context);
|
||||
get isoData(): IsoData {
|
||||
return this.context.store.getState().value;
|
||||
}
|
||||
private itemsPerPage = 15;
|
||||
private emptyState: EmojiFormState = {
|
||||
siteRes: this.isoData.site_res,
|
||||
|
|
|
@ -9,7 +9,6 @@ import {
|
|||
getDataTypeString,
|
||||
myAuth,
|
||||
postToCommentSortType,
|
||||
setIsoData,
|
||||
showLocal,
|
||||
updatePersonBlock,
|
||||
} from "@utils/app";
|
||||
|
@ -59,6 +58,7 @@ import {
|
|||
LockPost,
|
||||
MarkCommentReplyAsRead,
|
||||
MarkPersonMentionAsRead,
|
||||
MyUserInfo,
|
||||
PaginationCursor,
|
||||
PostResponse,
|
||||
PurgeComment,
|
||||
|
@ -77,9 +77,10 @@ import {
|
|||
CommentViewType,
|
||||
DataType,
|
||||
InitialFetchRequest,
|
||||
IsoData,
|
||||
} from "../../interfaces";
|
||||
import { mdToHtml } from "../../markdown";
|
||||
import { FirstLoadService, I18NextService, UserService } from "../../services";
|
||||
import { FirstLoadService, I18NextService } from "../../services";
|
||||
import {
|
||||
EMPTY_REQUEST,
|
||||
HttpService,
|
||||
|
@ -168,7 +169,7 @@ function getDataTypeFromQuery(type?: string): DataType {
|
|||
|
||||
function getListingTypeFromQuery(
|
||||
type?: string,
|
||||
myUserInfo = UserService.Instance.myUserInfo,
|
||||
myUserInfo?: MyUserInfo,
|
||||
): ListingType | undefined {
|
||||
const myListingType =
|
||||
myUserInfo?.local_user_view?.local_user?.default_listing_type;
|
||||
|
@ -178,7 +179,7 @@ function getListingTypeFromQuery(
|
|||
|
||||
function getSortTypeFromQuery(
|
||||
type?: string,
|
||||
myUserInfo = UserService.Instance.myUserInfo,
|
||||
myUserInfo?: MyUserInfo,
|
||||
): SortType {
|
||||
const mySortType = myUserInfo?.local_user_view?.local_user?.default_sort_type;
|
||||
|
||||
|
@ -225,7 +226,9 @@ const LinkButton = ({
|
|||
);
|
||||
|
||||
export class Home extends Component<any, HomeState> {
|
||||
private isoData = setIsoData<HomeData>(this.context);
|
||||
get isoData(): IsoData<HomeData> {
|
||||
return this.context.store.getState().value;
|
||||
}
|
||||
state: HomeState = {
|
||||
postsRes: EMPTY_REQUEST,
|
||||
commentsRes: EMPTY_REQUEST,
|
||||
|
@ -242,6 +245,7 @@ export class Home extends Component<any, HomeState> {
|
|||
|
||||
constructor(props: any, context: any) {
|
||||
super(props, context);
|
||||
console.log(this.isoData);
|
||||
|
||||
this.handleSortChange = this.handleSortChange.bind(this);
|
||||
this.handleListingTypeChange = this.handleListingTypeChange.bind(this);
|
||||
|
@ -416,7 +420,7 @@ export class Home extends Component<any, HomeState> {
|
|||
}
|
||||
|
||||
get hasFollows(): boolean {
|
||||
const mui = UserService.Instance.myUserInfo;
|
||||
const mui = this.isoData.site_res.my_user;
|
||||
return !!mui && mui.follows.length > 0;
|
||||
}
|
||||
|
||||
|
@ -606,7 +610,7 @@ export class Home extends Component<any, HomeState> {
|
|||
>
|
||||
<div className="card-body">
|
||||
<ul className="list-inline mb-0">
|
||||
{UserService.Instance.myUserInfo?.follows.map(cfv => (
|
||||
{this.isoData.site_res.my_user?.follows.map(cfv => (
|
||||
<li
|
||||
key={cfv.community.id}
|
||||
className="list-inline-item d-inline-block"
|
||||
|
@ -734,6 +738,7 @@ export class Home extends Component<any, HomeState> {
|
|||
return (
|
||||
<CommentNodes
|
||||
nodes={commentsToFlatNodes(comments)}
|
||||
myUserInfo={this.isoData.site_res.my_user}
|
||||
viewType={CommentViewType.Flat}
|
||||
finished={this.state.finished}
|
||||
isTopLevel
|
||||
|
@ -909,7 +914,7 @@ export class Home extends Component<any, HomeState> {
|
|||
async handleBlockPerson(form: BlockPerson) {
|
||||
const blockPersonRes = await HttpService.client.blockPerson(form);
|
||||
if (blockPersonRes.state === "success") {
|
||||
updatePersonBlock(blockPersonRes.data);
|
||||
updatePersonBlock(blockPersonRes.data, this.isoData.site_res.my_user);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import { setIsoData } from "@utils/app";
|
||||
import { RouteDataResponse } from "@utils/types";
|
||||
import { Component } from "inferno";
|
||||
import {
|
||||
|
@ -9,7 +8,7 @@ import {
|
|||
} from "lemmy-js-client";
|
||||
import classNames from "classnames";
|
||||
import { relTags } from "../../config";
|
||||
import { InitialFetchRequest } from "../../interfaces";
|
||||
import { InitialFetchRequest, IsoData } from "../../interfaces";
|
||||
import { FirstLoadService, I18NextService } from "../../services";
|
||||
import {
|
||||
EMPTY_REQUEST,
|
||||
|
@ -34,7 +33,9 @@ interface InstancesState {
|
|||
}
|
||||
|
||||
export class Instances extends Component<any, InstancesState> {
|
||||
private isoData = setIsoData<InstancesData>(this.context);
|
||||
get isoData(): IsoData<InstancesData> {
|
||||
return this.context.store.getState().value;
|
||||
}
|
||||
state: InstancesState = {
|
||||
instancesRes: EMPTY_REQUEST,
|
||||
siteRes: this.isoData.site_res,
|
||||
|
|
|
@ -1,16 +1,18 @@
|
|||
import { setIsoData } from "@utils/app";
|
||||
import { Component } from "inferno";
|
||||
import { GetSiteResponse } from "lemmy-js-client";
|
||||
import { mdToHtml } from "../../markdown";
|
||||
import { I18NextService } from "../../services";
|
||||
import { HtmlTags } from "../common/html-tags";
|
||||
import { IsoData } from "../../interfaces";
|
||||
|
||||
interface LegalState {
|
||||
siteRes: GetSiteResponse;
|
||||
}
|
||||
|
||||
export class Legal extends Component<any, LegalState> {
|
||||
private isoData = setIsoData(this.context);
|
||||
get isoData(): IsoData {
|
||||
return this.context.store.getState().value;
|
||||
}
|
||||
state: LegalState = {
|
||||
siteRes: this.isoData.site_res,
|
||||
};
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import { setIsoData } from "@utils/app";
|
||||
import { capitalizeFirstLetter, validEmail } from "@utils/helpers";
|
||||
import { Component, linkEvent } from "inferno";
|
||||
import { GetSiteResponse } from "lemmy-js-client";
|
||||
|
@ -6,6 +5,7 @@ import { HttpService, I18NextService } from "../../services";
|
|||
import { toast } from "../../toast";
|
||||
import { HtmlTags } from "../common/html-tags";
|
||||
import { Spinner } from "../common/icon";
|
||||
import { IsoData } from "../../interfaces";
|
||||
|
||||
interface State {
|
||||
form: {
|
||||
|
@ -16,7 +16,9 @@ interface State {
|
|||
}
|
||||
|
||||
export class LoginReset extends Component<any, State> {
|
||||
private isoData = setIsoData(this.context);
|
||||
get isoData(): IsoData {
|
||||
return this.context.store.getState().value;
|
||||
}
|
||||
|
||||
state: State = {
|
||||
form: {
|
||||
|
|
|
@ -46,6 +46,7 @@ async function handleLoginSuccess(i: Login, loginRes: LoginResponse) {
|
|||
const site = await HttpService.client.getSite();
|
||||
|
||||
if (site.state === "success") {
|
||||
// TODO this is the key, you need to update the redux store here
|
||||
UserService.Instance.myUserInfo = site.data.my_user;
|
||||
updateDataBsTheme(site.data);
|
||||
}
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import { setIsoData } from "@utils/app";
|
||||
import { isBrowser } from "@utils/browser";
|
||||
import { validEmail } from "@utils/helpers";
|
||||
import { Component, linkEvent } from "inferno";
|
||||
|
@ -12,7 +11,7 @@ import {
|
|||
} from "lemmy-js-client";
|
||||
import { joinLemmyUrl } from "../../config";
|
||||
import { mdToHtml } from "../../markdown";
|
||||
import { I18NextService, UserService } from "../../services";
|
||||
import { I18NextService } from "../../services";
|
||||
import {
|
||||
EMPTY_REQUEST,
|
||||
HttpService,
|
||||
|
@ -24,6 +23,7 @@ import { HtmlTags } from "../common/html-tags";
|
|||
import { Icon, Spinner } from "../common/icon";
|
||||
import { MarkdownTextArea } from "../common/markdown-textarea";
|
||||
import PasswordInput from "../common/password-input";
|
||||
import { IsoData } from "../../interfaces";
|
||||
|
||||
interface State {
|
||||
registerRes: RequestState<LoginResponse>;
|
||||
|
@ -44,7 +44,9 @@ interface State {
|
|||
}
|
||||
|
||||
export class Signup extends Component<any, State> {
|
||||
private isoData = setIsoData(this.context);
|
||||
get isoData(): IsoData {
|
||||
return this.context.store.getState().value;
|
||||
}
|
||||
private audio?: HTMLAudioElement;
|
||||
|
||||
state: State = {
|
||||
|
|
|
@ -498,6 +498,7 @@ export class SiteForm extends Component<SiteFormProps, SiteFormState> {
|
|||
selectedLanguageIds={this.state.siteForm.discussion_languages}
|
||||
multiple={true}
|
||||
onChange={this.handleDiscussionLanguageChange}
|
||||
myUserInfo={this.props.siteRes.my_user}
|
||||
showAll
|
||||
/>
|
||||
<div className="mb-3 row">
|
||||
|
|
|
@ -1,9 +1,4 @@
|
|||
import {
|
||||
fetchUsers,
|
||||
getUpdatedSearchId,
|
||||
personToChoice,
|
||||
setIsoData,
|
||||
} from "@utils/app";
|
||||
import { fetchUsers, getUpdatedSearchId, personToChoice } from "@utils/app";
|
||||
import {
|
||||
debounce,
|
||||
formatPastDate,
|
||||
|
@ -46,7 +41,7 @@ import {
|
|||
Person,
|
||||
} from "lemmy-js-client";
|
||||
import { fetchLimit } from "../config";
|
||||
import { InitialFetchRequest } from "../interfaces";
|
||||
import { InitialFetchRequest, IsoData } from "../interfaces";
|
||||
import { FirstLoadService, I18NextService } from "../services";
|
||||
import {
|
||||
EMPTY_REQUEST,
|
||||
|
@ -636,7 +631,9 @@ export class Modlog extends Component<
|
|||
RouteComponentProps<{ communityId?: string }>,
|
||||
ModlogState
|
||||
> {
|
||||
private isoData = setIsoData<ModlogData>(this.context);
|
||||
get isoData(): IsoData<ModlogData> {
|
||||
return this.context.store.getState().value;
|
||||
}
|
||||
|
||||
state: ModlogState = {
|
||||
res: EMPTY_REQUEST,
|
||||
|
|
|
@ -7,7 +7,6 @@ import {
|
|||
enableDownvotes,
|
||||
getCommentParentId,
|
||||
myAuth,
|
||||
setIsoData,
|
||||
updatePersonBlock,
|
||||
} from "@utils/app";
|
||||
import { capitalizeFirstLetter, randomStr } from "@utils/helpers";
|
||||
|
@ -61,8 +60,12 @@ import {
|
|||
TransferCommunity,
|
||||
} from "lemmy-js-client";
|
||||
import { fetchLimit, relTags } from "../../config";
|
||||
import { CommentViewType, InitialFetchRequest } from "../../interfaces";
|
||||
import { FirstLoadService, I18NextService, UserService } from "../../services";
|
||||
import {
|
||||
CommentViewType,
|
||||
InitialFetchRequest,
|
||||
IsoData,
|
||||
} from "../../interfaces";
|
||||
import { FirstLoadService, I18NextService } from "../../services";
|
||||
import { UnreadCounterService } from "../../services";
|
||||
import {
|
||||
EMPTY_REQUEST,
|
||||
|
@ -127,7 +130,9 @@ interface InboxState {
|
|||
}
|
||||
|
||||
export class Inbox extends Component<any, InboxState> {
|
||||
private isoData = setIsoData<InboxData>(this.context);
|
||||
get isoData(): IsoData<InboxData> {
|
||||
return this.context.store.getState().value;
|
||||
}
|
||||
state: InboxState = {
|
||||
unreadOrAll: UnreadOrAll.Unread,
|
||||
messageType: MessageType.All,
|
||||
|
@ -194,7 +199,7 @@ export class Inbox extends Component<any, InboxState> {
|
|||
}
|
||||
|
||||
get documentTitle(): string {
|
||||
const mui = UserService.Instance.myUserInfo;
|
||||
const mui = this.isoData.site_res.my_user;
|
||||
return mui
|
||||
? `@${mui.local_user_view.person.name} ${I18NextService.i18n.t(
|
||||
"inbox",
|
||||
|
@ -483,6 +488,7 @@ export class Inbox extends Component<any, InboxState> {
|
|||
nodes={[
|
||||
{ comment_view: i.view as CommentView, children: [], depth: 0 },
|
||||
]}
|
||||
myUserInfo={this.isoData.site_res.my_user}
|
||||
viewType={CommentViewType.Flat}
|
||||
finished={this.state.finished}
|
||||
markable
|
||||
|
@ -848,7 +854,7 @@ export class Inbox extends Component<any, InboxState> {
|
|||
async handleBlockPerson(form: BlockPerson) {
|
||||
const blockPersonRes = await HttpService.client.blockPerson(form);
|
||||
if (blockPersonRes.state === "success") {
|
||||
updatePersonBlock(blockPersonRes.data);
|
||||
updatePersonBlock(blockPersonRes.data, this.isoData.site_res.my_user);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -4,13 +4,14 @@ import { hostname, isCakeDay } from "@utils/helpers";
|
|||
import classNames from "classnames";
|
||||
import { Component } from "inferno";
|
||||
import { Link } from "inferno-router";
|
||||
import { Person } from "lemmy-js-client";
|
||||
import { MyUserInfo, Person } from "lemmy-js-client";
|
||||
import { relTags } from "../../config";
|
||||
import { PictrsImage } from "../common/pictrs-image";
|
||||
import { CakeDay } from "./cake-day";
|
||||
|
||||
interface PersonListingProps {
|
||||
person: Person;
|
||||
myUserInfo?: MyUserInfo;
|
||||
realLink?: boolean;
|
||||
useApubName?: boolean;
|
||||
muted?: boolean;
|
||||
|
@ -87,7 +88,7 @@ export class PersonListing extends Component<PersonListingProps, any> {
|
|||
<>
|
||||
{!this.props.hideAvatar &&
|
||||
!this.props.person.banned &&
|
||||
showAvatars() && (
|
||||
showAvatars(this.props.myUserInfo) && (
|
||||
<PictrsImage
|
||||
src={avatar ?? `${getStaticDir()}/assets/icons/icon-96x96.png`}
|
||||
icon
|
||||
|
|
|
@ -5,7 +5,6 @@ import {
|
|||
enableDownvotes,
|
||||
enableNsfw,
|
||||
getCommentParentId,
|
||||
setIsoData,
|
||||
updatePersonBlock,
|
||||
} from "@utils/app";
|
||||
import { restoreScrollPosition, saveScrollPosition } from "@utils/browser";
|
||||
|
@ -59,6 +58,7 @@ import {
|
|||
LockPost,
|
||||
MarkCommentReplyAsRead,
|
||||
MarkPersonMentionAsRead,
|
||||
MyUserInfo,
|
||||
PersonView,
|
||||
PostResponse,
|
||||
PurgeComment,
|
||||
|
@ -73,9 +73,13 @@ import {
|
|||
TransferCommunity,
|
||||
} from "lemmy-js-client";
|
||||
import { fetchLimit, relTags } from "../../config";
|
||||
import { InitialFetchRequest, PersonDetailsView } from "../../interfaces";
|
||||
import {
|
||||
InitialFetchRequest,
|
||||
IsoData,
|
||||
PersonDetailsView,
|
||||
} from "../../interfaces";
|
||||
import { mdToHtml } from "../../markdown";
|
||||
import { FirstLoadService, I18NextService, UserService } from "../../services";
|
||||
import { FirstLoadService, I18NextService } from "../../services";
|
||||
import {
|
||||
EMPTY_REQUEST,
|
||||
HttpService,
|
||||
|
@ -159,13 +163,16 @@ const getCommunitiesListing = (
|
|||
const Moderates = ({ moderates }: { moderates?: CommunityModeratorView[] }) =>
|
||||
getCommunitiesListing("moderates", moderates);
|
||||
|
||||
const Follows = () =>
|
||||
getCommunitiesListing("subscribed", UserService.Instance.myUserInfo?.follows);
|
||||
const Follows = ({ myUserInfo }: { myUserInfo?: MyUserInfo }) =>
|
||||
getCommunitiesListing("subscribed", myUserInfo?.follows);
|
||||
|
||||
function isPersonBlocked(personRes: RequestState<GetPersonDetailsResponse>) {
|
||||
function isPersonBlocked(
|
||||
personRes: RequestState<GetPersonDetailsResponse>,
|
||||
myUserInfo?: MyUserInfo,
|
||||
) {
|
||||
return (
|
||||
(personRes.state === "success" &&
|
||||
UserService.Instance.myUserInfo?.person_blocks.some(
|
||||
myUserInfo?.person_blocks.some(
|
||||
({ target: { id } }) => id === personRes.data.person_view.person.id,
|
||||
)) ??
|
||||
false
|
||||
|
@ -176,7 +183,9 @@ export class Profile extends Component<
|
|||
RouteComponentProps<{ username: string }>,
|
||||
ProfileState
|
||||
> {
|
||||
private isoData = setIsoData<ProfileData>(this.context);
|
||||
get isoData(): IsoData<ProfileData> {
|
||||
return this.context.store.getState().value;
|
||||
}
|
||||
state: ProfileState = {
|
||||
personRes: EMPTY_REQUEST,
|
||||
personBlocked: false,
|
||||
|
@ -269,7 +278,7 @@ export class Profile extends Component<
|
|||
get amCurrentUser() {
|
||||
if (this.state.personRes.state === "success") {
|
||||
return (
|
||||
UserService.Instance.myUserInfo?.local_user_view.person.id ===
|
||||
this.isoData.site_res.my_user?.local_user_view.person.id ===
|
||||
this.state.personRes.data.person_view.person.id
|
||||
);
|
||||
} else {
|
||||
|
@ -388,7 +397,9 @@ export class Profile extends Component<
|
|||
|
||||
<div className="col-12 col-md-4">
|
||||
<Moderates moderates={personRes.moderates} />
|
||||
{this.amCurrentUser && <Follows />}
|
||||
{this.amCurrentUser && (
|
||||
<Follows myUserInfo={this.isoData.site_res.my_user} />
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
@ -511,7 +522,7 @@ export class Profile extends Component<
|
|||
</div>
|
||||
{this.banDialog(pv)}
|
||||
<div className="flex-grow-1 unselectable pointer mx-2"></div>
|
||||
{!this.amCurrentUser && UserService.Instance.myUserInfo && (
|
||||
{!this.amCurrentUser && this.isoData.site_res.my_user && (
|
||||
<>
|
||||
<a
|
||||
className={`d-flex align-self-start btn btn-secondary me-2 ${
|
||||
|
@ -622,7 +633,7 @@ export class Profile extends Component<
|
|||
{format(parseISO(pv.person.published), "PPP")}
|
||||
</span>
|
||||
</div>
|
||||
{!UserService.Instance.myUserInfo && (
|
||||
{!this.isoData.site_res.my_user && (
|
||||
<div className="alert alert-info" role="alert">
|
||||
{I18NextService.i18n.t("profile_not_logged_in_alert")}
|
||||
</div>
|
||||
|
@ -799,7 +810,7 @@ export class Profile extends Component<
|
|||
block,
|
||||
});
|
||||
if (res.state === "success") {
|
||||
updatePersonBlock(res.data);
|
||||
updatePersonBlock(res.data, this.isoData.site_res.my_user);
|
||||
this.setState({ personBlocked: res.data.blocked });
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { editRegistrationApplication, setIsoData } from "@utils/app";
|
||||
import { editRegistrationApplication } from "@utils/app";
|
||||
import { randomStr } from "@utils/helpers";
|
||||
import { RouteDataResponse } from "@utils/types";
|
||||
import classNames from "classnames";
|
||||
|
@ -11,8 +11,8 @@ import {
|
|||
RegistrationApplicationView,
|
||||
} from "lemmy-js-client";
|
||||
import { fetchLimit } from "../../config";
|
||||
import { InitialFetchRequest } from "../../interfaces";
|
||||
import { FirstLoadService, I18NextService, UserService } from "../../services";
|
||||
import { InitialFetchRequest, IsoData } from "../../interfaces";
|
||||
import { FirstLoadService, I18NextService } from "../../services";
|
||||
import {
|
||||
EMPTY_REQUEST,
|
||||
HttpService,
|
||||
|
@ -49,7 +49,9 @@ export class RegistrationApplications extends Component<
|
|||
any,
|
||||
RegistrationApplicationsState
|
||||
> {
|
||||
private isoData = setIsoData<RegistrationApplicationsData>(this.context);
|
||||
get isoData(): IsoData<RegistrationApplicationsData> {
|
||||
return this.context.store.getState().value;
|
||||
}
|
||||
state: RegistrationApplicationsState = {
|
||||
appsRes: EMPTY_REQUEST,
|
||||
siteRes: this.isoData.site_res,
|
||||
|
@ -82,7 +84,7 @@ export class RegistrationApplications extends Component<
|
|||
}
|
||||
|
||||
get documentTitle(): string {
|
||||
const mui = UserService.Instance.myUserInfo;
|
||||
const mui = this.isoData.site_res.my_user;
|
||||
return mui
|
||||
? `@${mui.local_user_view.person.name} ${I18NextService.i18n.t(
|
||||
"registration_applications",
|
||||
|
|
|
@ -2,7 +2,6 @@ import {
|
|||
editCommentReport,
|
||||
editPostReport,
|
||||
editPrivateMessageReport,
|
||||
setIsoData,
|
||||
} from "@utils/app";
|
||||
import { randomStr } from "@utils/helpers";
|
||||
import { amAdmin } from "@utils/roles";
|
||||
|
@ -29,13 +28,8 @@ import {
|
|||
ResolvePrivateMessageReport,
|
||||
} from "lemmy-js-client";
|
||||
import { fetchLimit } from "../../config";
|
||||
import { InitialFetchRequest } from "../../interfaces";
|
||||
import {
|
||||
FirstLoadService,
|
||||
HttpService,
|
||||
I18NextService,
|
||||
UserService,
|
||||
} from "../../services";
|
||||
import { InitialFetchRequest, IsoData } from "../../interfaces";
|
||||
import { FirstLoadService, HttpService, I18NextService } from "../../services";
|
||||
import {
|
||||
EMPTY_REQUEST,
|
||||
LOADING_REQUEST,
|
||||
|
@ -94,7 +88,9 @@ interface ReportsState {
|
|||
}
|
||||
|
||||
export class Reports extends Component<any, ReportsState> {
|
||||
private isoData = setIsoData<ReportsData>(this.context);
|
||||
get isoData(): IsoData<ReportsData> {
|
||||
return this.context.store.getState().value;
|
||||
}
|
||||
state: ReportsState = {
|
||||
commentReportsRes: EMPTY_REQUEST,
|
||||
postReportsRes: EMPTY_REQUEST,
|
||||
|
@ -144,7 +140,7 @@ export class Reports extends Component<any, ReportsState> {
|
|||
}
|
||||
|
||||
get documentTitle(): string {
|
||||
const mui = UserService.Instance.myUserInfo;
|
||||
const mui = this.isoData.site_res.my_user;
|
||||
return mui
|
||||
? `@${mui.local_user_view.person.name} ${I18NextService.i18n.t(
|
||||
"reports",
|
||||
|
@ -397,6 +393,7 @@ export class Reports extends Component<any, ReportsState> {
|
|||
return (
|
||||
<CommentReport
|
||||
key={i.id}
|
||||
myUserInfo={this.isoData.site_res.my_user}
|
||||
report={i.view as CommentReportView}
|
||||
onResolveReport={this.handleResolveCommentReport}
|
||||
/>
|
||||
|
|
|
@ -6,7 +6,6 @@ import {
|
|||
instanceToChoice,
|
||||
myAuth,
|
||||
personToChoice,
|
||||
setIsoData,
|
||||
setTheme,
|
||||
showLocal,
|
||||
updateCommunityBlock,
|
||||
|
@ -37,7 +36,7 @@ import {
|
|||
UpdateTotpResponse,
|
||||
} from "lemmy-js-client";
|
||||
import { elementUrl, emDash, fetchLimit, relTags } from "../../config";
|
||||
import { FirstLoadService, UserService } from "../../services";
|
||||
import { FirstLoadService } from "../../services";
|
||||
import {
|
||||
EMPTY_REQUEST,
|
||||
HttpService,
|
||||
|
@ -60,7 +59,7 @@ import { SortSelect } from "../common/sort-select";
|
|||
import Tabs from "../common/tabs";
|
||||
import { CommunityLink } from "../community/community-link";
|
||||
import { PersonListing } from "./person-listing";
|
||||
import { InitialFetchRequest } from "../../interfaces";
|
||||
import { InitialFetchRequest, IsoData } from "../../interfaces";
|
||||
import TotpModal from "../common/totp-modal";
|
||||
import { LoadingEllipses } from "../common/loading-ellipses";
|
||||
import { updateDataBsTheme } from "../../utils/browser";
|
||||
|
@ -190,7 +189,9 @@ function handleClose2faModal(i: Settings) {
|
|||
}
|
||||
|
||||
export class Settings extends Component<any, SettingsState> {
|
||||
private isoData = setIsoData<SettingsData>(this.context);
|
||||
get isoData(): IsoData<SettingsData> {
|
||||
return this.context.store.getState().value;
|
||||
}
|
||||
exportSettingsLink = createRef<HTMLAnchorElement>();
|
||||
|
||||
state: SettingsState = {
|
||||
|
@ -246,7 +247,7 @@ export class Settings extends Component<any, SettingsState> {
|
|||
this.handleEnable2fa = this.handleEnable2fa.bind(this);
|
||||
this.handleDisable2fa = this.handleDisable2fa.bind(this);
|
||||
|
||||
const mui = UserService.Instance.myUserInfo;
|
||||
const mui = this.isoData.site_res.my_user;
|
||||
if (mui) {
|
||||
const {
|
||||
local_user: {
|
||||
|
@ -818,6 +819,7 @@ export class Settings extends Component<any, SettingsState> {
|
|||
showAll={true}
|
||||
showSite
|
||||
onChange={this.handleDiscussionLanguageChange}
|
||||
myUserInfo={this.isoData.site_res.my_user}
|
||||
/>
|
||||
<div className="mb-3 row">
|
||||
<label className="col-sm-3 col-form-label" htmlFor="user-theme">
|
||||
|
@ -1125,7 +1127,7 @@ export class Settings extends Component<any, SettingsState> {
|
|||
|
||||
totpSection() {
|
||||
const totpEnabled =
|
||||
!!UserService.Instance.myUserInfo?.local_user_view.local_user
|
||||
!!this.isoData.site_res.my_user?.local_user_view.local_user
|
||||
.totp_2fa_enabled;
|
||||
const { generateTotpRes } = this.state;
|
||||
|
||||
|
@ -1181,7 +1183,7 @@ export class Settings extends Component<any, SettingsState> {
|
|||
|
||||
const siteRes = await HttpService.client.getSite();
|
||||
|
||||
UserService.Instance.myUserInfo!.local_user_view.local_user.totp_2fa_enabled =
|
||||
this.isoData.site_res.my_user!.local_user_view.local_user.totp_2fa_enabled =
|
||||
enabled;
|
||||
|
||||
if (siteRes.state === "success") {
|
||||
|
@ -1349,7 +1351,7 @@ export class Settings extends Component<any, SettingsState> {
|
|||
}
|
||||
|
||||
handleShowAvatarsChange(i: Settings, event: any) {
|
||||
const mui = UserService.Instance.myUserInfo;
|
||||
const mui = this.isoData.site_res.my_user;
|
||||
if (mui) {
|
||||
mui.local_user_view.local_user.show_avatars = event.target.checked;
|
||||
}
|
||||
|
@ -1395,7 +1397,7 @@ export class Settings extends Component<any, SettingsState> {
|
|||
}
|
||||
|
||||
handleShowScoresChange(i: Settings, event: any) {
|
||||
const mui = UserService.Instance.myUserInfo;
|
||||
const mui = this.isoData.site_res.my_user;
|
||||
if (mui) {
|
||||
mui.local_user_view.local_user.show_scores = event.target.checked;
|
||||
}
|
||||
|
@ -1528,6 +1530,7 @@ export class Settings extends Component<any, SettingsState> {
|
|||
siteRes: siteRes.data,
|
||||
});
|
||||
|
||||
// TODO need to update this
|
||||
UserService.Instance.myUserInfo = siteRes.data.my_user;
|
||||
}
|
||||
|
||||
|
@ -1628,6 +1631,7 @@ export class Settings extends Component<any, SettingsState> {
|
|||
},
|
||||
} = siteRes.data.my_user!.local_user_view;
|
||||
|
||||
// TODO need to update redux
|
||||
UserService.Instance.myUserInfo = siteRes.data.my_user;
|
||||
updateDataBsTheme(siteRes.data);
|
||||
|
||||
|
@ -1705,8 +1709,8 @@ export class Settings extends Component<any, SettingsState> {
|
|||
|
||||
personBlock(res: RequestState<BlockPersonResponse>) {
|
||||
if (res.state === "success") {
|
||||
updatePersonBlock(res.data);
|
||||
const mui = UserService.Instance.myUserInfo;
|
||||
updatePersonBlock(res.data, this.isoData.site_res.my_user);
|
||||
const mui = this.isoData.site_res.my_user;
|
||||
if (mui) {
|
||||
this.setState({ personBlocks: mui.person_blocks });
|
||||
}
|
||||
|
@ -1715,8 +1719,8 @@ export class Settings extends Component<any, SettingsState> {
|
|||
|
||||
communityBlock(res: RequestState<BlockCommunityResponse>) {
|
||||
if (res.state === "success") {
|
||||
updateCommunityBlock(res.data);
|
||||
const mui = UserService.Instance.myUserInfo;
|
||||
updateCommunityBlock(res.data, this.isoData.site_res.my_user);
|
||||
const mui = this.isoData.site_res.my_user;
|
||||
if (mui) {
|
||||
this.setState({ communityBlocks: mui.community_blocks });
|
||||
}
|
||||
|
@ -1730,8 +1734,13 @@ export class Settings extends Component<any, SettingsState> {
|
|||
) {
|
||||
const linkedInstances =
|
||||
this.state.instancesRes.data.federated_instances?.linked ?? [];
|
||||
updateInstanceBlock(res.data, id, linkedInstances);
|
||||
const mui = UserService.Instance.myUserInfo;
|
||||
updateInstanceBlock(
|
||||
res.data,
|
||||
id,
|
||||
linkedInstances,
|
||||
this.isoData.site_res.my_user,
|
||||
);
|
||||
const mui = this.isoData.site_res.my_user;
|
||||
if (mui) {
|
||||
this.setState({ instanceBlocks: mui.instance_blocks });
|
||||
}
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import { setIsoData } from "@utils/app";
|
||||
import { Component } from "inferno";
|
||||
import { GetSiteResponse, SuccessResponse } from "lemmy-js-client";
|
||||
import { I18NextService } from "../../services";
|
||||
|
@ -11,6 +10,7 @@ import {
|
|||
import { toast } from "../../toast";
|
||||
import { HtmlTags } from "../common/html-tags";
|
||||
import { Spinner } from "../common/icon";
|
||||
import { IsoData } from "../../interfaces";
|
||||
|
||||
interface State {
|
||||
verifyRes: RequestState<SuccessResponse>;
|
||||
|
@ -18,7 +18,9 @@ interface State {
|
|||
}
|
||||
|
||||
export class VerifyEmail extends Component<any, State> {
|
||||
private isoData = setIsoData(this.context);
|
||||
get isoData(): IsoData {
|
||||
return this.context.store.getState().value;
|
||||
}
|
||||
|
||||
state: State = {
|
||||
verifyRes: EMPTY_REQUEST,
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { enableDownvotes, enableNsfw, setIsoData } from "@utils/app";
|
||||
import { enableDownvotes, enableNsfw } from "@utils/app";
|
||||
import { getIdFromString, getQueryParams } from "@utils/helpers";
|
||||
import type { QueryParams } from "@utils/types";
|
||||
import { Choice, RouteDataResponse } from "@utils/types";
|
||||
|
@ -12,7 +12,7 @@ import {
|
|||
LemmyHttp,
|
||||
ListCommunitiesResponse,
|
||||
} from "lemmy-js-client";
|
||||
import { InitialFetchRequest, PostFormParams } from "../../interfaces";
|
||||
import { InitialFetchRequest, IsoData, PostFormParams } from "../../interfaces";
|
||||
import { FirstLoadService, I18NextService } from "../../services";
|
||||
import {
|
||||
EMPTY_REQUEST,
|
||||
|
@ -57,7 +57,9 @@ export class CreatePost extends Component<
|
|||
RouteComponentProps<Record<string, never>>,
|
||||
CreatePostState
|
||||
> {
|
||||
private isoData = setIsoData<CreatePostData>(this.context);
|
||||
get isoData(): IsoData<CreatePostData> {
|
||||
return this.context.store.getState().value;
|
||||
}
|
||||
state: CreatePostState = {
|
||||
siteRes: this.isoData.site_res,
|
||||
loading: true,
|
||||
|
|
|
@ -17,6 +17,7 @@ import {
|
|||
EditPost,
|
||||
GetSiteMetadataResponse,
|
||||
Language,
|
||||
MyUserInfo,
|
||||
PostView,
|
||||
SearchResponse,
|
||||
} from "lemmy-js-client";
|
||||
|
@ -28,7 +29,7 @@ import {
|
|||
webArchiveUrl,
|
||||
} from "../../config";
|
||||
import { PostFormParams } from "../../interfaces";
|
||||
import { I18NextService, UserService } from "../../services";
|
||||
import { I18NextService } from "../../services";
|
||||
import {
|
||||
EMPTY_REQUEST,
|
||||
HttpService,
|
||||
|
@ -47,6 +48,7 @@ const MAX_POST_TITLE_LENGTH = 200;
|
|||
|
||||
interface PostFormProps {
|
||||
post_view?: PostView; // If a post is given, that means this is an edit
|
||||
myUserInfo?: MyUserInfo;
|
||||
crossPosts?: PostView[];
|
||||
allLanguages: Language[];
|
||||
siteLanguages: number[];
|
||||
|
@ -423,7 +425,7 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
|
|||
accept="image/*,video/*"
|
||||
name="file"
|
||||
className="small col-sm-10 form-control"
|
||||
disabled={!UserService.Instance.myUserInfo}
|
||||
disabled={!this.props.myUserInfo}
|
||||
onChange={linkEvent(this, handleImageUpload)}
|
||||
/>
|
||||
{this.state.imageLoading && <Spinner />}
|
||||
|
@ -496,6 +498,7 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
|
|||
selectedLanguageIds={selectedLangs}
|
||||
multiple={false}
|
||||
onChange={this.handleLanguageChange}
|
||||
myUserInfo={this.props.myUserInfo}
|
||||
/>
|
||||
{!this.props.post_view && (
|
||||
<div className="mb-3 row">
|
||||
|
|
|
@ -33,6 +33,7 @@ import {
|
|||
Language,
|
||||
LockPost,
|
||||
MarkPostAsRead,
|
||||
MyUserInfo,
|
||||
PersonView,
|
||||
PostView,
|
||||
PurgePerson,
|
||||
|
@ -49,7 +50,7 @@ import {
|
|||
VoteContentType,
|
||||
} from "../../interfaces";
|
||||
import { mdToHtml, mdToHtmlInline } from "../../markdown";
|
||||
import { I18NextService, UserService } from "../../services";
|
||||
import { I18NextService } from "../../services";
|
||||
import { setupTippy } from "../../tippy";
|
||||
import { Icon, PurgeWarning, Spinner } from "../common/icon";
|
||||
import { MomentTime } from "../common/moment-time";
|
||||
|
@ -98,6 +99,7 @@ interface PostListingState {
|
|||
|
||||
interface PostListingProps {
|
||||
post_view: PostView;
|
||||
myUserInfo?: MyUserInfo;
|
||||
crossPosts?: PostView[];
|
||||
moderators?: CommunityModeratorView[];
|
||||
admins?: PersonView[];
|
||||
|
@ -171,11 +173,10 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
|
|||
}
|
||||
|
||||
componentDidMount(): void {
|
||||
if (UserService.Instance.myUserInfo) {
|
||||
if (this.props.myUserInfo) {
|
||||
this.setState({
|
||||
imageExpanded:
|
||||
UserService.Instance.myUserInfo.local_user_view.local_user
|
||||
.auto_expand,
|
||||
this.props.myUserInfo.local_user_view.local_user.auto_expand,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -629,6 +630,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
|
|||
{mobile && !this.props.viewOnly && (
|
||||
<VoteButtonsCompact
|
||||
voteContentType={VoteContentType.Post}
|
||||
loggedIn={!!this.props.myUserInfo}
|
||||
id={this.postView.post.id}
|
||||
onVote={this.props.onPostVote}
|
||||
enableDownvotes={this.props.enableDownvotes}
|
||||
|
@ -639,9 +641,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
|
|||
|
||||
{this.props.showBody && pv.post.body && this.viewSourceButton}
|
||||
|
||||
{UserService.Instance.myUserInfo &&
|
||||
!this.props.viewOnly &&
|
||||
this.postActions()}
|
||||
{this.props.myUserInfo && !this.props.viewOnly && this.postActions()}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -687,7 +687,8 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
|
|||
)}
|
||||
|
||||
{/* Any mod can do these, not limited to hierarchy*/}
|
||||
{(amMod(this.postView.community.id) || amAdmin()) && (
|
||||
{(amMod(this.postView.community.id, this.props.myUserInfo) ||
|
||||
amAdmin(this.props.myUserInfo)) && (
|
||||
<>
|
||||
<li>
|
||||
<hr className="dropdown-divider" />
|
||||
|
@ -718,7 +719,11 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
|
|||
</>
|
||||
)}
|
||||
|
||||
{(amCommunityCreator(pv.creator.id, this.props.moderators) ||
|
||||
{(amCommunityCreator(
|
||||
pv.creator.id,
|
||||
this.props.moderators,
|
||||
this.props.myUserInfo,
|
||||
) ||
|
||||
this.canAdmin_) &&
|
||||
pv.creator_is_moderator && (
|
||||
<li>{this.transferCommunityButton}</li>
|
||||
|
@ -753,7 +758,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
|
|||
}
|
||||
|
||||
public get linkTarget(): string {
|
||||
return UserService.Instance.myUserInfo?.local_user_view.local_user
|
||||
return this.props.myUserInfo?.local_user_view.local_user
|
||||
.open_links_in_new_tab
|
||||
? "_blank"
|
||||
: // _self is the default target on links when the field is not specified
|
||||
|
@ -1378,6 +1383,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
|
|||
<div className="col flex-grow-0">
|
||||
<VoteButtons
|
||||
voteContentType={VoteContentType.Post}
|
||||
loggedIn={!!this.props.myUserInfo}
|
||||
id={this.postView.post.id}
|
||||
onVote={this.props.onPostVote}
|
||||
enableDownvotes={this.props.enableDownvotes}
|
||||
|
@ -1409,7 +1415,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
|
|||
private get myPost(): boolean {
|
||||
return (
|
||||
this.postView.creator.id ===
|
||||
UserService.Instance.myUserInfo?.local_user_view.person.id
|
||||
this.props.myUserInfo?.local_user_view.person.id
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -1774,10 +1780,15 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
|
|||
this.postView.creator.id,
|
||||
this.props.moderators,
|
||||
this.props.admins,
|
||||
this.props.myUserInfo,
|
||||
);
|
||||
}
|
||||
|
||||
get canAdmin_(): boolean {
|
||||
return canAdmin(this.postView.creator.id, this.props.admins);
|
||||
return canAdmin(
|
||||
this.postView.creator.id,
|
||||
this.props.admins,
|
||||
this.props.myUserInfo,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,7 +9,6 @@ import {
|
|||
getCommentParentId,
|
||||
getDepthFromComment,
|
||||
getIdFromProps,
|
||||
setIsoData,
|
||||
updateCommunityBlock,
|
||||
updatePersonBlock,
|
||||
} from "@utils/app";
|
||||
|
@ -80,8 +79,9 @@ import {
|
|||
CommentNodeI,
|
||||
CommentViewType,
|
||||
InitialFetchRequest,
|
||||
IsoData,
|
||||
} from "../../interfaces";
|
||||
import { FirstLoadService, I18NextService, UserService } from "../../services";
|
||||
import { FirstLoadService, I18NextService } from "../../services";
|
||||
import {
|
||||
EMPTY_REQUEST,
|
||||
HttpService,
|
||||
|
@ -123,7 +123,9 @@ interface PostState {
|
|||
}
|
||||
|
||||
export class Post extends Component<any, PostState> {
|
||||
private isoData = setIsoData<PostData>(this.context);
|
||||
get isoData(): IsoData<PostData> {
|
||||
return this.context.store.getState().value;
|
||||
}
|
||||
private commentScrollDebounced: () => void;
|
||||
state: PostState = {
|
||||
postRes: EMPTY_REQUEST,
|
||||
|
@ -402,6 +404,7 @@ export class Post extends Component<any, PostState> {
|
|||
{!this.state.commentId && (
|
||||
<CommentForm
|
||||
node={res.post_view.post.id}
|
||||
loggedIn={!!this.isoData.site_res.my_user}
|
||||
disabled={res.post_view.post.locked}
|
||||
allLanguages={this.state.siteRes.all_languages}
|
||||
siteLanguages={this.state.siteRes.discussion_languages}
|
||||
|
@ -761,7 +764,7 @@ export class Post extends Component<any, PostState> {
|
|||
// Update myUserInfo
|
||||
if (followCommunityRes.state === "success") {
|
||||
const communityId = followCommunityRes.data.community_view.community.id;
|
||||
const mui = UserService.Instance.myUserInfo;
|
||||
const mui = this.isoData.site_res.my_user;
|
||||
if (mui) {
|
||||
mui.follows = mui.follows.filter(i => i.community.id !== communityId);
|
||||
}
|
||||
|
@ -791,7 +794,10 @@ export class Post extends Component<any, PostState> {
|
|||
async handleBlockCommunity(form: BlockCommunity) {
|
||||
const blockCommunityRes = await HttpService.client.blockCommunity(form);
|
||||
if (blockCommunityRes.state === "success") {
|
||||
updateCommunityBlock(blockCommunityRes.data);
|
||||
updateCommunityBlock(
|
||||
blockCommunityRes.data,
|
||||
this.isoData.site_res.my_user,
|
||||
);
|
||||
this.setState(s => {
|
||||
if (s.postRes.state === "success") {
|
||||
s.postRes.data.community_view.blocked =
|
||||
|
@ -804,7 +810,7 @@ export class Post extends Component<any, PostState> {
|
|||
async handleBlockPerson(form: BlockPerson) {
|
||||
const blockPersonRes = await HttpService.client.blockPerson(form);
|
||||
if (blockPersonRes.state === "success") {
|
||||
updatePersonBlock(blockPersonRes.data);
|
||||
updatePersonBlock(blockPersonRes.data, this.isoData.site_res.my_user);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { getRecipientIdFromProps, setIsoData } from "@utils/app";
|
||||
import { getRecipientIdFromProps } from "@utils/app";
|
||||
import { RouteDataResponse } from "@utils/types";
|
||||
import { Component } from "inferno";
|
||||
import {
|
||||
|
@ -8,7 +8,7 @@ import {
|
|||
GetSiteResponse,
|
||||
LemmyHttp,
|
||||
} from "lemmy-js-client";
|
||||
import { InitialFetchRequest } from "../../interfaces";
|
||||
import { InitialFetchRequest, IsoData } from "../../interfaces";
|
||||
import { FirstLoadService, I18NextService } from "../../services";
|
||||
import {
|
||||
EMPTY_REQUEST,
|
||||
|
@ -38,7 +38,9 @@ export class CreatePrivateMessage extends Component<
|
|||
any,
|
||||
CreatePrivateMessageState
|
||||
> {
|
||||
private isoData = setIsoData<CreatePrivateMessageData>(this.context);
|
||||
get isoData(): IsoData<CreatePrivateMessageData> {
|
||||
return this.context.store.getState().value;
|
||||
}
|
||||
state: CreatePrivateMessageState = {
|
||||
siteRes: this.isoData.site_res,
|
||||
recipientRes: EMPTY_REQUEST,
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import { setIsoData } from "@utils/app";
|
||||
import { getQueryParams } from "@utils/helpers";
|
||||
import { QueryParams, RouteDataResponse } from "@utils/types";
|
||||
import { Component, linkEvent } from "inferno";
|
||||
|
@ -7,7 +6,7 @@ import {
|
|||
LemmyHttp,
|
||||
ResolveObjectResponse,
|
||||
} from "lemmy-js-client";
|
||||
import { InitialFetchRequest } from "../interfaces";
|
||||
import { InitialFetchRequest, IsoData } from "../interfaces";
|
||||
import { FirstLoadService, HttpService, I18NextService } from "../services";
|
||||
import {
|
||||
EMPTY_REQUEST,
|
||||
|
@ -84,7 +83,9 @@ const handleFollow = (i: RemoteFetch) => handleToggleFollow(i, true);
|
|||
const handleUnfollow = (i: RemoteFetch) => handleToggleFollow(i, false);
|
||||
|
||||
export class RemoteFetch extends Component<any, RemoteFetchState> {
|
||||
private isoData = setIsoData<RemoteFetchData>(this.context);
|
||||
get isoData(): IsoData<RemoteFetchData> {
|
||||
return this.context.store.getState().value;
|
||||
}
|
||||
state: RemoteFetchState = {
|
||||
resolveObjectRes: EMPTY_REQUEST,
|
||||
isIsomorphic: false,
|
||||
|
|
|
@ -8,7 +8,6 @@ import {
|
|||
getUpdatedSearchId,
|
||||
myAuth,
|
||||
personToChoice,
|
||||
setIsoData,
|
||||
showLocal,
|
||||
} from "@utils/app";
|
||||
import { restoreScrollPosition, saveScrollPosition } from "@utils/browser";
|
||||
|
@ -47,7 +46,7 @@ import {
|
|||
SortType,
|
||||
} from "lemmy-js-client";
|
||||
import { fetchLimit } from "../config";
|
||||
import { CommentViewType, InitialFetchRequest } from "../interfaces";
|
||||
import { CommentViewType, InitialFetchRequest, IsoData } from "../interfaces";
|
||||
import { FirstLoadService, I18NextService } from "../services";
|
||||
import {
|
||||
EMPTY_REQUEST,
|
||||
|
@ -241,7 +240,9 @@ function getListing(
|
|||
}
|
||||
|
||||
export class Search extends Component<any, SearchState> {
|
||||
private isoData = setIsoData<SearchData>(this.context);
|
||||
get isoData(): IsoData<SearchData> {
|
||||
return this.context.store.getState().value;
|
||||
}
|
||||
searchInput = createRef<HTMLInputElement>();
|
||||
|
||||
state: SearchState = {
|
||||
|
|
|
@ -20,7 +20,7 @@ export type IsoDataOptionalSite<T extends RouteData = any> = Partial<
|
|||
|
||||
declare global {
|
||||
interface Window {
|
||||
isoData: IsoData;
|
||||
isoData?: IsoDataOptionalSite;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,11 @@
|
|||
import { getHttpBase } from "@utils/env";
|
||||
import { LemmyHttp } from "lemmy-js-client";
|
||||
import { LemmyHttp, LoginResponse } from "lemmy-js-client";
|
||||
import { toast } from "../toast";
|
||||
import { I18NextService } from "./I18NextService";
|
||||
import { clearAuthCookie, isBrowser, setAuthCookie } from "@utils/browser";
|
||||
import { isAuthPath } from "@utils/app";
|
||||
import cookie from "cookie";
|
||||
import { authCookieName } from "../config";
|
||||
|
||||
export const EMPTY_REQUEST = {
|
||||
state: "empty",
|
||||
|
@ -56,7 +60,7 @@ class WrappedLemmyHttpClient {
|
|||
Object.getPrototypeOf(this.rawClient),
|
||||
)) {
|
||||
if (key !== "constructor") {
|
||||
this[key] = async (...args) => {
|
||||
this[key] = async (...args: any) => {
|
||||
try {
|
||||
const res = await this.rawClient[key](...args);
|
||||
|
||||
|
@ -88,6 +92,18 @@ export function wrapClient(client: LemmyHttp, silent = false) {
|
|||
) as unknown as WrappedLemmyHttp;
|
||||
}
|
||||
|
||||
// TODO These are unused for now
|
||||
// interface Claims {
|
||||
// sub: number;
|
||||
// iss: string;
|
||||
// iat: number;
|
||||
// }
|
||||
|
||||
// interface AuthInfo {
|
||||
// claims: Claims;
|
||||
// auth: string;
|
||||
// }
|
||||
|
||||
export class HttpService {
|
||||
static #_instance: HttpService;
|
||||
#silent_client: WrappedLemmyHttp;
|
||||
|
@ -95,10 +111,42 @@ export class HttpService {
|
|||
|
||||
private constructor() {
|
||||
const lemmyHttp = new LemmyHttp(getHttpBase());
|
||||
const auth = cookie.parse(document.cookie)[authCookieName];
|
||||
|
||||
if (auth) {
|
||||
HttpService.client.setHeaders({ Authorization: `Bearer ${auth}` });
|
||||
}
|
||||
this.#client = wrapClient(lemmyHttp);
|
||||
this.#silent_client = wrapClient(lemmyHttp, true);
|
||||
}
|
||||
|
||||
public login({
|
||||
res,
|
||||
showToast = true,
|
||||
}: {
|
||||
res: LoginResponse;
|
||||
showToast?: boolean;
|
||||
}) {
|
||||
if (isBrowser() && res.jwt) {
|
||||
showToast && toast(I18NextService.i18n.t("logged_in"));
|
||||
setAuthCookie(res.jwt);
|
||||
}
|
||||
}
|
||||
|
||||
public logout() {
|
||||
if (isBrowser()) {
|
||||
clearAuthCookie();
|
||||
}
|
||||
|
||||
this.#client.logout();
|
||||
|
||||
if (isAuthPath(location.pathname)) {
|
||||
location.replace("/");
|
||||
} else {
|
||||
location.reload();
|
||||
}
|
||||
}
|
||||
|
||||
static get #Instance() {
|
||||
return this.#_instance ?? (this.#_instance = new this());
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { UserService, HttpService } from "../services";
|
||||
import { HttpService } from "../services";
|
||||
import { updateUnreadCountsInterval } from "../config";
|
||||
import { poll } from "@utils/helpers";
|
||||
import { myAuth } from "@utils/app";
|
||||
|
|
|
@ -1,99 +0,0 @@
|
|||
import { isAuthPath } from "@utils/app";
|
||||
import { clearAuthCookie, isBrowser, setAuthCookie } from "@utils/browser";
|
||||
import * as cookie from "cookie";
|
||||
import { jwtDecode } from "jwt-decode";
|
||||
import { LoginResponse, MyUserInfo } from "lemmy-js-client";
|
||||
import { toast } from "../toast";
|
||||
import { I18NextService } from "./I18NextService";
|
||||
import { amAdmin } from "@utils/roles";
|
||||
import { HttpService } from ".";
|
||||
import { authCookieName } from "../config";
|
||||
|
||||
interface Claims {
|
||||
sub: number;
|
||||
iss: string;
|
||||
iat: number;
|
||||
}
|
||||
|
||||
interface AuthInfo {
|
||||
claims: Claims;
|
||||
auth: string;
|
||||
}
|
||||
|
||||
export class UserService {
|
||||
static #instance: UserService;
|
||||
public myUserInfo?: MyUserInfo;
|
||||
public authInfo?: AuthInfo;
|
||||
|
||||
private constructor() {
|
||||
this.#setAuthInfo();
|
||||
}
|
||||
|
||||
public login({
|
||||
res,
|
||||
showToast = true,
|
||||
}: {
|
||||
res: LoginResponse;
|
||||
showToast?: boolean;
|
||||
}) {
|
||||
if (isBrowser() && res.jwt) {
|
||||
showToast && toast(I18NextService.i18n.t("logged_in"));
|
||||
setAuthCookie(res.jwt);
|
||||
this.#setAuthInfo();
|
||||
}
|
||||
}
|
||||
|
||||
public logout() {
|
||||
this.authInfo = undefined;
|
||||
this.myUserInfo = undefined;
|
||||
|
||||
if (isBrowser()) {
|
||||
clearAuthCookie();
|
||||
}
|
||||
|
||||
HttpService.client.logout();
|
||||
|
||||
if (isAuthPath(location.pathname)) {
|
||||
location.replace("/");
|
||||
} else {
|
||||
location.reload();
|
||||
}
|
||||
}
|
||||
|
||||
public auth(throwErr = false): string | undefined {
|
||||
const auth = this.authInfo?.auth;
|
||||
|
||||
if (auth) {
|
||||
return auth;
|
||||
} else {
|
||||
const msg = "No JWT cookie found";
|
||||
|
||||
if (throwErr && isBrowser()) {
|
||||
console.error(msg);
|
||||
toast(I18NextService.i18n.t("not_logged_in"), "danger");
|
||||
}
|
||||
|
||||
return undefined;
|
||||
// throw msg;
|
||||
}
|
||||
}
|
||||
|
||||
#setAuthInfo() {
|
||||
if (isBrowser()) {
|
||||
const auth = cookie.parse(document.cookie)[authCookieName];
|
||||
|
||||
if (auth) {
|
||||
HttpService.client.setHeaders({ Authorization: `Bearer ${auth}` });
|
||||
this.authInfo = { auth, claims: jwtDecode(auth) };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public get moderatesSomething(): boolean {
|
||||
return amAdmin() || (this.myUserInfo?.moderates?.length ?? 0) > 0;
|
||||
}
|
||||
|
||||
public static get Instance() {
|
||||
return this.#instance || (this.#instance = new this());
|
||||
}
|
||||
}
|
|
@ -1,5 +1,4 @@
|
|||
export { FirstLoadService } from "./FirstLoadService";
|
||||
export { HttpService } from "./HttpService";
|
||||
export { I18NextService } from "./I18NextService";
|
||||
export { UserService } from "./UserService";
|
||||
export { UnreadCounterService } from "./UnreadCounterService";
|
||||
|
|
|
@ -43,7 +43,6 @@ import personToChoice from "./person-to-choice";
|
|||
import postToCommentSortType from "./post-to-comment-sort-type";
|
||||
import searchCommentTree from "./search-comment-tree";
|
||||
import selectableLanguages from "./selectable-languages";
|
||||
import setIsoData from "./set-iso-data";
|
||||
import setTheme from "./set-theme";
|
||||
import setupDateFns from "./setup-date-fns";
|
||||
import showAvatars from "./show-avatars";
|
||||
|
@ -55,6 +54,7 @@ import updatePersonBlock from "./update-person-block";
|
|||
import instanceToChoice from "./instance-to-choice";
|
||||
import updateInstanceBlock from "./update-instance-block";
|
||||
import isAnonymousPath from "./is-anonymous-path";
|
||||
import setupRedux from "./setup-redux";
|
||||
|
||||
export {
|
||||
buildCommentsTree,
|
||||
|
@ -102,11 +102,11 @@ export {
|
|||
postToCommentSortType,
|
||||
searchCommentTree,
|
||||
selectableLanguages,
|
||||
setIsoData,
|
||||
setTheme,
|
||||
setupDateFns,
|
||||
showAvatars,
|
||||
showLocal,
|
||||
setupRedux,
|
||||
showScores,
|
||||
siteBannerCss,
|
||||
updateCommunityBlock,
|
||||
|
|
|
@ -4,6 +4,7 @@ import { I18NextService, UserService } from "../../services";
|
|||
import { updateDataBsTheme } from "@utils/browser";
|
||||
|
||||
export default function initializeSite(site?: GetSiteResponse) {
|
||||
// TODO Should already be in siteRes
|
||||
UserService.Instance.myUserInfo = site?.my_user;
|
||||
updateDataBsTheme(site);
|
||||
I18NextService.i18n.changeLanguage();
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
import { MyUserInfo, PostView } from "lemmy-js-client";
|
||||
import { UserService } from "../../services";
|
||||
|
||||
export default function isPostBlocked(
|
||||
pv: PostView,
|
||||
myUserInfo: MyUserInfo | undefined = UserService.Instance.myUserInfo,
|
||||
myUserInfo?: MyUserInfo,
|
||||
): boolean {
|
||||
return (
|
||||
(myUserInfo?.community_blocks
|
||||
|
|
|
@ -1,6 +1,18 @@
|
|||
import { UserService } from "../../services";
|
||||
import { isBrowser } from "@utils/browser";
|
||||
import { toast } from "../../../shared/toast";
|
||||
import { I18NextService } from "../../services";
|
||||
|
||||
// Warning, do not use this in fetchInitialData
|
||||
export default function myAuth(): string | undefined {
|
||||
return UserService.Instance.auth();
|
||||
export default function myAuth(throwErr = false): string | undefined {
|
||||
if (auth) {
|
||||
return auth;
|
||||
} else {
|
||||
const msg = "No JWT cookie found";
|
||||
|
||||
if (throwErr && isBrowser()) {
|
||||
console.error(msg);
|
||||
toast(I18NextService.i18n.t("not_logged_in"), "danger");
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
import { PostView } from "lemmy-js-client";
|
||||
import { UserService } from "../../services";
|
||||
import { MyUserInfo, PostView } from "lemmy-js-client";
|
||||
|
||||
export default function nsfwCheck(
|
||||
pv: PostView,
|
||||
myUserInfo = UserService.Instance.myUserInfo,
|
||||
myUserInfo?: MyUserInfo,
|
||||
): boolean {
|
||||
const nsfw = pv.post.nsfw || pv.community.nsfw;
|
||||
const myShowNsfw = myUserInfo?.local_user_view.local_user.show_nsfw ?? false;
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import { Language } from "lemmy-js-client";
|
||||
import { UserService } from "../../services";
|
||||
import { Language, MyUserInfo } from "lemmy-js-client";
|
||||
|
||||
/**
|
||||
* This shows what language you can select
|
||||
|
@ -13,7 +12,7 @@ export default function selectableLanguages(
|
|||
siteLanguages: number[],
|
||||
showAll?: boolean,
|
||||
showSite?: boolean,
|
||||
myUserInfo = UserService.Instance.myUserInfo,
|
||||
myUserInfo?: MyUserInfo,
|
||||
): Language[] {
|
||||
const allLangIds = allLanguages.map(l => l.id);
|
||||
let myLangs = myUserInfo?.discussion_languages ?? allLangIds;
|
||||
|
|
|
@ -1,11 +0,0 @@
|
|||
import { isBrowser } from "@utils/browser";
|
||||
import { IsoData, RouteData } from "../../interfaces";
|
||||
|
||||
export default function setIsoData<T extends RouteData>(
|
||||
context: any,
|
||||
): IsoData<T> {
|
||||
// If its the browser, you need to deserialize the data from the window
|
||||
if (isBrowser()) {
|
||||
return window.isoData;
|
||||
} else return context.router.staticContext;
|
||||
}
|
13
src/shared/utils/app/setup-redux.ts
Normal file
13
src/shared/utils/app/setup-redux.ts
Normal file
|
@ -0,0 +1,13 @@
|
|||
import { configureStore, createSlice } from "@reduxjs/toolkit";
|
||||
import { IsoDataOptionalSite } from "../../../shared/interfaces";
|
||||
|
||||
// TODO add reducer function here
|
||||
export default function setupRedux(isoData?: IsoDataOptionalSite) {
|
||||
const slice = createSlice({
|
||||
name: "isoData",
|
||||
initialState: { value: isoData },
|
||||
reducers: {},
|
||||
});
|
||||
const store = configureStore({ reducer: slice.reducer });
|
||||
return store;
|
||||
}
|
|
@ -1,7 +1,5 @@
|
|||
import { UserService } from "../../services";
|
||||
import { MyUserInfo } from "lemmy-js-client";
|
||||
|
||||
export default function showAvatars(
|
||||
myUserInfo = UserService.Instance.myUserInfo,
|
||||
): boolean {
|
||||
export default function showAvatars(myUserInfo?: MyUserInfo): boolean {
|
||||
return myUserInfo?.local_user_view.local_user.show_avatars ?? true;
|
||||
}
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
import { UserService } from "../../services";
|
||||
import { MyUserInfo } from "lemmy-js-client";
|
||||
|
||||
export default function showScores(
|
||||
myUserInfo = UserService.Instance.myUserInfo,
|
||||
): boolean {
|
||||
export default function showScores(myUserInfo?: MyUserInfo): boolean {
|
||||
return myUserInfo?.local_user_view.local_user.show_scores ?? true;
|
||||
}
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
import { BlockCommunityResponse, MyUserInfo } from "lemmy-js-client";
|
||||
import { I18NextService, UserService } from "../../services";
|
||||
import { I18NextService } from "../../services";
|
||||
import { toast } from "../../toast";
|
||||
|
||||
export default function updateCommunityBlock(
|
||||
data: BlockCommunityResponse,
|
||||
myUserInfo: MyUserInfo | undefined = UserService.Instance.myUserInfo,
|
||||
myUserInfo?: MyUserInfo,
|
||||
) {
|
||||
if (myUserInfo) {
|
||||
if (data.blocked) {
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
import { BlockInstanceResponse, Instance, MyUserInfo } from "lemmy-js-client";
|
||||
import { I18NextService, UserService } from "../../services";
|
||||
import { I18NextService } from "../../services";
|
||||
import { toast } from "../../toast";
|
||||
|
||||
export default function updateInstanceBlock(
|
||||
data: BlockInstanceResponse,
|
||||
id: number,
|
||||
linkedInstances: Instance[],
|
||||
myUserInfo: MyUserInfo | undefined = UserService.Instance.myUserInfo,
|
||||
myUserInfo?: MyUserInfo,
|
||||
) {
|
||||
if (myUserInfo) {
|
||||
const instance = linkedInstances.find(i => i.id === id)!;
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
import { BlockPersonResponse, MyUserInfo } from "lemmy-js-client";
|
||||
import { I18NextService, UserService } from "../../services";
|
||||
import { I18NextService } from "../../services";
|
||||
import { toast } from "../../toast";
|
||||
|
||||
export default function updatePersonBlock(
|
||||
data: BlockPersonResponse,
|
||||
myUserInfo: MyUserInfo | undefined = UserService.Instance.myUserInfo,
|
||||
myUserInfo?: MyUserInfo,
|
||||
) {
|
||||
if (myUserInfo) {
|
||||
if (data.blocked) {
|
||||
|
|
0
src/shared/utils/app/update-redux.ts
Normal file
0
src/shared/utils/app/update-redux.ts
Normal file
|
@ -1,7 +1,5 @@
|
|||
import { UserService } from "../../services";
|
||||
import { MyUserInfo } from "lemmy-js-client";
|
||||
|
||||
export default function amAdmin(
|
||||
myUserInfo = UserService.Instance.myUserInfo,
|
||||
): boolean {
|
||||
export default function amAdmin(myUserInfo?: MyUserInfo): boolean {
|
||||
return myUserInfo?.local_user_view.local_user.admin ?? false;
|
||||
}
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
import { CommunityModeratorView } from "lemmy-js-client";
|
||||
import { UserService } from "../../services";
|
||||
import { CommunityModeratorView, MyUserInfo } from "lemmy-js-client";
|
||||
|
||||
export default function amCommunityCreator(
|
||||
creator_id: number,
|
||||
mods?: CommunityModeratorView[],
|
||||
myUserInfo = UserService.Instance.myUserInfo,
|
||||
myUserInfo?: MyUserInfo,
|
||||
): boolean {
|
||||
const myId = myUserInfo?.local_user_view.person.id;
|
||||
// Don't allow mod actions on yourself
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
import { CommunityId } from "lemmy-js-client";
|
||||
import { UserService } from "../../services";
|
||||
import { CommunityId, MyUserInfo } from "lemmy-js-client";
|
||||
|
||||
export default function amMod(
|
||||
communityId: CommunityId,
|
||||
myUserInfo = UserService.Instance.myUserInfo,
|
||||
myUserInfo?: MyUserInfo,
|
||||
): boolean {
|
||||
return myUserInfo
|
||||
? myUserInfo.moderates.map(cmv => cmv.community.id).includes(communityId)
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
import { PersonView } from "lemmy-js-client";
|
||||
import { UserService } from "../../services";
|
||||
import { MyUserInfo, PersonView } from "lemmy-js-client";
|
||||
|
||||
export default function amSiteCreator(
|
||||
creator_id: number,
|
||||
admins?: PersonView[],
|
||||
myUserInfo = UserService.Instance.myUserInfo,
|
||||
myUserInfo?: MyUserInfo,
|
||||
): boolean {
|
||||
const myId = myUserInfo?.local_user_view.person.id;
|
||||
return myId === admins?.at(0)?.person.id && myId !== creator_id;
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
import { CommunityModeratorView } from "lemmy-js-client";
|
||||
import { UserService } from "../../services";
|
||||
import { CommunityModeratorView, MyUserInfo } from "lemmy-js-client";
|
||||
|
||||
export default function amTopMod(
|
||||
mods: CommunityModeratorView[],
|
||||
myUserInfo = UserService.Instance.myUserInfo,
|
||||
myUserInfo?: MyUserInfo,
|
||||
): boolean {
|
||||
return mods.at(0)?.moderator.id === myUserInfo?.local_user_view.person.id;
|
||||
}
|
||||
|
|
|
@ -1,11 +1,10 @@
|
|||
import { canMod } from "@utils/roles";
|
||||
import { PersonView } from "lemmy-js-client";
|
||||
import { UserService } from "../../services";
|
||||
import { MyUserInfo, PersonView } from "lemmy-js-client";
|
||||
|
||||
export default function canAdmin(
|
||||
creatorId: number,
|
||||
admins?: PersonView[],
|
||||
myUserInfo = UserService.Instance.myUserInfo,
|
||||
myUserInfo?: MyUserInfo,
|
||||
onSelf = false,
|
||||
): boolean {
|
||||
return canMod(creatorId, undefined, admins, myUserInfo, onSelf);
|
||||
|
|
|
@ -1,12 +1,8 @@
|
|||
import { amAdmin } from "@utils/roles";
|
||||
import { GetSiteResponse } from "lemmy-js-client";
|
||||
import { UserService } from "../../services";
|
||||
|
||||
export default function canCreateCommunity(
|
||||
siteRes: GetSiteResponse,
|
||||
myUserInfo = UserService.Instance.myUserInfo,
|
||||
): boolean {
|
||||
export default function canCreateCommunity(siteRes: GetSiteResponse): boolean {
|
||||
const adminOnly = siteRes.site_view.local_site.community_creation_admin_only;
|
||||
// TODO: Make this check if user is logged on as well
|
||||
return !adminOnly || amAdmin(myUserInfo);
|
||||
return !adminOnly || amAdmin(siteRes.my_user);
|
||||
}
|
||||
|
|
|
@ -1,11 +1,14 @@
|
|||
import { CommunityModeratorView, PersonView } from "lemmy-js-client";
|
||||
import { UserService } from "../../services";
|
||||
import {
|
||||
CommunityModeratorView,
|
||||
MyUserInfo,
|
||||
PersonView,
|
||||
} from "lemmy-js-client";
|
||||
|
||||
export default function canMod(
|
||||
creator_id: number,
|
||||
mods?: CommunityModeratorView[],
|
||||
admins?: PersonView[],
|
||||
myUserInfo = UserService.Instance.myUserInfo,
|
||||
myUserInfo?: MyUserInfo,
|
||||
onSelf = false,
|
||||
): boolean {
|
||||
// You can do moderator actions only on the mods added after you.
|
||||
|
|
|
@ -7,6 +7,7 @@ import canAdmin from "./can-admin";
|
|||
import canCreateCommunity from "./can-create-community";
|
||||
import canMod from "./can-mod";
|
||||
import isBanned from "./is-banned";
|
||||
import moderatesSomething from "./moderates-something";
|
||||
|
||||
export {
|
||||
amAdmin,
|
||||
|
@ -18,4 +19,5 @@ export {
|
|||
canCreateCommunity,
|
||||
canMod,
|
||||
isBanned,
|
||||
moderatesSomething,
|
||||
};
|
||||
|
|
6
src/shared/utils/roles/moderates-something.ts
Normal file
6
src/shared/utils/roles/moderates-something.ts
Normal file
|
@ -0,0 +1,6 @@
|
|||
import { MyUserInfo } from "lemmy-js-client";
|
||||
import amAdmin from "./am-admin";
|
||||
|
||||
export default function moderatesSomething(myUserInfo?: MyUserInfo): boolean {
|
||||
return amAdmin(myUserInfo) || (myUserInfo?.moderates?.length ?? 0) > 0;
|
||||
}
|
38
yarn.lock
38
yarn.lock
|
@ -1217,6 +1217,16 @@
|
|||
resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.11.8.tgz#6b79032e760a0899cd4204710beede972a3a185f"
|
||||
integrity sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==
|
||||
|
||||
"@reduxjs/toolkit@^2.0.1":
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@reduxjs/toolkit/-/toolkit-2.0.1.tgz#0a5233c1e35c1941b03aece39cceade3467a1062"
|
||||
integrity sha512-fxIjrR9934cmS8YXIGd9e7s1XRsEU++aFc9DVNMFMRTM5Vtsg2DCRMj21eslGtDt43IUf9bJL3h5bwUlZleibA==
|
||||
dependencies:
|
||||
immer "^10.0.3"
|
||||
redux "^5.0.0"
|
||||
redux-thunk "^3.1.0"
|
||||
reselect "^5.0.1"
|
||||
|
||||
"@rollup/plugin-babel@^5.2.0":
|
||||
version "5.3.1"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/plugin-babel/-/plugin-babel-5.3.1.tgz#04bc0608f4aa4b2e4b1aebf284344d0f68fda283"
|
||||
|
@ -4829,6 +4839,11 @@ ignore@^5.2.0, ignore@^5.2.4:
|
|||
resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.0.tgz#67418ae40d34d6999c95ff56016759c718c82f78"
|
||||
integrity sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg==
|
||||
|
||||
immer@^10.0.3:
|
||||
version "10.0.3"
|
||||
resolved "https://registry.yarnpkg.com/immer/-/immer-10.0.3.tgz#a8de42065e964aa3edf6afc282dfc7f7f34ae3c9"
|
||||
integrity sha512-pwupu3eWfouuaowscykeckFmVTpqbzW+rXFCX8rQLkZzM9ftBmU/++Ra+o+L27mz03zJTlyV4UUr+fdKNffo4A==
|
||||
|
||||
immutable@^4.0.0:
|
||||
version "4.3.4"
|
||||
resolved "https://registry.yarnpkg.com/immutable/-/immutable-4.3.4.tgz#2e07b33837b4bb7662f288c244d1ced1ef65a78f"
|
||||
|
@ -4969,6 +4984,14 @@ inferno-i18next-dess@0.0.2:
|
|||
inferno-shared "^8.0.3"
|
||||
inferno-vnode-flags "^8.0.3"
|
||||
|
||||
inferno-redux@^8.2.2:
|
||||
version "8.2.2"
|
||||
resolved "https://registry.yarnpkg.com/inferno-redux/-/inferno-redux-8.2.2.tgz#1df3520f169def67d616d3ba6b54e5b70a59948f"
|
||||
integrity sha512-2H+lYaunRh9jJ92m4JWEDDaM86SeexMg68lf4iJcjs47rJU0GnLYyme508EW3WsIfO9f1say9j9EDzoeHrNTNQ==
|
||||
dependencies:
|
||||
hoist-non-inferno-statics "^1.1.3"
|
||||
inferno "8.2.2"
|
||||
|
||||
inferno-router@^8.2.2:
|
||||
version "8.2.2"
|
||||
resolved "https://registry.yarnpkg.com/inferno-router/-/inferno-router-8.2.2.tgz#3d13e2610ecb8f6bb3e36421ab569c21777a0d23"
|
||||
|
@ -7719,6 +7742,16 @@ rechoir@^0.8.0:
|
|||
dependencies:
|
||||
resolve "^1.20.0"
|
||||
|
||||
redux-thunk@^3.1.0:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/redux-thunk/-/redux-thunk-3.1.0.tgz#94aa6e04977c30e14e892eae84978c1af6058ff3"
|
||||
integrity sha512-NW2r5T6ksUKXCabzhL9z+h206HQw/NJkcLm1GPImRQ8IzfXwRGqjVhKJGauHirT0DAuyy6hjdnMZaRoAcy0Klw==
|
||||
|
||||
redux@^5.0.0:
|
||||
version "5.0.0"
|
||||
resolved "https://registry.yarnpkg.com/redux/-/redux-5.0.0.tgz#29572e29a439e094ff8fec46883fc45053f6736d"
|
||||
integrity sha512-blLIYmYetpZMET6Q6uCY7Jtl/Im5OBldy+vNPauA8vvsdqyt66oep4EUpAMWNHauTC6xa9JuRPhRB72rY82QGA==
|
||||
|
||||
reflect.getprototypeof@^1.0.4:
|
||||
version "1.0.4"
|
||||
resolved "https://registry.yarnpkg.com/reflect.getprototypeof/-/reflect.getprototypeof-1.0.4.tgz#aaccbf41aca3821b87bb71d9dcbc7ad0ba50a3f3"
|
||||
|
@ -7849,6 +7882,11 @@ requires-port@^1.0.0:
|
|||
resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff"
|
||||
integrity sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==
|
||||
|
||||
reselect@^5.0.1:
|
||||
version "5.0.1"
|
||||
resolved "https://registry.yarnpkg.com/reselect/-/reselect-5.0.1.tgz#587cdaaeb4e0e8927cff80ebe2bbef05f74b1648"
|
||||
integrity sha512-D72j2ubjgHpvuCiORWkOUxndHJrxDaSolheiz5CO+roz8ka97/4msh2E8F5qay4GawR5vzBt5MkbDHT+Rdy/Wg==
|
||||
|
||||
resolve-cwd@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-3.0.0.tgz#0f0075f1bb2544766cf73ba6a6e2adfebcb13f2d"
|
||||
|
|
Loading…
Reference in a new issue