About 1/3rd done with adding redux.

This commit is contained in:
Dessalines 2023-12-05 22:12:54 -05:00
parent fc234716b0
commit 4298c3fb91
75 changed files with 499 additions and 373 deletions

View file

@ -43,6 +43,7 @@
"@babel/preset-typescript": "^7.21.5", "@babel/preset-typescript": "^7.21.5",
"@babel/runtime": "^7.21.5", "@babel/runtime": "^7.21.5",
"@emoji-mart/data": "^1.1.0", "@emoji-mart/data": "^1.1.0",
"@reduxjs/toolkit": "^2.0.1",
"@shortcm/qr-image": "^9.0.2", "@shortcm/qr-image": "^9.0.2",
"autosize": "^6.0.1", "autosize": "^6.0.1",
"babel-loader": "^9.1.3", "babel-loader": "^9.1.3",
@ -67,6 +68,7 @@
"inferno-helmet": "^5.2.1", "inferno-helmet": "^5.2.1",
"inferno-hydrate": "^8.2.2", "inferno-hydrate": "^8.2.2",
"inferno-i18next-dess": "0.0.2", "inferno-i18next-dess": "0.0.2",
"inferno-redux": "^8.2.2",
"inferno-router": "^8.2.2", "inferno-router": "^8.2.2",
"inferno-server": "^8.2.2", "inferno-server": "^8.2.2",
"jwt-decode": "^4.0.0", "jwt-decode": "^4.0.0",
@ -83,6 +85,7 @@
"markdown-it-sub": "^1.0.0", "markdown-it-sub": "^1.0.0",
"markdown-it-sup": "^1.0.0", "markdown-it-sup": "^1.0.0",
"mini-css-extract-plugin": "^2.7.5", "mini-css-extract-plugin": "^2.7.5",
"redux": "^5.0.0",
"register-service-worker": "^1.7.2", "register-service-worker": "^1.7.2",
"run-node-webpack-plugin": "^1.3.0", "run-node-webpack-plugin": "^1.3.0",
"rxjs": "^7.8.1", "rxjs": "^7.8.1",

View file

@ -1,4 +1,4 @@
import { initializeSite, setupDateFns } from "@utils/app"; import { initializeSite, setupDateFns, setupRedux } from "@utils/app";
import { hydrate } from "inferno-hydrate"; import { hydrate } from "inferno-hydrate";
import { BrowserRouter } from "inferno-router"; import { BrowserRouter } from "inferno-router";
import { App } from "../shared/components/app/app"; 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/collapse";
import "bootstrap/js/dist/dropdown"; import "bootstrap/js/dist/dropdown";
import "bootstrap/js/dist/modal"; import "bootstrap/js/dist/modal";
import { Provider } from "inferno-redux";
async function startClient() { async function startClient() {
initializeSite(window.isoData.site_res); const windowData = window.isoData;
delete window.isoData;
initializeSite(windowData?.site_res);
await setupDateFns(); await setupDateFns();
const store = setupRedux(windowData);
const wrapper = ( const wrapper = (
<BrowserRouter> <Provider store={store}>
<App /> <BrowserRouter>
</BrowserRouter> <App />
</BrowserRouter>
</Provider>
); );
const root = document.getElementById("root"); const root = document.getElementById("root");

View file

@ -20,6 +20,8 @@ import { createSsrHtml } from "../utils/create-ssr-html";
import { getErrorPageData } from "../utils/get-error-page-data"; import { getErrorPageData } from "../utils/get-error-page-data";
import { setForwardedHeaders } from "../utils/set-forwarded-headers"; import { setForwardedHeaders } from "../utils/set-forwarded-headers";
import { getJwtCookie } from "../utils/has-jwt-cookie"; 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) => { export default async (req: Request, res: Response) => {
try { try {
@ -108,10 +110,19 @@ export default async (req: Request, res: Response) => {
errorPageData, errorPageData,
}; };
const slice = createSlice({
name: "isoData",
initialState: { value: isoData },
reducers: {},
});
const store = configureStore({ reducer: slice.reducer });
const wrapper = ( const wrapper = (
<StaticRouter location={url} context={isoData}> <Provider store={store}>
<App /> <StaticRouter location={url} context={{}}>
</StaticRouter> <App />
</StaticRouter>
</Provider>
); );
const root = renderToString(wrapper); const root = renderToString(wrapper);

View file

@ -1,4 +1,4 @@
import { isAnonymousPath, isAuthPath, setIsoData } from "@utils/app"; import { isAnonymousPath, isAuthPath } from "@utils/app";
import { dataBsTheme } from "@utils/browser"; import { dataBsTheme } from "@utils/browser";
import { Component, RefObject, createRef, linkEvent } from "inferno"; import { Component, RefObject, createRef, linkEvent } from "inferno";
import { Provider } from "inferno-i18next-dess"; import { Provider } from "inferno-i18next-dess";
@ -17,20 +17,20 @@ import AnonymousGuard from "../common/anonymous-guard";
import { CodeTheme } from "./code-theme"; import { CodeTheme } from "./code-theme";
export class App extends Component<any, any> { export class App extends Component<any, any> {
private isoData: IsoDataOptionalSite = setIsoData(this.context);
private readonly mainContentRef: RefObject<HTMLElement>; private readonly mainContentRef: RefObject<HTMLElement>;
constructor(props: any, context: any) { constructor(props: any, context: any) {
super(props, context); super(props, context);
this.mainContentRef = createRef(); this.mainContentRef = createRef();
} }
handleJumpToContent(event) { handleJumpToContent(event: any) {
event.preventDefault(); event.preventDefault();
this.mainContentRef.current?.focus(); this.mainContentRef.current?.focus();
} }
render() { 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; const siteView = siteRes?.site_view;
return ( return (

View file

@ -1,4 +1,3 @@
import { setIsoData } from "@utils/app";
import { Component } from "inferno"; import { Component } from "inferno";
import { T } from "inferno-i18next-dess"; import { T } from "inferno-i18next-dess";
import { Link } from "inferno-router"; import { Link } from "inferno-router";
@ -6,14 +5,13 @@ import { IsoDataOptionalSite } from "../../interfaces";
import { I18NextService } from "../../services"; import { I18NextService } from "../../services";
export class ErrorPage extends Component<any, any> { export class ErrorPage extends Component<any, any> {
private isoData: IsoDataOptionalSite = setIsoData(this.context);
constructor(props: any, context: any) { constructor(props: any, context: any) {
super(props, context); super(props, context);
} }
render() { render() {
const { errorPageData } = this.isoData; const reduxState: IsoDataOptionalSite = this.context.store.getState();
const errorPageData = reduxState.errorPageData;
return ( return (
<div className="error-page container-lg text-center"> <div className="error-page container-lg text-center">
@ -41,8 +39,7 @@ export class ErrorPage extends Component<any, any> {
<div> <div>
{I18NextService.i18n.t("error_page_admin_matrix", { {I18NextService.i18n.t("error_page_admin_matrix", {
instance: instance:
this.isoData.site_res?.site_view.site.name ?? reduxState.site_res?.site_view.site.name ?? "this instance",
"this instance",
})} })}
</div> </div>
<ul className="mx-auto mt-2" style={{ width: "fit-content" }}> <ul className="mx-auto mt-2" style={{ width: "fit-content" }}>

View file

@ -1,15 +1,15 @@
import { showAvatars } from "@utils/app"; import { showAvatars } from "@utils/app";
import { isBrowser } from "@utils/browser"; import { isBrowser } from "@utils/browser";
import { numToSI } from "@utils/helpers"; 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 { Component, createRef, linkEvent } from "inferno";
import { NavLink } from "inferno-router"; import { NavLink } from "inferno-router";
import { GetSiteResponse } from "lemmy-js-client"; import { GetSiteResponse } from "lemmy-js-client";
import { donateLemmyUrl } from "../../config"; import { donateLemmyUrl } from "../../config";
import { import {
I18NextService, I18NextService,
UserService,
UnreadCounterService, UnreadCounterService,
HttpService,
} from "../../services"; } from "../../services";
import { toast } from "../../toast"; import { toast } from "../../toast";
import { Icon } from "../common/icon"; import { Icon } from "../common/icon";
@ -38,7 +38,7 @@ function handleCollapseClick(i: Navbar) {
} }
function handleLogOut(i: Navbar) { function handleLogOut(i: Navbar) {
UserService.Instance.logout(); HttpService._Instance.logout();
handleCollapseClick(i); handleCollapseClick(i);
} }
@ -94,7 +94,7 @@ export class Navbar extends Component<NavbarProps, NavbarState> {
// TODO class active corresponding to current pages // TODO class active corresponding to current pages
render() { render() {
const siteView = this.props.siteRes?.site_view; 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 ( return (
<div className="shadow-sm"> <div className="shadow-sm">
<nav <nav
@ -108,9 +108,10 @@ export class Navbar extends Component<NavbarProps, NavbarState> {
className="d-flex align-items-center navbar-brand me-md-3" className="d-flex align-items-center navbar-brand me-md-3"
onMouseUp={linkEvent(this, handleCollapseClick)} onMouseUp={linkEvent(this, handleCollapseClick)}
> >
{siteView?.site.icon && showAvatars() && ( {siteView?.site.icon &&
<PictrsImage src={siteView.site.icon} icon /> showAvatars(this.props.siteRes?.my_user) && (
)} <PictrsImage src={siteView.site.icon} icon />
)}
{siteView?.site.name} {siteView?.site.name}
</NavLink> </NavLink>
{person && ( {person && (
@ -133,7 +134,7 @@ export class Navbar extends Component<NavbarProps, NavbarState> {
)} )}
</NavLink> </NavLink>
</li> </li>
{UserService.Instance.moderatesSomething && ( {moderatesSomething(this.props.siteRes?.my_user) && (
<li className="nav-item nav-item-icon"> <li className="nav-item nav-item-icon">
<NavLink <NavLink
to="/reports" to="/reports"
@ -306,7 +307,7 @@ export class Navbar extends Component<NavbarProps, NavbarState> {
)} )}
</NavLink> </NavLink>
</li> </li>
{UserService.Instance.moderatesSomething && ( {moderatesSomething(this.props.siteRes?.my_user) && (
<li id="navModeration" className="nav-item"> <li id="navModeration" className="nav-item">
<NavLink <NavLink
className="nav-link d-inline-flex align-items-center d-md-inline-block" 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() { requestNotificationPermission() {
if (UserService.Instance.myUserInfo) { if (this.props.siteRes?.my_user) {
document.addEventListener("DOMContentLoaded", function () { document.addEventListener("DOMContentLoaded", function () {
if (!Notification) { if (!Notification) {
toast(I18NextService.i18n.t("notifications_error"), "danger"); toast(I18NextService.i18n.t("notifications_error"), "danger");

View file

@ -1,14 +1,15 @@
import { Component } from "inferno"; import { Component } from "inferno";
import { Helmet } from "inferno-helmet"; import { Helmet } from "inferno-helmet";
import { UserService } from "../../services"; import { MyUserInfo } from "lemmy-js-client";
interface Props { interface Props {
defaultTheme: string; defaultTheme: string;
myUserInfo?: MyUserInfo;
} }
export class Theme extends Component<Props> { export class Theme extends Component<Props> {
render() { render() {
const user = UserService.Instance.myUserInfo; const user = this.props.myUserInfo;
const hasTheme = user?.local_user_view.local_user.theme !== "browser"; const hasTheme = user?.local_user_view.local_user.theme !== "browser";
if (user && hasTheme) { if (user && hasTheme) {

View file

@ -4,7 +4,7 @@ import { T } from "inferno-i18next-dess";
import { Link } from "inferno-router"; import { Link } from "inferno-router";
import { CreateComment, EditComment, Language } from "lemmy-js-client"; import { CreateComment, EditComment, Language } from "lemmy-js-client";
import { CommentNodeI } from "../../interfaces"; import { CommentNodeI } from "../../interfaces";
import { I18NextService, UserService } from "../../services"; import { I18NextService } from "../../services";
import { Icon } from "../common/icon"; import { Icon } from "../common/icon";
import { MarkdownTextArea } from "../common/markdown-textarea"; 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. * Can either be the parent, or the editable comment. The right side is a postId.
*/ */
node: CommentNodeI | number; node: CommentNodeI | number;
loggedIn: boolean;
finished?: boolean; finished?: boolean;
edit?: boolean; edit?: boolean;
disabled?: boolean; disabled?: boolean;
@ -45,7 +46,7 @@ export class CommentForm extends Component<CommentFormProps, any> {
" ", " ",
)} )}
> >
{UserService.Instance.myUserInfo ? ( {this.props.loggedIn ? (
<MarkdownTextArea <MarkdownTextArea
initialContent={initialContent} initialContent={initialContent}
showLanguage showLanguage

View file

@ -27,6 +27,7 @@ import {
Language, Language,
MarkCommentReplyAsRead, MarkCommentReplyAsRead,
MarkPersonMentionAsRead, MarkPersonMentionAsRead,
MyUserInfo,
PersonMentionView, PersonMentionView,
PersonView, PersonView,
PurgeComment, PurgeComment,
@ -45,7 +46,7 @@ import {
VoteContentType, VoteContentType,
} from "../../interfaces"; } from "../../interfaces";
import { mdToHtml, mdToHtmlNoImages } from "../../markdown"; import { mdToHtml, mdToHtmlNoImages } from "../../markdown";
import { I18NextService, UserService } from "../../services"; import { I18NextService } from "../../services";
import { setupTippy } from "../../tippy"; import { setupTippy } from "../../tippy";
import { Icon, PurgeWarning, Spinner } from "../common/icon"; import { Icon, PurgeWarning, Spinner } from "../common/icon";
import { MomentTime } from "../common/moment-time"; import { MomentTime } from "../common/moment-time";
@ -97,6 +98,7 @@ interface CommentNodeState {
interface CommentNodeProps { interface CommentNodeProps {
node: CommentNodeI; node: CommentNodeI;
myUserInfo?: MyUserInfo;
moderators?: CommunityModeratorView[]; moderators?: CommunityModeratorView[];
admins?: PersonView[]; admins?: PersonView[];
noBorder?: boolean; noBorder?: boolean;
@ -238,14 +240,18 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
cv.creator.id, cv.creator.id,
this.props.moderators, this.props.moderators,
this.props.admins, this.props.admins,
UserService.Instance.myUserInfo, this.props.myUserInfo,
true, 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( const canAdminOnSelf = canAdmin(
cv.creator.id, cv.creator.id,
this.props.admins, this.props.admins,
UserService.Instance.myUserInfo, this.props.myUserInfo,
true, true,
); );
const isMod_ = cv.creator_is_moderator; const isMod_ = cv.creator_is_moderator;
@ -253,6 +259,7 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
const amCommunityCreator_ = amCommunityCreator( const amCommunityCreator_ = amCommunityCreator(
cv.creator.id, cv.creator.id,
this.props.moderators, this.props.moderators,
this.props.myUserInfo,
); );
const moreRepliesBorderColor = this.props.node.depth const moreRepliesBorderColor = this.props.node.depth
@ -327,7 +334,7 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
{/* This is an expanding spacer for mobile */} {/* This is an expanding spacer for mobile */}
<div className="me-lg-5 flex-grow-1 flex-lg-grow-0 unselectable pointer mx-2" /> <div className="me-lg-5 flex-grow-1 flex-lg-grow-0 unselectable pointer mx-2" />
{showScores() && ( {showScores(this.props.myUserInfo) && (
<> <>
<span <span
className={`me-1 fw-bold ${this.scoreColor}`} className={`me-1 fw-bold ${this.scoreColor}`}
@ -352,6 +359,7 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
{this.state.showEdit && ( {this.state.showEdit && (
<CommentForm <CommentForm
node={node} node={node}
loggedIn={!!this.props.myUserInfo}
edit edit
onReplyCancel={this.handleReplyCancel} onReplyCancel={this.handleReplyCancel}
disabled={this.props.locked} disabled={this.props.locked}
@ -410,7 +418,7 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
)} )}
</button> </button>
)} )}
{UserService.Instance.myUserInfo && !this.props.viewOnly && ( {this.props.myUserInfo && !this.props.viewOnly && (
<> <>
<VoteButtonsCompact <VoteButtonsCompact
voteContentType={VoteContentType.Comment} voteContentType={VoteContentType.Comment}
@ -1067,6 +1075,7 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
{this.state.showReply && ( {this.state.showReply && (
<CommentForm <CommentForm
node={node} node={node}
loggedIn={!!this.props.myUserInfo}
onReplyCancel={this.handleReplyCancel} onReplyCancel={this.handleReplyCancel}
disabled={this.props.locked} disabled={this.props.locked}
finished={this.props.finished.get( finished={this.props.finished.get(
@ -1082,6 +1091,7 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
{!this.state.collapsed && node.children.length > 0 && ( {!this.state.collapsed && node.children.length > 0 && (
<CommentNodes <CommentNodes
nodes={node.children} nodes={node.children}
myUserInfo={this.props.myUserInfo}
locked={this.props.locked} locked={this.props.locked}
moderators={this.props.moderators} moderators={this.props.moderators}
admins={this.props.admins} admins={this.props.admins}
@ -1166,7 +1176,7 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
get myComment(): boolean { get myComment(): boolean {
return ( return (
UserService.Instance.myUserInfo?.local_user_view.person.id === this.props.myUserInfo?.local_user_view.person.id ===
this.commentView.creator.id this.commentView.creator.id
); );
} }

View file

@ -19,6 +19,7 @@ import {
Language, Language,
MarkCommentReplyAsRead, MarkCommentReplyAsRead,
MarkPersonMentionAsRead, MarkPersonMentionAsRead,
MyUserInfo,
PersonView, PersonView,
PurgeComment, PurgeComment,
PurgePerson, PurgePerson,
@ -31,6 +32,7 @@ import { CommentNode } from "./comment-node";
interface CommentNodesProps { interface CommentNodesProps {
nodes: CommentNodeI[]; nodes: CommentNodeI[];
myUserInfo?: MyUserInfo;
moderators?: CommunityModeratorView[]; moderators?: CommunityModeratorView[];
admins?: PersonView[]; admins?: PersonView[];
maxCommentsShown?: number; maxCommentsShown?: number;
@ -99,6 +101,7 @@ export class CommentNodes extends Component<CommentNodesProps, any> {
<CommentNode <CommentNode
key={node.comment_view.comment.id} key={node.comment_view.comment.id}
node={node} node={node}
myUserInfo={this.props.myUserInfo}
noBorder={this.props.noBorder} noBorder={this.props.noBorder}
isTopLevel={this.props.isTopLevel} isTopLevel={this.props.isTopLevel}
viewOnly={this.props.viewOnly} viewOnly={this.props.viewOnly}

View file

@ -3,6 +3,7 @@ import { T } from "inferno-i18next-dess";
import { import {
CommentReportView, CommentReportView,
CommentView, CommentView,
MyUserInfo,
ResolveCommentReport, ResolveCommentReport,
} from "lemmy-js-client"; } from "lemmy-js-client";
import { CommentNodeI, CommentViewType } from "../../interfaces"; import { CommentNodeI, CommentViewType } from "../../interfaces";
@ -14,6 +15,7 @@ import { EMPTY_REQUEST } from "../../services/HttpService";
interface CommentReportProps { interface CommentReportProps {
report: CommentReportView; report: CommentReportView;
myUserInfo?: MyUserInfo;
onResolveReport(form: ResolveCommentReport): void; onResolveReport(form: ResolveCommentReport): void;
} }
@ -75,6 +77,7 @@ export class CommentReport extends Component<
<div className="comment-report"> <div className="comment-report">
<CommentNode <CommentNode
node={node} node={node}
myUserInfo={this.props.myUserInfo}
viewType={CommentViewType.Flat} viewType={CommentViewType.Flat}
enableDownvotes={true} enableDownvotes={true}
viewOnly={true} viewOnly={true}

View file

@ -1,17 +1,17 @@
import { setIsoData } from "@utils/app";
import { Component } from "inferno"; import { Component } from "inferno";
import { ErrorPage } from "../app/error-page"; import { ErrorPage } from "../app/error-page";
import { IsoDataOptionalSite } from "../../interfaces";
class ErrorGuard extends Component<any, any> { class ErrorGuard extends Component<any, any> {
private isoData = setIsoData(this.context);
constructor(props: any, context: any) { constructor(props: any, context: any) {
super(props, context); super(props, context);
} }
render() { render() {
const errorPageData = this.isoData.errorPageData; const reduxState: IsoDataOptionalSite = this.context.store.getState().value;
const siteRes = this.isoData.site_res; const errorPageData = reduxState.errorPageData;
const siteRes = reduxState.site_res;
console.log(`error guard data: ${reduxState.path}`);
if (errorPageData || !siteRes) { if (errorPageData || !siteRes) {
return <ErrorPage />; return <ErrorPage />;

View file

@ -2,12 +2,13 @@ import { selectableLanguages } from "@utils/app";
import { randomStr } from "@utils/helpers"; import { randomStr } from "@utils/helpers";
import classNames from "classnames"; import classNames from "classnames";
import { Component, linkEvent } from "inferno"; import { Component, linkEvent } from "inferno";
import { Language } from "lemmy-js-client"; import { Language, MyUserInfo } from "lemmy-js-client";
import { I18NextService, UserService } from "../../services"; import { I18NextService } from "../../services";
import { Icon } from "./icon"; import { Icon } from "./icon";
interface LanguageSelectProps { interface LanguageSelectProps {
allLanguages: Language[]; allLanguages: Language[];
myUserInfo?: MyUserInfo;
siteLanguages: number[]; siteLanguages: number[];
selectedLanguageIds?: number[]; selectedLanguageIds?: number[];
multiple?: boolean; multiple?: boolean;
@ -97,7 +98,7 @@ export class LanguageSelect extends Component<LanguageSelectProps, any> {
this.props.siteLanguages, this.props.siteLanguages,
this.props.showAll, this.props.showAll,
this.props.showSite, this.props.showSite,
UserService.Instance.myUserInfo, this.props.myUserInfo,
); );
return ( return (

View file

@ -5,7 +5,7 @@ import classNames from "classnames";
import { NoOptionI18nKeys } from "i18next"; import { NoOptionI18nKeys } from "i18next";
import { Component, linkEvent } from "inferno"; import { Component, linkEvent } from "inferno";
import { Prompt } from "inferno-router"; import { Prompt } from "inferno-router";
import { Language } from "lemmy-js-client"; import { Language, MyUserInfo } from "lemmy-js-client";
import { import {
concurrentImageUpload, concurrentImageUpload,
markdownFieldCharacterLimit, markdownFieldCharacterLimit,
@ -14,7 +14,7 @@ import {
relTags, relTags,
} from "../../config"; } from "../../config";
import { customEmojisLookup, mdToHtml, setupTribute } from "../../markdown"; import { customEmojisLookup, mdToHtml, setupTribute } from "../../markdown";
import { HttpService, I18NextService, UserService } from "../../services"; import { HttpService, I18NextService } from "../../services";
import { setupTippy } from "../../tippy"; import { setupTippy } from "../../tippy";
import { pictrsDeleteToast, toast } from "../../toast"; import { pictrsDeleteToast, toast } from "../../toast";
import { EmojiPicker } from "./emoji-picker"; import { EmojiPicker } from "./emoji-picker";
@ -52,6 +52,7 @@ interface MarkdownTextAreaProps {
onSubmit?(content: string, languageId?: number): void; onSubmit?(content: string, languageId?: number): void;
allLanguages: Language[]; // TODO should probably be nullable allLanguages: Language[]; // TODO should probably be nullable
siteLanguages: number[]; // TODO same siteLanguages: number[]; // TODO same
myUserInfo?: MyUserInfo;
} }
interface ImageUploadStatus { interface ImageUploadStatus {
@ -168,7 +169,7 @@ export class MarkdownTextArea extends Component<
<label <label
htmlFor={`file-upload-${this.id}`} htmlFor={`file-upload-${this.id}`}
className={classNames("mb-0", { className={classNames("mb-0", {
pointer: UserService.Instance.myUserInfo, pointer: !!this.props.myUserInfo,
})} })}
data-tippy-content={I18NextService.i18n.t("upload_image")} data-tippy-content={I18NextService.i18n.t("upload_image")}
> >
@ -195,7 +196,7 @@ export class MarkdownTextArea extends Component<
name="file" name="file"
className="d-none" className="d-none"
multiple multiple
disabled={!UserService.Instance.myUserInfo} disabled={!this.props.myUserInfo}
onChange={linkEvent(this, this.handleImageUpload)} onChange={linkEvent(this, this.handleImageUpload)}
/> />
{this.getFormatButton("header", this.handleInsertHeader)} {this.getFormatButton("header", this.handleInsertHeader)}
@ -276,6 +277,7 @@ export class MarkdownTextArea extends Component<
{this.props.showLanguage && ( {this.props.showLanguage && (
<LanguageSelect <LanguageSelect
iconVersion iconVersion
myUserInfo={this.props.myUserInfo}
allLanguages={this.props.allLanguages} allLanguages={this.props.allLanguages}
selectedLanguageIds={ selectedLanguageIds={
languageId ? Array.of(languageId) : undefined languageId ? Array.of(languageId) : undefined

View file

@ -6,14 +6,16 @@ import {
CommentAggregates, CommentAggregates,
CreateCommentLike, CreateCommentLike,
CreatePostLike, CreatePostLike,
MyUserInfo,
PostAggregates, PostAggregates,
} from "lemmy-js-client"; } from "lemmy-js-client";
import { VoteContentType, VoteType } from "../../interfaces"; import { VoteContentType, VoteType } from "../../interfaces";
import { I18NextService, UserService } from "../../services"; import { I18NextService } from "../../services";
import { Icon, Spinner } from "../common/icon"; import { Icon, Spinner } from "../common/icon";
interface VoteButtonsProps { interface VoteButtonsProps {
voteContentType: VoteContentType; voteContentType: VoteContentType;
myUserInfo?: MyUserInfo;
id: number; id: number;
onVote: (i: CreateCommentLike | CreatePostLike) => void; onVote: (i: CreateCommentLike | CreatePostLike) => void;
enableDownvotes?: boolean; enableDownvotes?: boolean;
@ -113,7 +115,7 @@ export class VoteButtonsCompact extends Component<
this.props.my_vote === 1 ? "text-info" : "text-muted" this.props.my_vote === 1 ? "text-info" : "text-muted"
}`} }`}
data-tippy-content={tippy(this.props.counts)} data-tippy-content={tippy(this.props.counts)}
disabled={!UserService.Instance.myUserInfo} disabled={!this.props.myUserInfo}
onClick={linkEvent(this, handleUpvote)} onClick={linkEvent(this, handleUpvote)}
aria-label={I18NextService.i18n.t("upvote")} aria-label={I18NextService.i18n.t("upvote")}
aria-pressed={this.props.my_vote === 1} aria-pressed={this.props.my_vote === 1}
@ -123,7 +125,7 @@ export class VoteButtonsCompact extends Component<
) : ( ) : (
<> <>
<Icon icon="arrow-up1" classes="icon-inline small" /> <Icon icon="arrow-up1" classes="icon-inline small" />
{showScores() && ( {showScores(this.props.myUserInfo) && (
<span className="ms-2"> <span className="ms-2">
{numToSI(this.props.counts.upvotes)} {numToSI(this.props.counts.upvotes)}
</span> </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 ${ className={`ms-2 btn btn-sm btn-link btn-animate btn py-0 px-1 ${
this.props.my_vote === -1 ? "text-danger" : "text-muted" this.props.my_vote === -1 ? "text-danger" : "text-muted"
}`} }`}
disabled={!UserService.Instance.myUserInfo} disabled={!this.props.myUserInfo}
onClick={linkEvent(this, handleDownvote)} onClick={linkEvent(this, handleDownvote)}
data-tippy-content={tippy(this.props.counts)} data-tippy-content={tippy(this.props.counts)}
aria-label={I18NextService.i18n.t("downvote")} aria-label={I18NextService.i18n.t("downvote")}
@ -148,7 +150,7 @@ export class VoteButtonsCompact extends Component<
) : ( ) : (
<> <>
<Icon icon="arrow-down1" classes="icon-inline small" /> <Icon icon="arrow-down1" classes="icon-inline small" />
{showScores() && ( {showScores(this.props.myUserInfo) && (
<span <span
className={classNames("ms-2", { className={classNames("ms-2", {
invisible: this.props.counts.downvotes === 0, 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 ${ className={`btn-animate btn btn-link p-0 ${
this.props.my_vote === 1 ? "text-info" : "text-muted" this.props.my_vote === 1 ? "text-info" : "text-muted"
}`} }`}
disabled={!UserService.Instance.myUserInfo} disabled={!this.props.myUserInfo}
onClick={linkEvent(this, handleUpvote)} onClick={linkEvent(this, handleUpvote)}
data-tippy-content={I18NextService.i18n.t("upvote")} data-tippy-content={I18NextService.i18n.t("upvote")}
aria-label={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" /> <Icon icon="arrow-up1" classes="upvote" />
)} )}
</button> </button>
{showScores() ? ( {showScores(this.props.myUserInfo) ? (
<div <div
className="unselectable pointer text-muted post-score" className="unselectable pointer text-muted post-score"
data-tippy-content={tippy(this.props.counts)} 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 ${ className={`btn-animate btn btn-link p-0 ${
this.props.my_vote === -1 ? "text-danger" : "text-muted" this.props.my_vote === -1 ? "text-danger" : "text-muted"
}`} }`}
disabled={!UserService.Instance.myUserInfo} disabled={!this.props.myUserInfo}
onClick={linkEvent(this, handleDownvote)} onClick={linkEvent(this, handleDownvote)}
data-tippy-content={I18NextService.i18n.t("downvote")} data-tippy-content={I18NextService.i18n.t("downvote")}
aria-label={I18NextService.i18n.t("downvote")} aria-label={I18NextService.i18n.t("downvote")}

View file

@ -1,4 +1,4 @@
import { editCommunity, setIsoData, showLocal } from "@utils/app"; import { editCommunity, showLocal } from "@utils/app";
import { import {
getPageFromString, getPageFromString,
getQueryParams, getQueryParams,
@ -17,7 +17,7 @@ import {
ListingType, ListingType,
SortType, SortType,
} from "lemmy-js-client"; } from "lemmy-js-client";
import { InitialFetchRequest } from "../../interfaces"; import { InitialFetchRequest, IsoData } from "../../interfaces";
import { FirstLoadService, I18NextService } from "../../services"; import { FirstLoadService, I18NextService } from "../../services";
import { import {
EMPTY_REQUEST, EMPTY_REQUEST,
@ -70,7 +70,9 @@ function getCommunitiesQueryParams() {
} }
export class Communities extends Component<any, CommunitiesState> { 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 = { state: CommunitiesState = {
listCommunitiesResponse: EMPTY_REQUEST, listCommunitiesResponse: EMPTY_REQUEST,
siteRes: this.isoData.site_res, siteRes: this.isoData.site_res,

View file

@ -243,6 +243,7 @@ export class CommunityForm extends Component<
selectedLanguageIds={this.state.form.discussion_languages} selectedLanguageIds={this.state.form.discussion_languages}
multiple={true} multiple={true}
onChange={this.handleDiscussionLanguageChange} onChange={this.handleDiscussionLanguageChange}
myUserInfo={this.props.myUserInfo}
/> />
<div className="mb-3 row"> <div className="mb-3 row">
<div className="col-12"> <div className="col-12">

View file

@ -2,12 +2,13 @@ import { showAvatars } from "@utils/app";
import { hostname } from "@utils/helpers"; import { hostname } from "@utils/helpers";
import { Component } from "inferno"; import { Component } from "inferno";
import { Link } from "inferno-router"; import { Link } from "inferno-router";
import { Community } from "lemmy-js-client"; import { Community, MyUserInfo } from "lemmy-js-client";
import { relTags } from "../../config"; import { relTags } from "../../config";
import { PictrsImage } from "../common/pictrs-image"; import { PictrsImage } from "../common/pictrs-image";
interface CommunityLinkProps { interface CommunityLinkProps {
community: Community; community: Community;
myUserInfo?: MyUserInfo;
realLink?: boolean; realLink?: boolean;
useApubName?: boolean; useApubName?: boolean;
muted?: boolean; muted?: boolean;
@ -63,7 +64,7 @@ export class CommunityLink extends Component<CommunityLinkProps, any> {
<> <>
{!this.props.hideAvatar && {!this.props.hideAvatar &&
!this.props.community.removed && !this.props.community.removed &&
showAvatars() && showAvatars(this.props.myUserInfo) &&
icon && <PictrsImage src={icon} icon nsfw={nsfw} />} icon && <PictrsImage src={icon} icon nsfw={nsfw} />}
<span className="overflow-wrap-anywhere">{displayName}</span> <span className="overflow-wrap-anywhere">{displayName}</span>
</> </>

View file

@ -9,7 +9,6 @@ import {
getCommentParentId, getCommentParentId,
getDataTypeString, getDataTypeString,
postToCommentSortType, postToCommentSortType,
setIsoData,
showLocal, showLocal,
updateCommunityBlock, updateCommunityBlock,
updatePersonBlock, updatePersonBlock,
@ -58,6 +57,7 @@ import {
LockPost, LockPost,
MarkCommentReplyAsRead, MarkCommentReplyAsRead,
MarkPersonMentionAsRead, MarkPersonMentionAsRead,
MyUserInfo,
PaginationCursor, PaginationCursor,
PostResponse, PostResponse,
PurgeComment, PurgeComment,
@ -78,8 +78,9 @@ import {
CommentViewType, CommentViewType,
DataType, DataType,
InitialFetchRequest, InitialFetchRequest,
IsoData,
} from "../../interfaces"; } from "../../interfaces";
import { FirstLoadService, I18NextService, UserService } from "../../services"; import { FirstLoadService, I18NextService } from "../../services";
import { import {
EMPTY_REQUEST, EMPTY_REQUEST,
HttpService, HttpService,
@ -136,10 +137,11 @@ function getDataTypeFromQuery(type?: string): DataType {
return type ? DataType[type] : DataType.Post; return type ? DataType[type] : DataType.Post;
} }
function getSortTypeFromQuery(type?: string): SortType { function getSortTypeFromQuery(
const mySortType = type?: string,
UserService.Instance.myUserInfo?.local_user_view.local_user myUserInfo?: MyUserInfo,
.default_sort_type; ): SortType {
const mySortType = myUserInfo?.local_user_view.local_user.default_sort_type;
return type ? (type as SortType) : mySortType ?? "Active"; return type ? (type as SortType) : mySortType ?? "Active";
} }
@ -148,7 +150,9 @@ export class Community extends Component<
RouteComponentProps<{ name: string }>, RouteComponentProps<{ name: string }>,
State State
> { > {
private isoData = setIsoData<CommunityData>(this.context); get isoData(): IsoData<CommunityData> {
return this.context.store.getState().value;
}
state: State = { state: State = {
communityRes: EMPTY_REQUEST, communityRes: EMPTY_REQUEST,
postsRes: EMPTY_REQUEST, postsRes: EMPTY_REQUEST,
@ -463,6 +467,7 @@ export class Community extends Component<
return ( return (
<CommentNodes <CommentNodes
nodes={commentsToFlatNodes(this.state.commentsRes.data.comments)} nodes={commentsToFlatNodes(this.state.commentsRes.data.comments)}
myUserInfo={this.isoData.site_res.my_user}
viewType={CommentViewType.Flat} viewType={CommentViewType.Flat}
finished={this.state.finished} finished={this.state.finished}
isTopLevel isTopLevel
@ -642,7 +647,7 @@ export class Community extends Component<
// Update myUserInfo // Update myUserInfo
if (followCommunityRes.state === "success") { if (followCommunityRes.state === "success") {
const communityId = followCommunityRes.data.community_view.community.id; const communityId = followCommunityRes.data.community_view.community.id;
const mui = UserService.Instance.myUserInfo; const mui = this.isoData.site_res.my_user;
if (mui) { if (mui) {
mui.follows = mui.follows.filter(i => i.community.id !== communityId); mui.follows = mui.follows.filter(i => i.community.id !== communityId);
} }
@ -672,7 +677,10 @@ export class Community extends Component<
async handleBlockCommunity(form: BlockCommunity) { async handleBlockCommunity(form: BlockCommunity) {
const blockCommunityRes = await HttpService.client.blockCommunity(form); const blockCommunityRes = await HttpService.client.blockCommunity(form);
if (blockCommunityRes.state === "success") { if (blockCommunityRes.state === "success") {
updateCommunityBlock(blockCommunityRes.data); updateCommunityBlock(
blockCommunityRes.data,
this.isoData.site_res.my_user,
);
this.setState(s => { this.setState(s => {
if (s.communityRes.state === "success") { if (s.communityRes.state === "success") {
s.communityRes.data.community_view.blocked = s.communityRes.data.community_view.blocked =
@ -685,7 +693,7 @@ export class Community extends Component<
async handleBlockPerson(form: BlockPerson) { async handleBlockPerson(form: BlockPerson) {
const blockPersonRes = await HttpService.client.blockPerson(form); const blockPersonRes = await HttpService.client.blockPerson(form);
if (blockPersonRes.state === "success") { if (blockPersonRes.state === "success") {
updatePersonBlock(blockPersonRes.data); updatePersonBlock(blockPersonRes.data, this.isoData.site_res.my_user);
} }
} }

View file

@ -1,4 +1,4 @@
import { enableNsfw, setIsoData } from "@utils/app"; import { enableNsfw } from "@utils/app";
import { Component } from "inferno"; import { Component } from "inferno";
import { import {
CreateCommunity as CreateCommunityI, CreateCommunity as CreateCommunityI,
@ -7,6 +7,7 @@ import {
import { HttpService, I18NextService } from "../../services"; import { HttpService, I18NextService } from "../../services";
import { HtmlTags } from "../common/html-tags"; import { HtmlTags } from "../common/html-tags";
import { CommunityForm } from "./community-form"; import { CommunityForm } from "./community-form";
import { IsoData } from "../../interfaces";
interface CreateCommunityState { interface CreateCommunityState {
siteRes: GetSiteResponse; siteRes: GetSiteResponse;
@ -14,7 +15,9 @@ interface CreateCommunityState {
} }
export class CreateCommunity extends Component<any, CreateCommunityState> { export class CreateCommunity extends Component<any, CreateCommunityState> {
private isoData = setIsoData(this.context); get isoData(): IsoData {
return this.context.store.getState().value;
}
state: CreateCommunityState = { state: CreateCommunityState = {
siteRes: this.isoData.site_res, siteRes: this.isoData.site_res,
loading: false, loading: false,

View file

@ -12,12 +12,13 @@ import {
EditCommunity, EditCommunity,
FollowCommunity, FollowCommunity,
Language, Language,
MyUserInfo,
PersonView, PersonView,
PurgeCommunity, PurgeCommunity,
RemoveCommunity, RemoveCommunity,
} from "lemmy-js-client"; } from "lemmy-js-client";
import { mdToHtml } from "../../markdown"; import { mdToHtml } from "../../markdown";
import { I18NextService, UserService } from "../../services"; import { I18NextService } from "../../services";
import { Badges } from "../common/badges"; import { Badges } from "../common/badges";
import { BannerIconHeader } from "../common/banner-icon-header"; import { BannerIconHeader } from "../common/banner-icon-header";
import { Icon, PurgeWarning, Spinner } from "../common/icon"; import { Icon, PurgeWarning, Spinner } from "../common/icon";
@ -28,6 +29,7 @@ import { PersonListing } from "../person/person-listing";
interface SidebarProps { interface SidebarProps {
community_view: CommunityView; community_view: CommunityView;
myUserInfo?: MyUserInfo;
moderators: CommunityModeratorView[]; moderators: CommunityModeratorView[];
admins: PersonView[]; admins: PersonView[];
allLanguages: Language[]; allLanguages: Language[];
@ -122,7 +124,7 @@ export class Sidebar extends Component<SidebarProps, SidebarState> {
} }
sidebar() { sidebar() {
const myUSerInfo = UserService.Instance.myUserInfo; const myUserInfo = this.props.myUserInfo;
const { const {
community: { name, actor_id }, community: { name, actor_id },
} = this.props.community_view; } = this.props.community_view;
@ -140,8 +142,8 @@ export class Sidebar extends Component<SidebarProps, SidebarState> {
loading={this.state.followCommunityLoading} loading={this.state.followCommunityLoading}
/> />
{this.canPost && this.createPost()} {this.canPost && this.createPost()}
{myUSerInfo && this.blockCommunity()} {myUserInfo && this.blockCommunity()}
{!myUSerInfo && ( {!myUserInfo && (
<div className="alert alert-info" role="alert"> <div className="alert alert-info" role="alert">
<T <T
i18nKey="community_not_logged_in_alert" i18nKey="community_not_logged_in_alert"
@ -268,7 +270,10 @@ export class Sidebar extends Component<SidebarProps, SidebarState> {
return ( return (
<> <>
<ul className="list-inline mb-1 text-muted fw-bold"> <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"> <li className="list-inline-item-action">
<button <button
@ -280,7 +285,7 @@ export class Sidebar extends Component<SidebarProps, SidebarState> {
<Icon icon="edit" classes="icon-inline" /> <Icon icon="edit" classes="icon-inline" />
</button> </button>
</li> </li>
{!amTopMod(this.props.moderators) && {!amTopMod(this.props.moderators, this.props.myUserInfo) &&
(!this.state.showConfirmLeaveModTeam ? ( (!this.state.showConfirmLeaveModTeam ? (
<li className="list-inline-item-action"> <li className="list-inline-item-action">
<button <button
@ -319,7 +324,7 @@ export class Sidebar extends Component<SidebarProps, SidebarState> {
</li> </li>
</> </>
))} ))}
{amTopMod(this.props.moderators) && ( {amTopMod(this.props.moderators, this.props.myUserInfo) && (
<li className="list-inline-item-action"> <li className="list-inline-item-action">
<button <button
className="btn btn-link text-muted d-inline-block" className="btn btn-link text-muted d-inline-block"
@ -468,8 +473,8 @@ export class Sidebar extends Component<SidebarProps, SidebarState> {
get canPost(): boolean { get canPost(): boolean {
return ( return (
!this.props.community_view.community.posting_restricted_to_mods || !this.props.community_view.community.posting_restricted_to_mods ||
amMod(this.props.community_view.community.id) || amMod(this.props.community_view.community.id, this.props.myUserInfo) ||
amAdmin() amAdmin(this.props.myUserInfo)
); );
} }
@ -520,7 +525,7 @@ export class Sidebar extends Component<SidebarProps, SidebarState> {
} }
handleLeaveModTeam(i: Sidebar) { 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) { if (myId) {
i.setState({ leaveModTeamLoading: true }); i.setState({ leaveModTeamLoading: true });
i.props.onLeaveModTeam({ i.props.onLeaveModTeam({

View file

@ -1,4 +1,4 @@
import { fetchThemeList, setIsoData, showLocal } from "@utils/app"; import { fetchThemeList, showLocal } from "@utils/app";
import { capitalizeFirstLetter } from "@utils/helpers"; import { capitalizeFirstLetter } from "@utils/helpers";
import { RouteDataResponse } from "@utils/types"; import { RouteDataResponse } from "@utils/types";
import classNames from "classnames"; import classNames from "classnames";
@ -14,7 +14,7 @@ import {
LemmyHttp, LemmyHttp,
PersonView, PersonView,
} from "lemmy-js-client"; } from "lemmy-js-client";
import { InitialFetchRequest } from "../../interfaces"; import { InitialFetchRequest, IsoData } from "../../interfaces";
import { removeFromEmojiDataModel, updateEmojiDataModel } from "../../markdown"; import { removeFromEmojiDataModel, updateEmojiDataModel } from "../../markdown";
import { FirstLoadService, I18NextService } from "../../services"; import { FirstLoadService, I18NextService } from "../../services";
import { import {
@ -53,7 +53,9 @@ interface AdminSettingsState {
} }
export class AdminSettings extends Component<any, 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 = { state: AdminSettingsState = {
siteRes: this.isoData.site_res, siteRes: this.isoData.site_res,
banned: [], banned: [],

View file

@ -1,4 +1,3 @@
import { setIsoData } from "@utils/app";
import { capitalizeFirstLetter } from "@utils/helpers"; import { capitalizeFirstLetter } from "@utils/helpers";
import { Component, linkEvent } from "inferno"; import { Component, linkEvent } from "inferno";
import { import {
@ -13,6 +12,7 @@ import { pictrsDeleteToast, toast } from "../../toast";
import { EmojiMart } from "../common/emoji-mart"; import { EmojiMart } from "../common/emoji-mart";
import { Icon, Spinner } from "../common/icon"; import { Icon, Spinner } from "../common/icon";
import { Paginator } from "../common/paginator"; import { Paginator } from "../common/paginator";
import { IsoData } from "../../interfaces";
interface EmojiFormProps { interface EmojiFormProps {
onEdit(form: EditCustomEmoji): void; onEdit(form: EditCustomEmoji): void;
@ -39,7 +39,9 @@ interface CustomEmojiViewForm {
} }
export class EmojiForm extends Component<EmojiFormProps, EmojiFormState> { 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 itemsPerPage = 15;
private emptyState: EmojiFormState = { private emptyState: EmojiFormState = {
siteRes: this.isoData.site_res, siteRes: this.isoData.site_res,

View file

@ -9,7 +9,6 @@ import {
getDataTypeString, getDataTypeString,
myAuth, myAuth,
postToCommentSortType, postToCommentSortType,
setIsoData,
showLocal, showLocal,
updatePersonBlock, updatePersonBlock,
} from "@utils/app"; } from "@utils/app";
@ -59,6 +58,7 @@ import {
LockPost, LockPost,
MarkCommentReplyAsRead, MarkCommentReplyAsRead,
MarkPersonMentionAsRead, MarkPersonMentionAsRead,
MyUserInfo,
PaginationCursor, PaginationCursor,
PostResponse, PostResponse,
PurgeComment, PurgeComment,
@ -77,9 +77,10 @@ import {
CommentViewType, CommentViewType,
DataType, DataType,
InitialFetchRequest, InitialFetchRequest,
IsoData,
} from "../../interfaces"; } from "../../interfaces";
import { mdToHtml } from "../../markdown"; import { mdToHtml } from "../../markdown";
import { FirstLoadService, I18NextService, UserService } from "../../services"; import { FirstLoadService, I18NextService } from "../../services";
import { import {
EMPTY_REQUEST, EMPTY_REQUEST,
HttpService, HttpService,
@ -168,7 +169,7 @@ function getDataTypeFromQuery(type?: string): DataType {
function getListingTypeFromQuery( function getListingTypeFromQuery(
type?: string, type?: string,
myUserInfo = UserService.Instance.myUserInfo, myUserInfo?: MyUserInfo,
): ListingType | undefined { ): ListingType | undefined {
const myListingType = const myListingType =
myUserInfo?.local_user_view?.local_user?.default_listing_type; myUserInfo?.local_user_view?.local_user?.default_listing_type;
@ -178,7 +179,7 @@ function getListingTypeFromQuery(
function getSortTypeFromQuery( function getSortTypeFromQuery(
type?: string, type?: string,
myUserInfo = UserService.Instance.myUserInfo, myUserInfo?: MyUserInfo,
): SortType { ): SortType {
const mySortType = myUserInfo?.local_user_view?.local_user?.default_sort_type; const mySortType = myUserInfo?.local_user_view?.local_user?.default_sort_type;
@ -225,7 +226,9 @@ const LinkButton = ({
); );
export class Home extends Component<any, HomeState> { 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 = { state: HomeState = {
postsRes: EMPTY_REQUEST, postsRes: EMPTY_REQUEST,
commentsRes: EMPTY_REQUEST, commentsRes: EMPTY_REQUEST,
@ -242,6 +245,7 @@ export class Home extends Component<any, HomeState> {
constructor(props: any, context: any) { constructor(props: any, context: any) {
super(props, context); super(props, context);
console.log(this.isoData);
this.handleSortChange = this.handleSortChange.bind(this); this.handleSortChange = this.handleSortChange.bind(this);
this.handleListingTypeChange = this.handleListingTypeChange.bind(this); this.handleListingTypeChange = this.handleListingTypeChange.bind(this);
@ -416,7 +420,7 @@ export class Home extends Component<any, HomeState> {
} }
get hasFollows(): boolean { get hasFollows(): boolean {
const mui = UserService.Instance.myUserInfo; const mui = this.isoData.site_res.my_user;
return !!mui && mui.follows.length > 0; return !!mui && mui.follows.length > 0;
} }
@ -606,7 +610,7 @@ export class Home extends Component<any, HomeState> {
> >
<div className="card-body"> <div className="card-body">
<ul className="list-inline mb-0"> <ul className="list-inline mb-0">
{UserService.Instance.myUserInfo?.follows.map(cfv => ( {this.isoData.site_res.my_user?.follows.map(cfv => (
<li <li
key={cfv.community.id} key={cfv.community.id}
className="list-inline-item d-inline-block" className="list-inline-item d-inline-block"
@ -734,6 +738,7 @@ export class Home extends Component<any, HomeState> {
return ( return (
<CommentNodes <CommentNodes
nodes={commentsToFlatNodes(comments)} nodes={commentsToFlatNodes(comments)}
myUserInfo={this.isoData.site_res.my_user}
viewType={CommentViewType.Flat} viewType={CommentViewType.Flat}
finished={this.state.finished} finished={this.state.finished}
isTopLevel isTopLevel
@ -909,7 +914,7 @@ export class Home extends Component<any, HomeState> {
async handleBlockPerson(form: BlockPerson) { async handleBlockPerson(form: BlockPerson) {
const blockPersonRes = await HttpService.client.blockPerson(form); const blockPersonRes = await HttpService.client.blockPerson(form);
if (blockPersonRes.state === "success") { if (blockPersonRes.state === "success") {
updatePersonBlock(blockPersonRes.data); updatePersonBlock(blockPersonRes.data, this.isoData.site_res.my_user);
} }
} }

View file

@ -1,4 +1,3 @@
import { setIsoData } from "@utils/app";
import { RouteDataResponse } from "@utils/types"; import { RouteDataResponse } from "@utils/types";
import { Component } from "inferno"; import { Component } from "inferno";
import { import {
@ -9,7 +8,7 @@ import {
} from "lemmy-js-client"; } from "lemmy-js-client";
import classNames from "classnames"; import classNames from "classnames";
import { relTags } from "../../config"; import { relTags } from "../../config";
import { InitialFetchRequest } from "../../interfaces"; import { InitialFetchRequest, IsoData } from "../../interfaces";
import { FirstLoadService, I18NextService } from "../../services"; import { FirstLoadService, I18NextService } from "../../services";
import { import {
EMPTY_REQUEST, EMPTY_REQUEST,
@ -34,7 +33,9 @@ interface InstancesState {
} }
export class Instances extends Component<any, 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 = { state: InstancesState = {
instancesRes: EMPTY_REQUEST, instancesRes: EMPTY_REQUEST,
siteRes: this.isoData.site_res, siteRes: this.isoData.site_res,

View file

@ -1,16 +1,18 @@
import { setIsoData } from "@utils/app";
import { Component } from "inferno"; import { Component } from "inferno";
import { GetSiteResponse } from "lemmy-js-client"; import { GetSiteResponse } from "lemmy-js-client";
import { mdToHtml } from "../../markdown"; import { mdToHtml } from "../../markdown";
import { I18NextService } from "../../services"; import { I18NextService } from "../../services";
import { HtmlTags } from "../common/html-tags"; import { HtmlTags } from "../common/html-tags";
import { IsoData } from "../../interfaces";
interface LegalState { interface LegalState {
siteRes: GetSiteResponse; siteRes: GetSiteResponse;
} }
export class Legal extends Component<any, LegalState> { export class Legal extends Component<any, LegalState> {
private isoData = setIsoData(this.context); get isoData(): IsoData {
return this.context.store.getState().value;
}
state: LegalState = { state: LegalState = {
siteRes: this.isoData.site_res, siteRes: this.isoData.site_res,
}; };

View file

@ -1,4 +1,3 @@
import { setIsoData } from "@utils/app";
import { capitalizeFirstLetter, validEmail } from "@utils/helpers"; import { capitalizeFirstLetter, validEmail } from "@utils/helpers";
import { Component, linkEvent } from "inferno"; import { Component, linkEvent } from "inferno";
import { GetSiteResponse } from "lemmy-js-client"; import { GetSiteResponse } from "lemmy-js-client";
@ -6,6 +5,7 @@ import { HttpService, I18NextService } from "../../services";
import { toast } from "../../toast"; import { toast } from "../../toast";
import { HtmlTags } from "../common/html-tags"; import { HtmlTags } from "../common/html-tags";
import { Spinner } from "../common/icon"; import { Spinner } from "../common/icon";
import { IsoData } from "../../interfaces";
interface State { interface State {
form: { form: {
@ -16,7 +16,9 @@ interface State {
} }
export class LoginReset extends Component<any, State> { export class LoginReset extends Component<any, State> {
private isoData = setIsoData(this.context); get isoData(): IsoData {
return this.context.store.getState().value;
}
state: State = { state: State = {
form: { form: {

View file

@ -46,6 +46,7 @@ async function handleLoginSuccess(i: Login, loginRes: LoginResponse) {
const site = await HttpService.client.getSite(); const site = await HttpService.client.getSite();
if (site.state === "success") { if (site.state === "success") {
// TODO this is the key, you need to update the redux store here
UserService.Instance.myUserInfo = site.data.my_user; UserService.Instance.myUserInfo = site.data.my_user;
updateDataBsTheme(site.data); updateDataBsTheme(site.data);
} }

View file

@ -1,4 +1,3 @@
import { setIsoData } from "@utils/app";
import { isBrowser } from "@utils/browser"; import { isBrowser } from "@utils/browser";
import { validEmail } from "@utils/helpers"; import { validEmail } from "@utils/helpers";
import { Component, linkEvent } from "inferno"; import { Component, linkEvent } from "inferno";
@ -12,7 +11,7 @@ import {
} from "lemmy-js-client"; } from "lemmy-js-client";
import { joinLemmyUrl } from "../../config"; import { joinLemmyUrl } from "../../config";
import { mdToHtml } from "../../markdown"; import { mdToHtml } from "../../markdown";
import { I18NextService, UserService } from "../../services"; import { I18NextService } from "../../services";
import { import {
EMPTY_REQUEST, EMPTY_REQUEST,
HttpService, HttpService,
@ -24,6 +23,7 @@ import { HtmlTags } from "../common/html-tags";
import { Icon, Spinner } from "../common/icon"; import { Icon, Spinner } from "../common/icon";
import { MarkdownTextArea } from "../common/markdown-textarea"; import { MarkdownTextArea } from "../common/markdown-textarea";
import PasswordInput from "../common/password-input"; import PasswordInput from "../common/password-input";
import { IsoData } from "../../interfaces";
interface State { interface State {
registerRes: RequestState<LoginResponse>; registerRes: RequestState<LoginResponse>;
@ -44,7 +44,9 @@ interface State {
} }
export class Signup extends Component<any, 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; private audio?: HTMLAudioElement;
state: State = { state: State = {

View file

@ -498,6 +498,7 @@ export class SiteForm extends Component<SiteFormProps, SiteFormState> {
selectedLanguageIds={this.state.siteForm.discussion_languages} selectedLanguageIds={this.state.siteForm.discussion_languages}
multiple={true} multiple={true}
onChange={this.handleDiscussionLanguageChange} onChange={this.handleDiscussionLanguageChange}
myUserInfo={this.props.siteRes.my_user}
showAll showAll
/> />
<div className="mb-3 row"> <div className="mb-3 row">

View file

@ -1,9 +1,4 @@
import { import { fetchUsers, getUpdatedSearchId, personToChoice } from "@utils/app";
fetchUsers,
getUpdatedSearchId,
personToChoice,
setIsoData,
} from "@utils/app";
import { import {
debounce, debounce,
formatPastDate, formatPastDate,
@ -46,7 +41,7 @@ import {
Person, Person,
} from "lemmy-js-client"; } from "lemmy-js-client";
import { fetchLimit } from "../config"; import { fetchLimit } from "../config";
import { InitialFetchRequest } from "../interfaces"; import { InitialFetchRequest, IsoData } from "../interfaces";
import { FirstLoadService, I18NextService } from "../services"; import { FirstLoadService, I18NextService } from "../services";
import { import {
EMPTY_REQUEST, EMPTY_REQUEST,
@ -636,7 +631,9 @@ export class Modlog extends Component<
RouteComponentProps<{ communityId?: string }>, RouteComponentProps<{ communityId?: string }>,
ModlogState ModlogState
> { > {
private isoData = setIsoData<ModlogData>(this.context); get isoData(): IsoData<ModlogData> {
return this.context.store.getState().value;
}
state: ModlogState = { state: ModlogState = {
res: EMPTY_REQUEST, res: EMPTY_REQUEST,

View file

@ -7,7 +7,6 @@ import {
enableDownvotes, enableDownvotes,
getCommentParentId, getCommentParentId,
myAuth, myAuth,
setIsoData,
updatePersonBlock, updatePersonBlock,
} from "@utils/app"; } from "@utils/app";
import { capitalizeFirstLetter, randomStr } from "@utils/helpers"; import { capitalizeFirstLetter, randomStr } from "@utils/helpers";
@ -61,8 +60,12 @@ import {
TransferCommunity, TransferCommunity,
} from "lemmy-js-client"; } from "lemmy-js-client";
import { fetchLimit, relTags } from "../../config"; import { fetchLimit, relTags } from "../../config";
import { CommentViewType, InitialFetchRequest } from "../../interfaces"; import {
import { FirstLoadService, I18NextService, UserService } from "../../services"; CommentViewType,
InitialFetchRequest,
IsoData,
} from "../../interfaces";
import { FirstLoadService, I18NextService } from "../../services";
import { UnreadCounterService } from "../../services"; import { UnreadCounterService } from "../../services";
import { import {
EMPTY_REQUEST, EMPTY_REQUEST,
@ -127,7 +130,9 @@ interface InboxState {
} }
export class Inbox extends Component<any, 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 = { state: InboxState = {
unreadOrAll: UnreadOrAll.Unread, unreadOrAll: UnreadOrAll.Unread,
messageType: MessageType.All, messageType: MessageType.All,
@ -194,7 +199,7 @@ export class Inbox extends Component<any, InboxState> {
} }
get documentTitle(): string { get documentTitle(): string {
const mui = UserService.Instance.myUserInfo; const mui = this.isoData.site_res.my_user;
return mui return mui
? `@${mui.local_user_view.person.name} ${I18NextService.i18n.t( ? `@${mui.local_user_view.person.name} ${I18NextService.i18n.t(
"inbox", "inbox",
@ -483,6 +488,7 @@ export class Inbox extends Component<any, InboxState> {
nodes={[ nodes={[
{ comment_view: i.view as CommentView, children: [], depth: 0 }, { comment_view: i.view as CommentView, children: [], depth: 0 },
]} ]}
myUserInfo={this.isoData.site_res.my_user}
viewType={CommentViewType.Flat} viewType={CommentViewType.Flat}
finished={this.state.finished} finished={this.state.finished}
markable markable
@ -848,7 +854,7 @@ export class Inbox extends Component<any, InboxState> {
async handleBlockPerson(form: BlockPerson) { async handleBlockPerson(form: BlockPerson) {
const blockPersonRes = await HttpService.client.blockPerson(form); const blockPersonRes = await HttpService.client.blockPerson(form);
if (blockPersonRes.state === "success") { if (blockPersonRes.state === "success") {
updatePersonBlock(blockPersonRes.data); updatePersonBlock(blockPersonRes.data, this.isoData.site_res.my_user);
} }
} }

View file

@ -4,13 +4,14 @@ import { hostname, isCakeDay } from "@utils/helpers";
import classNames from "classnames"; import classNames from "classnames";
import { Component } from "inferno"; import { Component } from "inferno";
import { Link } from "inferno-router"; import { Link } from "inferno-router";
import { Person } from "lemmy-js-client"; import { MyUserInfo, Person } from "lemmy-js-client";
import { relTags } from "../../config"; import { relTags } from "../../config";
import { PictrsImage } from "../common/pictrs-image"; import { PictrsImage } from "../common/pictrs-image";
import { CakeDay } from "./cake-day"; import { CakeDay } from "./cake-day";
interface PersonListingProps { interface PersonListingProps {
person: Person; person: Person;
myUserInfo?: MyUserInfo;
realLink?: boolean; realLink?: boolean;
useApubName?: boolean; useApubName?: boolean;
muted?: boolean; muted?: boolean;
@ -87,7 +88,7 @@ export class PersonListing extends Component<PersonListingProps, any> {
<> <>
{!this.props.hideAvatar && {!this.props.hideAvatar &&
!this.props.person.banned && !this.props.person.banned &&
showAvatars() && ( showAvatars(this.props.myUserInfo) && (
<PictrsImage <PictrsImage
src={avatar ?? `${getStaticDir()}/assets/icons/icon-96x96.png`} src={avatar ?? `${getStaticDir()}/assets/icons/icon-96x96.png`}
icon icon

View file

@ -5,7 +5,6 @@ import {
enableDownvotes, enableDownvotes,
enableNsfw, enableNsfw,
getCommentParentId, getCommentParentId,
setIsoData,
updatePersonBlock, updatePersonBlock,
} from "@utils/app"; } from "@utils/app";
import { restoreScrollPosition, saveScrollPosition } from "@utils/browser"; import { restoreScrollPosition, saveScrollPosition } from "@utils/browser";
@ -59,6 +58,7 @@ import {
LockPost, LockPost,
MarkCommentReplyAsRead, MarkCommentReplyAsRead,
MarkPersonMentionAsRead, MarkPersonMentionAsRead,
MyUserInfo,
PersonView, PersonView,
PostResponse, PostResponse,
PurgeComment, PurgeComment,
@ -73,9 +73,13 @@ import {
TransferCommunity, TransferCommunity,
} from "lemmy-js-client"; } from "lemmy-js-client";
import { fetchLimit, relTags } from "../../config"; import { fetchLimit, relTags } from "../../config";
import { InitialFetchRequest, PersonDetailsView } from "../../interfaces"; import {
InitialFetchRequest,
IsoData,
PersonDetailsView,
} from "../../interfaces";
import { mdToHtml } from "../../markdown"; import { mdToHtml } from "../../markdown";
import { FirstLoadService, I18NextService, UserService } from "../../services"; import { FirstLoadService, I18NextService } from "../../services";
import { import {
EMPTY_REQUEST, EMPTY_REQUEST,
HttpService, HttpService,
@ -159,13 +163,16 @@ const getCommunitiesListing = (
const Moderates = ({ moderates }: { moderates?: CommunityModeratorView[] }) => const Moderates = ({ moderates }: { moderates?: CommunityModeratorView[] }) =>
getCommunitiesListing("moderates", moderates); getCommunitiesListing("moderates", moderates);
const Follows = () => const Follows = ({ myUserInfo }: { myUserInfo?: MyUserInfo }) =>
getCommunitiesListing("subscribed", UserService.Instance.myUserInfo?.follows); getCommunitiesListing("subscribed", myUserInfo?.follows);
function isPersonBlocked(personRes: RequestState<GetPersonDetailsResponse>) { function isPersonBlocked(
personRes: RequestState<GetPersonDetailsResponse>,
myUserInfo?: MyUserInfo,
) {
return ( return (
(personRes.state === "success" && (personRes.state === "success" &&
UserService.Instance.myUserInfo?.person_blocks.some( myUserInfo?.person_blocks.some(
({ target: { id } }) => id === personRes.data.person_view.person.id, ({ target: { id } }) => id === personRes.data.person_view.person.id,
)) ?? )) ??
false false
@ -176,7 +183,9 @@ export class Profile extends Component<
RouteComponentProps<{ username: string }>, RouteComponentProps<{ username: string }>,
ProfileState ProfileState
> { > {
private isoData = setIsoData<ProfileData>(this.context); get isoData(): IsoData<ProfileData> {
return this.context.store.getState().value;
}
state: ProfileState = { state: ProfileState = {
personRes: EMPTY_REQUEST, personRes: EMPTY_REQUEST,
personBlocked: false, personBlocked: false,
@ -269,7 +278,7 @@ export class Profile extends Component<
get amCurrentUser() { get amCurrentUser() {
if (this.state.personRes.state === "success") { if (this.state.personRes.state === "success") {
return ( 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 this.state.personRes.data.person_view.person.id
); );
} else { } else {
@ -388,7 +397,9 @@ export class Profile extends Component<
<div className="col-12 col-md-4"> <div className="col-12 col-md-4">
<Moderates moderates={personRes.moderates} /> <Moderates moderates={personRes.moderates} />
{this.amCurrentUser && <Follows />} {this.amCurrentUser && (
<Follows myUserInfo={this.isoData.site_res.my_user} />
)}
</div> </div>
</div> </div>
); );
@ -511,7 +522,7 @@ export class Profile extends Component<
</div> </div>
{this.banDialog(pv)} {this.banDialog(pv)}
<div className="flex-grow-1 unselectable pointer mx-2"></div> <div className="flex-grow-1 unselectable pointer mx-2"></div>
{!this.amCurrentUser && UserService.Instance.myUserInfo && ( {!this.amCurrentUser && this.isoData.site_res.my_user && (
<> <>
<a <a
className={`d-flex align-self-start btn btn-secondary me-2 ${ 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")} {format(parseISO(pv.person.published), "PPP")}
</span> </span>
</div> </div>
{!UserService.Instance.myUserInfo && ( {!this.isoData.site_res.my_user && (
<div className="alert alert-info" role="alert"> <div className="alert alert-info" role="alert">
{I18NextService.i18n.t("profile_not_logged_in_alert")} {I18NextService.i18n.t("profile_not_logged_in_alert")}
</div> </div>
@ -799,7 +810,7 @@ export class Profile extends Component<
block, block,
}); });
if (res.state === "success") { if (res.state === "success") {
updatePersonBlock(res.data); updatePersonBlock(res.data, this.isoData.site_res.my_user);
this.setState({ personBlocked: res.data.blocked }); this.setState({ personBlocked: res.data.blocked });
} }
} }

View file

@ -1,4 +1,4 @@
import { editRegistrationApplication, setIsoData } from "@utils/app"; import { editRegistrationApplication } from "@utils/app";
import { randomStr } from "@utils/helpers"; import { randomStr } from "@utils/helpers";
import { RouteDataResponse } from "@utils/types"; import { RouteDataResponse } from "@utils/types";
import classNames from "classnames"; import classNames from "classnames";
@ -11,8 +11,8 @@ import {
RegistrationApplicationView, RegistrationApplicationView,
} from "lemmy-js-client"; } from "lemmy-js-client";
import { fetchLimit } from "../../config"; import { fetchLimit } from "../../config";
import { InitialFetchRequest } from "../../interfaces"; import { InitialFetchRequest, IsoData } from "../../interfaces";
import { FirstLoadService, I18NextService, UserService } from "../../services"; import { FirstLoadService, I18NextService } from "../../services";
import { import {
EMPTY_REQUEST, EMPTY_REQUEST,
HttpService, HttpService,
@ -49,7 +49,9 @@ export class RegistrationApplications extends Component<
any, any,
RegistrationApplicationsState RegistrationApplicationsState
> { > {
private isoData = setIsoData<RegistrationApplicationsData>(this.context); get isoData(): IsoData<RegistrationApplicationsData> {
return this.context.store.getState().value;
}
state: RegistrationApplicationsState = { state: RegistrationApplicationsState = {
appsRes: EMPTY_REQUEST, appsRes: EMPTY_REQUEST,
siteRes: this.isoData.site_res, siteRes: this.isoData.site_res,
@ -82,7 +84,7 @@ export class RegistrationApplications extends Component<
} }
get documentTitle(): string { get documentTitle(): string {
const mui = UserService.Instance.myUserInfo; const mui = this.isoData.site_res.my_user;
return mui return mui
? `@${mui.local_user_view.person.name} ${I18NextService.i18n.t( ? `@${mui.local_user_view.person.name} ${I18NextService.i18n.t(
"registration_applications", "registration_applications",

View file

@ -2,7 +2,6 @@ import {
editCommentReport, editCommentReport,
editPostReport, editPostReport,
editPrivateMessageReport, editPrivateMessageReport,
setIsoData,
} from "@utils/app"; } from "@utils/app";
import { randomStr } from "@utils/helpers"; import { randomStr } from "@utils/helpers";
import { amAdmin } from "@utils/roles"; import { amAdmin } from "@utils/roles";
@ -29,13 +28,8 @@ import {
ResolvePrivateMessageReport, ResolvePrivateMessageReport,
} from "lemmy-js-client"; } from "lemmy-js-client";
import { fetchLimit } from "../../config"; import { fetchLimit } from "../../config";
import { InitialFetchRequest } from "../../interfaces"; import { InitialFetchRequest, IsoData } from "../../interfaces";
import { import { FirstLoadService, HttpService, I18NextService } from "../../services";
FirstLoadService,
HttpService,
I18NextService,
UserService,
} from "../../services";
import { import {
EMPTY_REQUEST, EMPTY_REQUEST,
LOADING_REQUEST, LOADING_REQUEST,
@ -94,7 +88,9 @@ interface ReportsState {
} }
export class Reports extends Component<any, 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 = { state: ReportsState = {
commentReportsRes: EMPTY_REQUEST, commentReportsRes: EMPTY_REQUEST,
postReportsRes: EMPTY_REQUEST, postReportsRes: EMPTY_REQUEST,
@ -144,7 +140,7 @@ export class Reports extends Component<any, ReportsState> {
} }
get documentTitle(): string { get documentTitle(): string {
const mui = UserService.Instance.myUserInfo; const mui = this.isoData.site_res.my_user;
return mui return mui
? `@${mui.local_user_view.person.name} ${I18NextService.i18n.t( ? `@${mui.local_user_view.person.name} ${I18NextService.i18n.t(
"reports", "reports",
@ -397,6 +393,7 @@ export class Reports extends Component<any, ReportsState> {
return ( return (
<CommentReport <CommentReport
key={i.id} key={i.id}
myUserInfo={this.isoData.site_res.my_user}
report={i.view as CommentReportView} report={i.view as CommentReportView}
onResolveReport={this.handleResolveCommentReport} onResolveReport={this.handleResolveCommentReport}
/> />

View file

@ -6,7 +6,6 @@ import {
instanceToChoice, instanceToChoice,
myAuth, myAuth,
personToChoice, personToChoice,
setIsoData,
setTheme, setTheme,
showLocal, showLocal,
updateCommunityBlock, updateCommunityBlock,
@ -37,7 +36,7 @@ import {
UpdateTotpResponse, UpdateTotpResponse,
} from "lemmy-js-client"; } from "lemmy-js-client";
import { elementUrl, emDash, fetchLimit, relTags } from "../../config"; import { elementUrl, emDash, fetchLimit, relTags } from "../../config";
import { FirstLoadService, UserService } from "../../services"; import { FirstLoadService } from "../../services";
import { import {
EMPTY_REQUEST, EMPTY_REQUEST,
HttpService, HttpService,
@ -60,7 +59,7 @@ import { SortSelect } from "../common/sort-select";
import Tabs from "../common/tabs"; import Tabs from "../common/tabs";
import { CommunityLink } from "../community/community-link"; import { CommunityLink } from "../community/community-link";
import { PersonListing } from "./person-listing"; import { PersonListing } from "./person-listing";
import { InitialFetchRequest } from "../../interfaces"; import { InitialFetchRequest, IsoData } from "../../interfaces";
import TotpModal from "../common/totp-modal"; import TotpModal from "../common/totp-modal";
import { LoadingEllipses } from "../common/loading-ellipses"; import { LoadingEllipses } from "../common/loading-ellipses";
import { updateDataBsTheme } from "../../utils/browser"; import { updateDataBsTheme } from "../../utils/browser";
@ -190,7 +189,9 @@ function handleClose2faModal(i: Settings) {
} }
export class Settings extends Component<any, SettingsState> { 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>(); exportSettingsLink = createRef<HTMLAnchorElement>();
state: SettingsState = { state: SettingsState = {
@ -246,7 +247,7 @@ export class Settings extends Component<any, SettingsState> {
this.handleEnable2fa = this.handleEnable2fa.bind(this); this.handleEnable2fa = this.handleEnable2fa.bind(this);
this.handleDisable2fa = this.handleDisable2fa.bind(this); this.handleDisable2fa = this.handleDisable2fa.bind(this);
const mui = UserService.Instance.myUserInfo; const mui = this.isoData.site_res.my_user;
if (mui) { if (mui) {
const { const {
local_user: { local_user: {
@ -818,6 +819,7 @@ export class Settings extends Component<any, SettingsState> {
showAll={true} showAll={true}
showSite showSite
onChange={this.handleDiscussionLanguageChange} onChange={this.handleDiscussionLanguageChange}
myUserInfo={this.isoData.site_res.my_user}
/> />
<div className="mb-3 row"> <div className="mb-3 row">
<label className="col-sm-3 col-form-label" htmlFor="user-theme"> <label className="col-sm-3 col-form-label" htmlFor="user-theme">
@ -1125,7 +1127,7 @@ export class Settings extends Component<any, SettingsState> {
totpSection() { totpSection() {
const totpEnabled = const totpEnabled =
!!UserService.Instance.myUserInfo?.local_user_view.local_user !!this.isoData.site_res.my_user?.local_user_view.local_user
.totp_2fa_enabled; .totp_2fa_enabled;
const { generateTotpRes } = this.state; const { generateTotpRes } = this.state;
@ -1181,7 +1183,7 @@ export class Settings extends Component<any, SettingsState> {
const siteRes = await HttpService.client.getSite(); 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; enabled;
if (siteRes.state === "success") { if (siteRes.state === "success") {
@ -1349,7 +1351,7 @@ export class Settings extends Component<any, SettingsState> {
} }
handleShowAvatarsChange(i: Settings, event: any) { handleShowAvatarsChange(i: Settings, event: any) {
const mui = UserService.Instance.myUserInfo; const mui = this.isoData.site_res.my_user;
if (mui) { if (mui) {
mui.local_user_view.local_user.show_avatars = event.target.checked; 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) { handleShowScoresChange(i: Settings, event: any) {
const mui = UserService.Instance.myUserInfo; const mui = this.isoData.site_res.my_user;
if (mui) { if (mui) {
mui.local_user_view.local_user.show_scores = event.target.checked; 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, siteRes: siteRes.data,
}); });
// TODO need to update this
UserService.Instance.myUserInfo = siteRes.data.my_user; 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; } = siteRes.data.my_user!.local_user_view;
// TODO need to update redux
UserService.Instance.myUserInfo = siteRes.data.my_user; UserService.Instance.myUserInfo = siteRes.data.my_user;
updateDataBsTheme(siteRes.data); updateDataBsTheme(siteRes.data);
@ -1705,8 +1709,8 @@ export class Settings extends Component<any, SettingsState> {
personBlock(res: RequestState<BlockPersonResponse>) { personBlock(res: RequestState<BlockPersonResponse>) {
if (res.state === "success") { if (res.state === "success") {
updatePersonBlock(res.data); updatePersonBlock(res.data, this.isoData.site_res.my_user);
const mui = UserService.Instance.myUserInfo; const mui = this.isoData.site_res.my_user;
if (mui) { if (mui) {
this.setState({ personBlocks: mui.person_blocks }); this.setState({ personBlocks: mui.person_blocks });
} }
@ -1715,8 +1719,8 @@ export class Settings extends Component<any, SettingsState> {
communityBlock(res: RequestState<BlockCommunityResponse>) { communityBlock(res: RequestState<BlockCommunityResponse>) {
if (res.state === "success") { if (res.state === "success") {
updateCommunityBlock(res.data); updateCommunityBlock(res.data, this.isoData.site_res.my_user);
const mui = UserService.Instance.myUserInfo; const mui = this.isoData.site_res.my_user;
if (mui) { if (mui) {
this.setState({ communityBlocks: mui.community_blocks }); this.setState({ communityBlocks: mui.community_blocks });
} }
@ -1730,8 +1734,13 @@ export class Settings extends Component<any, SettingsState> {
) { ) {
const linkedInstances = const linkedInstances =
this.state.instancesRes.data.federated_instances?.linked ?? []; this.state.instancesRes.data.federated_instances?.linked ?? [];
updateInstanceBlock(res.data, id, linkedInstances); updateInstanceBlock(
const mui = UserService.Instance.myUserInfo; res.data,
id,
linkedInstances,
this.isoData.site_res.my_user,
);
const mui = this.isoData.site_res.my_user;
if (mui) { if (mui) {
this.setState({ instanceBlocks: mui.instance_blocks }); this.setState({ instanceBlocks: mui.instance_blocks });
} }

View file

@ -1,4 +1,3 @@
import { setIsoData } from "@utils/app";
import { Component } from "inferno"; import { Component } from "inferno";
import { GetSiteResponse, SuccessResponse } from "lemmy-js-client"; import { GetSiteResponse, SuccessResponse } from "lemmy-js-client";
import { I18NextService } from "../../services"; import { I18NextService } from "../../services";
@ -11,6 +10,7 @@ import {
import { toast } from "../../toast"; import { toast } from "../../toast";
import { HtmlTags } from "../common/html-tags"; import { HtmlTags } from "../common/html-tags";
import { Spinner } from "../common/icon"; import { Spinner } from "../common/icon";
import { IsoData } from "../../interfaces";
interface State { interface State {
verifyRes: RequestState<SuccessResponse>; verifyRes: RequestState<SuccessResponse>;
@ -18,7 +18,9 @@ interface State {
} }
export class VerifyEmail extends Component<any, State> { export class VerifyEmail extends Component<any, State> {
private isoData = setIsoData(this.context); get isoData(): IsoData {
return this.context.store.getState().value;
}
state: State = { state: State = {
verifyRes: EMPTY_REQUEST, verifyRes: EMPTY_REQUEST,

View file

@ -1,4 +1,4 @@
import { enableDownvotes, enableNsfw, setIsoData } from "@utils/app"; import { enableDownvotes, enableNsfw } from "@utils/app";
import { getIdFromString, getQueryParams } from "@utils/helpers"; import { getIdFromString, getQueryParams } from "@utils/helpers";
import type { QueryParams } from "@utils/types"; import type { QueryParams } from "@utils/types";
import { Choice, RouteDataResponse } from "@utils/types"; import { Choice, RouteDataResponse } from "@utils/types";
@ -12,7 +12,7 @@ import {
LemmyHttp, LemmyHttp,
ListCommunitiesResponse, ListCommunitiesResponse,
} from "lemmy-js-client"; } from "lemmy-js-client";
import { InitialFetchRequest, PostFormParams } from "../../interfaces"; import { InitialFetchRequest, IsoData, PostFormParams } from "../../interfaces";
import { FirstLoadService, I18NextService } from "../../services"; import { FirstLoadService, I18NextService } from "../../services";
import { import {
EMPTY_REQUEST, EMPTY_REQUEST,
@ -57,7 +57,9 @@ export class CreatePost extends Component<
RouteComponentProps<Record<string, never>>, RouteComponentProps<Record<string, never>>,
CreatePostState CreatePostState
> { > {
private isoData = setIsoData<CreatePostData>(this.context); get isoData(): IsoData<CreatePostData> {
return this.context.store.getState().value;
}
state: CreatePostState = { state: CreatePostState = {
siteRes: this.isoData.site_res, siteRes: this.isoData.site_res,
loading: true, loading: true,

View file

@ -17,6 +17,7 @@ import {
EditPost, EditPost,
GetSiteMetadataResponse, GetSiteMetadataResponse,
Language, Language,
MyUserInfo,
PostView, PostView,
SearchResponse, SearchResponse,
} from "lemmy-js-client"; } from "lemmy-js-client";
@ -28,7 +29,7 @@ import {
webArchiveUrl, webArchiveUrl,
} from "../../config"; } from "../../config";
import { PostFormParams } from "../../interfaces"; import { PostFormParams } from "../../interfaces";
import { I18NextService, UserService } from "../../services"; import { I18NextService } from "../../services";
import { import {
EMPTY_REQUEST, EMPTY_REQUEST,
HttpService, HttpService,
@ -47,6 +48,7 @@ const MAX_POST_TITLE_LENGTH = 200;
interface PostFormProps { interface PostFormProps {
post_view?: PostView; // If a post is given, that means this is an edit post_view?: PostView; // If a post is given, that means this is an edit
myUserInfo?: MyUserInfo;
crossPosts?: PostView[]; crossPosts?: PostView[];
allLanguages: Language[]; allLanguages: Language[];
siteLanguages: number[]; siteLanguages: number[];
@ -423,7 +425,7 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
accept="image/*,video/*" accept="image/*,video/*"
name="file" name="file"
className="small col-sm-10 form-control" className="small col-sm-10 form-control"
disabled={!UserService.Instance.myUserInfo} disabled={!this.props.myUserInfo}
onChange={linkEvent(this, handleImageUpload)} onChange={linkEvent(this, handleImageUpload)}
/> />
{this.state.imageLoading && <Spinner />} {this.state.imageLoading && <Spinner />}
@ -496,6 +498,7 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
selectedLanguageIds={selectedLangs} selectedLanguageIds={selectedLangs}
multiple={false} multiple={false}
onChange={this.handleLanguageChange} onChange={this.handleLanguageChange}
myUserInfo={this.props.myUserInfo}
/> />
{!this.props.post_view && ( {!this.props.post_view && (
<div className="mb-3 row"> <div className="mb-3 row">

View file

@ -33,6 +33,7 @@ import {
Language, Language,
LockPost, LockPost,
MarkPostAsRead, MarkPostAsRead,
MyUserInfo,
PersonView, PersonView,
PostView, PostView,
PurgePerson, PurgePerson,
@ -49,7 +50,7 @@ import {
VoteContentType, VoteContentType,
} from "../../interfaces"; } from "../../interfaces";
import { mdToHtml, mdToHtmlInline } from "../../markdown"; import { mdToHtml, mdToHtmlInline } from "../../markdown";
import { I18NextService, UserService } from "../../services"; import { I18NextService } from "../../services";
import { setupTippy } from "../../tippy"; import { setupTippy } from "../../tippy";
import { Icon, PurgeWarning, Spinner } from "../common/icon"; import { Icon, PurgeWarning, Spinner } from "../common/icon";
import { MomentTime } from "../common/moment-time"; import { MomentTime } from "../common/moment-time";
@ -98,6 +99,7 @@ interface PostListingState {
interface PostListingProps { interface PostListingProps {
post_view: PostView; post_view: PostView;
myUserInfo?: MyUserInfo;
crossPosts?: PostView[]; crossPosts?: PostView[];
moderators?: CommunityModeratorView[]; moderators?: CommunityModeratorView[];
admins?: PersonView[]; admins?: PersonView[];
@ -171,11 +173,10 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
} }
componentDidMount(): void { componentDidMount(): void {
if (UserService.Instance.myUserInfo) { if (this.props.myUserInfo) {
this.setState({ this.setState({
imageExpanded: imageExpanded:
UserService.Instance.myUserInfo.local_user_view.local_user this.props.myUserInfo.local_user_view.local_user.auto_expand,
.auto_expand,
}); });
} }
} }
@ -629,6 +630,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
{mobile && !this.props.viewOnly && ( {mobile && !this.props.viewOnly && (
<VoteButtonsCompact <VoteButtonsCompact
voteContentType={VoteContentType.Post} voteContentType={VoteContentType.Post}
loggedIn={!!this.props.myUserInfo}
id={this.postView.post.id} id={this.postView.post.id}
onVote={this.props.onPostVote} onVote={this.props.onPostVote}
enableDownvotes={this.props.enableDownvotes} enableDownvotes={this.props.enableDownvotes}
@ -639,9 +641,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
{this.props.showBody && pv.post.body && this.viewSourceButton} {this.props.showBody && pv.post.body && this.viewSourceButton}
{UserService.Instance.myUserInfo && {this.props.myUserInfo && !this.props.viewOnly && this.postActions()}
!this.props.viewOnly &&
this.postActions()}
</div> </div>
); );
} }
@ -687,7 +687,8 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
)} )}
{/* Any mod can do these, not limited to hierarchy*/} {/* 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> <li>
<hr className="dropdown-divider" /> <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_) && this.canAdmin_) &&
pv.creator_is_moderator && ( pv.creator_is_moderator && (
<li>{this.transferCommunityButton}</li> <li>{this.transferCommunityButton}</li>
@ -753,7 +758,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
} }
public get linkTarget(): string { 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 .open_links_in_new_tab
? "_blank" ? "_blank"
: // _self is the default target on links when the field is not specified : // _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"> <div className="col flex-grow-0">
<VoteButtons <VoteButtons
voteContentType={VoteContentType.Post} voteContentType={VoteContentType.Post}
loggedIn={!!this.props.myUserInfo}
id={this.postView.post.id} id={this.postView.post.id}
onVote={this.props.onPostVote} onVote={this.props.onPostVote}
enableDownvotes={this.props.enableDownvotes} enableDownvotes={this.props.enableDownvotes}
@ -1409,7 +1415,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
private get myPost(): boolean { private get myPost(): boolean {
return ( return (
this.postView.creator.id === 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.postView.creator.id,
this.props.moderators, this.props.moderators,
this.props.admins, this.props.admins,
this.props.myUserInfo,
); );
} }
get canAdmin_(): boolean { get canAdmin_(): boolean {
return canAdmin(this.postView.creator.id, this.props.admins); return canAdmin(
this.postView.creator.id,
this.props.admins,
this.props.myUserInfo,
);
} }
} }

View file

@ -9,7 +9,6 @@ import {
getCommentParentId, getCommentParentId,
getDepthFromComment, getDepthFromComment,
getIdFromProps, getIdFromProps,
setIsoData,
updateCommunityBlock, updateCommunityBlock,
updatePersonBlock, updatePersonBlock,
} from "@utils/app"; } from "@utils/app";
@ -80,8 +79,9 @@ import {
CommentNodeI, CommentNodeI,
CommentViewType, CommentViewType,
InitialFetchRequest, InitialFetchRequest,
IsoData,
} from "../../interfaces"; } from "../../interfaces";
import { FirstLoadService, I18NextService, UserService } from "../../services"; import { FirstLoadService, I18NextService } from "../../services";
import { import {
EMPTY_REQUEST, EMPTY_REQUEST,
HttpService, HttpService,
@ -123,7 +123,9 @@ interface PostState {
} }
export class Post extends Component<any, 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; private commentScrollDebounced: () => void;
state: PostState = { state: PostState = {
postRes: EMPTY_REQUEST, postRes: EMPTY_REQUEST,
@ -402,6 +404,7 @@ export class Post extends Component<any, PostState> {
{!this.state.commentId && ( {!this.state.commentId && (
<CommentForm <CommentForm
node={res.post_view.post.id} node={res.post_view.post.id}
loggedIn={!!this.isoData.site_res.my_user}
disabled={res.post_view.post.locked} disabled={res.post_view.post.locked}
allLanguages={this.state.siteRes.all_languages} allLanguages={this.state.siteRes.all_languages}
siteLanguages={this.state.siteRes.discussion_languages} siteLanguages={this.state.siteRes.discussion_languages}
@ -761,7 +764,7 @@ export class Post extends Component<any, PostState> {
// Update myUserInfo // Update myUserInfo
if (followCommunityRes.state === "success") { if (followCommunityRes.state === "success") {
const communityId = followCommunityRes.data.community_view.community.id; const communityId = followCommunityRes.data.community_view.community.id;
const mui = UserService.Instance.myUserInfo; const mui = this.isoData.site_res.my_user;
if (mui) { if (mui) {
mui.follows = mui.follows.filter(i => i.community.id !== communityId); 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) { async handleBlockCommunity(form: BlockCommunity) {
const blockCommunityRes = await HttpService.client.blockCommunity(form); const blockCommunityRes = await HttpService.client.blockCommunity(form);
if (blockCommunityRes.state === "success") { if (blockCommunityRes.state === "success") {
updateCommunityBlock(blockCommunityRes.data); updateCommunityBlock(
blockCommunityRes.data,
this.isoData.site_res.my_user,
);
this.setState(s => { this.setState(s => {
if (s.postRes.state === "success") { if (s.postRes.state === "success") {
s.postRes.data.community_view.blocked = s.postRes.data.community_view.blocked =
@ -804,7 +810,7 @@ export class Post extends Component<any, PostState> {
async handleBlockPerson(form: BlockPerson) { async handleBlockPerson(form: BlockPerson) {
const blockPersonRes = await HttpService.client.blockPerson(form); const blockPersonRes = await HttpService.client.blockPerson(form);
if (blockPersonRes.state === "success") { if (blockPersonRes.state === "success") {
updatePersonBlock(blockPersonRes.data); updatePersonBlock(blockPersonRes.data, this.isoData.site_res.my_user);
} }
} }

View file

@ -1,4 +1,4 @@
import { getRecipientIdFromProps, setIsoData } from "@utils/app"; import { getRecipientIdFromProps } from "@utils/app";
import { RouteDataResponse } from "@utils/types"; import { RouteDataResponse } from "@utils/types";
import { Component } from "inferno"; import { Component } from "inferno";
import { import {
@ -8,7 +8,7 @@ import {
GetSiteResponse, GetSiteResponse,
LemmyHttp, LemmyHttp,
} from "lemmy-js-client"; } from "lemmy-js-client";
import { InitialFetchRequest } from "../../interfaces"; import { InitialFetchRequest, IsoData } from "../../interfaces";
import { FirstLoadService, I18NextService } from "../../services"; import { FirstLoadService, I18NextService } from "../../services";
import { import {
EMPTY_REQUEST, EMPTY_REQUEST,
@ -38,7 +38,9 @@ export class CreatePrivateMessage extends Component<
any, any,
CreatePrivateMessageState CreatePrivateMessageState
> { > {
private isoData = setIsoData<CreatePrivateMessageData>(this.context); get isoData(): IsoData<CreatePrivateMessageData> {
return this.context.store.getState().value;
}
state: CreatePrivateMessageState = { state: CreatePrivateMessageState = {
siteRes: this.isoData.site_res, siteRes: this.isoData.site_res,
recipientRes: EMPTY_REQUEST, recipientRes: EMPTY_REQUEST,

View file

@ -1,4 +1,3 @@
import { setIsoData } from "@utils/app";
import { getQueryParams } from "@utils/helpers"; import { getQueryParams } from "@utils/helpers";
import { QueryParams, RouteDataResponse } from "@utils/types"; import { QueryParams, RouteDataResponse } from "@utils/types";
import { Component, linkEvent } from "inferno"; import { Component, linkEvent } from "inferno";
@ -7,7 +6,7 @@ import {
LemmyHttp, LemmyHttp,
ResolveObjectResponse, ResolveObjectResponse,
} from "lemmy-js-client"; } from "lemmy-js-client";
import { InitialFetchRequest } from "../interfaces"; import { InitialFetchRequest, IsoData } from "../interfaces";
import { FirstLoadService, HttpService, I18NextService } from "../services"; import { FirstLoadService, HttpService, I18NextService } from "../services";
import { import {
EMPTY_REQUEST, EMPTY_REQUEST,
@ -84,7 +83,9 @@ const handleFollow = (i: RemoteFetch) => handleToggleFollow(i, true);
const handleUnfollow = (i: RemoteFetch) => handleToggleFollow(i, false); const handleUnfollow = (i: RemoteFetch) => handleToggleFollow(i, false);
export class RemoteFetch extends Component<any, RemoteFetchState> { 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 = { state: RemoteFetchState = {
resolveObjectRes: EMPTY_REQUEST, resolveObjectRes: EMPTY_REQUEST,
isIsomorphic: false, isIsomorphic: false,

View file

@ -8,7 +8,6 @@ import {
getUpdatedSearchId, getUpdatedSearchId,
myAuth, myAuth,
personToChoice, personToChoice,
setIsoData,
showLocal, showLocal,
} from "@utils/app"; } from "@utils/app";
import { restoreScrollPosition, saveScrollPosition } from "@utils/browser"; import { restoreScrollPosition, saveScrollPosition } from "@utils/browser";
@ -47,7 +46,7 @@ import {
SortType, SortType,
} from "lemmy-js-client"; } from "lemmy-js-client";
import { fetchLimit } from "../config"; import { fetchLimit } from "../config";
import { CommentViewType, InitialFetchRequest } from "../interfaces"; import { CommentViewType, InitialFetchRequest, IsoData } from "../interfaces";
import { FirstLoadService, I18NextService } from "../services"; import { FirstLoadService, I18NextService } from "../services";
import { import {
EMPTY_REQUEST, EMPTY_REQUEST,
@ -241,7 +240,9 @@ function getListing(
} }
export class Search extends Component<any, SearchState> { 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>(); searchInput = createRef<HTMLInputElement>();
state: SearchState = { state: SearchState = {

View file

@ -20,7 +20,7 @@ export type IsoDataOptionalSite<T extends RouteData = any> = Partial<
declare global { declare global {
interface Window { interface Window {
isoData: IsoData; isoData?: IsoDataOptionalSite;
} }
} }

View file

@ -1,7 +1,11 @@
import { getHttpBase } from "@utils/env"; import { getHttpBase } from "@utils/env";
import { LemmyHttp } from "lemmy-js-client"; import { LemmyHttp, LoginResponse } from "lemmy-js-client";
import { toast } from "../toast"; import { toast } from "../toast";
import { I18NextService } from "./I18NextService"; 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 = { export const EMPTY_REQUEST = {
state: "empty", state: "empty",
@ -56,7 +60,7 @@ class WrappedLemmyHttpClient {
Object.getPrototypeOf(this.rawClient), Object.getPrototypeOf(this.rawClient),
)) { )) {
if (key !== "constructor") { if (key !== "constructor") {
this[key] = async (...args) => { this[key] = async (...args: any) => {
try { try {
const res = await this.rawClient[key](...args); const res = await this.rawClient[key](...args);
@ -88,6 +92,18 @@ export function wrapClient(client: LemmyHttp, silent = false) {
) as unknown as WrappedLemmyHttp; ) 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 { export class HttpService {
static #_instance: HttpService; static #_instance: HttpService;
#silent_client: WrappedLemmyHttp; #silent_client: WrappedLemmyHttp;
@ -95,10 +111,42 @@ export class HttpService {
private constructor() { private constructor() {
const lemmyHttp = new LemmyHttp(getHttpBase()); 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.#client = wrapClient(lemmyHttp);
this.#silent_client = wrapClient(lemmyHttp, true); 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() { static get #Instance() {
return this.#_instance ?? (this.#_instance = new this()); return this.#_instance ?? (this.#_instance = new this());
} }

View file

@ -1,4 +1,4 @@
import { UserService, HttpService } from "../services"; import { HttpService } from "../services";
import { updateUnreadCountsInterval } from "../config"; import { updateUnreadCountsInterval } from "../config";
import { poll } from "@utils/helpers"; import { poll } from "@utils/helpers";
import { myAuth } from "@utils/app"; import { myAuth } from "@utils/app";

View file

@ -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());
}
}

View file

@ -1,5 +1,4 @@
export { FirstLoadService } from "./FirstLoadService"; export { FirstLoadService } from "./FirstLoadService";
export { HttpService } from "./HttpService"; export { HttpService } from "./HttpService";
export { I18NextService } from "./I18NextService"; export { I18NextService } from "./I18NextService";
export { UserService } from "./UserService";
export { UnreadCounterService } from "./UnreadCounterService"; export { UnreadCounterService } from "./UnreadCounterService";

View file

@ -43,7 +43,6 @@ import personToChoice from "./person-to-choice";
import postToCommentSortType from "./post-to-comment-sort-type"; import postToCommentSortType from "./post-to-comment-sort-type";
import searchCommentTree from "./search-comment-tree"; import searchCommentTree from "./search-comment-tree";
import selectableLanguages from "./selectable-languages"; import selectableLanguages from "./selectable-languages";
import setIsoData from "./set-iso-data";
import setTheme from "./set-theme"; import setTheme from "./set-theme";
import setupDateFns from "./setup-date-fns"; import setupDateFns from "./setup-date-fns";
import showAvatars from "./show-avatars"; import showAvatars from "./show-avatars";
@ -55,6 +54,7 @@ import updatePersonBlock from "./update-person-block";
import instanceToChoice from "./instance-to-choice"; import instanceToChoice from "./instance-to-choice";
import updateInstanceBlock from "./update-instance-block"; import updateInstanceBlock from "./update-instance-block";
import isAnonymousPath from "./is-anonymous-path"; import isAnonymousPath from "./is-anonymous-path";
import setupRedux from "./setup-redux";
export { export {
buildCommentsTree, buildCommentsTree,
@ -102,11 +102,11 @@ export {
postToCommentSortType, postToCommentSortType,
searchCommentTree, searchCommentTree,
selectableLanguages, selectableLanguages,
setIsoData,
setTheme, setTheme,
setupDateFns, setupDateFns,
showAvatars, showAvatars,
showLocal, showLocal,
setupRedux,
showScores, showScores,
siteBannerCss, siteBannerCss,
updateCommunityBlock, updateCommunityBlock,

View file

@ -4,6 +4,7 @@ import { I18NextService, UserService } from "../../services";
import { updateDataBsTheme } from "@utils/browser"; import { updateDataBsTheme } from "@utils/browser";
export default function initializeSite(site?: GetSiteResponse) { export default function initializeSite(site?: GetSiteResponse) {
// TODO Should already be in siteRes
UserService.Instance.myUserInfo = site?.my_user; UserService.Instance.myUserInfo = site?.my_user;
updateDataBsTheme(site); updateDataBsTheme(site);
I18NextService.i18n.changeLanguage(); I18NextService.i18n.changeLanguage();

View file

@ -1,9 +1,8 @@
import { MyUserInfo, PostView } from "lemmy-js-client"; import { MyUserInfo, PostView } from "lemmy-js-client";
import { UserService } from "../../services";
export default function isPostBlocked( export default function isPostBlocked(
pv: PostView, pv: PostView,
myUserInfo: MyUserInfo | undefined = UserService.Instance.myUserInfo, myUserInfo?: MyUserInfo,
): boolean { ): boolean {
return ( return (
(myUserInfo?.community_blocks (myUserInfo?.community_blocks

View file

@ -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(throwErr = false): string | undefined {
export default function myAuth(): string | undefined { if (auth) {
return UserService.Instance.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;
}
} }

View file

@ -1,9 +1,8 @@
import { PostView } from "lemmy-js-client"; import { MyUserInfo, PostView } from "lemmy-js-client";
import { UserService } from "../../services";
export default function nsfwCheck( export default function nsfwCheck(
pv: PostView, pv: PostView,
myUserInfo = UserService.Instance.myUserInfo, myUserInfo?: MyUserInfo,
): boolean { ): boolean {
const nsfw = pv.post.nsfw || pv.community.nsfw; const nsfw = pv.post.nsfw || pv.community.nsfw;
const myShowNsfw = myUserInfo?.local_user_view.local_user.show_nsfw ?? false; const myShowNsfw = myUserInfo?.local_user_view.local_user.show_nsfw ?? false;

View file

@ -1,5 +1,4 @@
import { Language } from "lemmy-js-client"; import { Language, MyUserInfo } from "lemmy-js-client";
import { UserService } from "../../services";
/** /**
* This shows what language you can select * This shows what language you can select
@ -13,7 +12,7 @@ export default function selectableLanguages(
siteLanguages: number[], siteLanguages: number[],
showAll?: boolean, showAll?: boolean,
showSite?: boolean, showSite?: boolean,
myUserInfo = UserService.Instance.myUserInfo, myUserInfo?: MyUserInfo,
): Language[] { ): Language[] {
const allLangIds = allLanguages.map(l => l.id); const allLangIds = allLanguages.map(l => l.id);
let myLangs = myUserInfo?.discussion_languages ?? allLangIds; let myLangs = myUserInfo?.discussion_languages ?? allLangIds;

View file

@ -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;
}

View 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;
}

View file

@ -1,7 +1,5 @@
import { UserService } from "../../services"; import { MyUserInfo } from "lemmy-js-client";
export default function showAvatars( export default function showAvatars(myUserInfo?: MyUserInfo): boolean {
myUserInfo = UserService.Instance.myUserInfo,
): boolean {
return myUserInfo?.local_user_view.local_user.show_avatars ?? true; return myUserInfo?.local_user_view.local_user.show_avatars ?? true;
} }

View file

@ -1,7 +1,5 @@
import { UserService } from "../../services"; import { MyUserInfo } from "lemmy-js-client";
export default function showScores( export default function showScores(myUserInfo?: MyUserInfo): boolean {
myUserInfo = UserService.Instance.myUserInfo,
): boolean {
return myUserInfo?.local_user_view.local_user.show_scores ?? true; return myUserInfo?.local_user_view.local_user.show_scores ?? true;
} }

View file

@ -1,10 +1,10 @@
import { BlockCommunityResponse, MyUserInfo } from "lemmy-js-client"; import { BlockCommunityResponse, MyUserInfo } from "lemmy-js-client";
import { I18NextService, UserService } from "../../services"; import { I18NextService } from "../../services";
import { toast } from "../../toast"; import { toast } from "../../toast";
export default function updateCommunityBlock( export default function updateCommunityBlock(
data: BlockCommunityResponse, data: BlockCommunityResponse,
myUserInfo: MyUserInfo | undefined = UserService.Instance.myUserInfo, myUserInfo?: MyUserInfo,
) { ) {
if (myUserInfo) { if (myUserInfo) {
if (data.blocked) { if (data.blocked) {

View file

@ -1,12 +1,12 @@
import { BlockInstanceResponse, Instance, MyUserInfo } from "lemmy-js-client"; import { BlockInstanceResponse, Instance, MyUserInfo } from "lemmy-js-client";
import { I18NextService, UserService } from "../../services"; import { I18NextService } from "../../services";
import { toast } from "../../toast"; import { toast } from "../../toast";
export default function updateInstanceBlock( export default function updateInstanceBlock(
data: BlockInstanceResponse, data: BlockInstanceResponse,
id: number, id: number,
linkedInstances: Instance[], linkedInstances: Instance[],
myUserInfo: MyUserInfo | undefined = UserService.Instance.myUserInfo, myUserInfo?: MyUserInfo,
) { ) {
if (myUserInfo) { if (myUserInfo) {
const instance = linkedInstances.find(i => i.id === id)!; const instance = linkedInstances.find(i => i.id === id)!;

View file

@ -1,10 +1,10 @@
import { BlockPersonResponse, MyUserInfo } from "lemmy-js-client"; import { BlockPersonResponse, MyUserInfo } from "lemmy-js-client";
import { I18NextService, UserService } from "../../services"; import { I18NextService } from "../../services";
import { toast } from "../../toast"; import { toast } from "../../toast";
export default function updatePersonBlock( export default function updatePersonBlock(
data: BlockPersonResponse, data: BlockPersonResponse,
myUserInfo: MyUserInfo | undefined = UserService.Instance.myUserInfo, myUserInfo?: MyUserInfo,
) { ) {
if (myUserInfo) { if (myUserInfo) {
if (data.blocked) { if (data.blocked) {

View file

View file

@ -1,7 +1,5 @@
import { UserService } from "../../services"; import { MyUserInfo } from "lemmy-js-client";
export default function amAdmin( export default function amAdmin(myUserInfo?: MyUserInfo): boolean {
myUserInfo = UserService.Instance.myUserInfo,
): boolean {
return myUserInfo?.local_user_view.local_user.admin ?? false; return myUserInfo?.local_user_view.local_user.admin ?? false;
} }

View file

@ -1,10 +1,9 @@
import { CommunityModeratorView } from "lemmy-js-client"; import { CommunityModeratorView, MyUserInfo } from "lemmy-js-client";
import { UserService } from "../../services";
export default function amCommunityCreator( export default function amCommunityCreator(
creator_id: number, creator_id: number,
mods?: CommunityModeratorView[], mods?: CommunityModeratorView[],
myUserInfo = UserService.Instance.myUserInfo, myUserInfo?: MyUserInfo,
): boolean { ): boolean {
const myId = myUserInfo?.local_user_view.person.id; const myId = myUserInfo?.local_user_view.person.id;
// Don't allow mod actions on yourself // Don't allow mod actions on yourself

View file

@ -1,9 +1,8 @@
import { CommunityId } from "lemmy-js-client"; import { CommunityId, MyUserInfo } from "lemmy-js-client";
import { UserService } from "../../services";
export default function amMod( export default function amMod(
communityId: CommunityId, communityId: CommunityId,
myUserInfo = UserService.Instance.myUserInfo, myUserInfo?: MyUserInfo,
): boolean { ): boolean {
return myUserInfo return myUserInfo
? myUserInfo.moderates.map(cmv => cmv.community.id).includes(communityId) ? myUserInfo.moderates.map(cmv => cmv.community.id).includes(communityId)

View file

@ -1,10 +1,9 @@
import { PersonView } from "lemmy-js-client"; import { MyUserInfo, PersonView } from "lemmy-js-client";
import { UserService } from "../../services";
export default function amSiteCreator( export default function amSiteCreator(
creator_id: number, creator_id: number,
admins?: PersonView[], admins?: PersonView[],
myUserInfo = UserService.Instance.myUserInfo, myUserInfo?: MyUserInfo,
): boolean { ): boolean {
const myId = myUserInfo?.local_user_view.person.id; const myId = myUserInfo?.local_user_view.person.id;
return myId === admins?.at(0)?.person.id && myId !== creator_id; return myId === admins?.at(0)?.person.id && myId !== creator_id;

View file

@ -1,9 +1,8 @@
import { CommunityModeratorView } from "lemmy-js-client"; import { CommunityModeratorView, MyUserInfo } from "lemmy-js-client";
import { UserService } from "../../services";
export default function amTopMod( export default function amTopMod(
mods: CommunityModeratorView[], mods: CommunityModeratorView[],
myUserInfo = UserService.Instance.myUserInfo, myUserInfo?: MyUserInfo,
): boolean { ): boolean {
return mods.at(0)?.moderator.id === myUserInfo?.local_user_view.person.id; return mods.at(0)?.moderator.id === myUserInfo?.local_user_view.person.id;
} }

View file

@ -1,11 +1,10 @@
import { canMod } from "@utils/roles"; import { canMod } from "@utils/roles";
import { PersonView } from "lemmy-js-client"; import { MyUserInfo, PersonView } from "lemmy-js-client";
import { UserService } from "../../services";
export default function canAdmin( export default function canAdmin(
creatorId: number, creatorId: number,
admins?: PersonView[], admins?: PersonView[],
myUserInfo = UserService.Instance.myUserInfo, myUserInfo?: MyUserInfo,
onSelf = false, onSelf = false,
): boolean { ): boolean {
return canMod(creatorId, undefined, admins, myUserInfo, onSelf); return canMod(creatorId, undefined, admins, myUserInfo, onSelf);

View file

@ -1,12 +1,8 @@
import { amAdmin } from "@utils/roles"; import { amAdmin } from "@utils/roles";
import { GetSiteResponse } from "lemmy-js-client"; import { GetSiteResponse } from "lemmy-js-client";
import { UserService } from "../../services";
export default function canCreateCommunity( export default function canCreateCommunity(siteRes: GetSiteResponse): boolean {
siteRes: GetSiteResponse,
myUserInfo = UserService.Instance.myUserInfo,
): boolean {
const adminOnly = siteRes.site_view.local_site.community_creation_admin_only; const adminOnly = siteRes.site_view.local_site.community_creation_admin_only;
// TODO: Make this check if user is logged on as well // TODO: Make this check if user is logged on as well
return !adminOnly || amAdmin(myUserInfo); return !adminOnly || amAdmin(siteRes.my_user);
} }

View file

@ -1,11 +1,14 @@
import { CommunityModeratorView, PersonView } from "lemmy-js-client"; import {
import { UserService } from "../../services"; CommunityModeratorView,
MyUserInfo,
PersonView,
} from "lemmy-js-client";
export default function canMod( export default function canMod(
creator_id: number, creator_id: number,
mods?: CommunityModeratorView[], mods?: CommunityModeratorView[],
admins?: PersonView[], admins?: PersonView[],
myUserInfo = UserService.Instance.myUserInfo, myUserInfo?: MyUserInfo,
onSelf = false, onSelf = false,
): boolean { ): boolean {
// You can do moderator actions only on the mods added after you. // You can do moderator actions only on the mods added after you.

View file

@ -7,6 +7,7 @@ import canAdmin from "./can-admin";
import canCreateCommunity from "./can-create-community"; import canCreateCommunity from "./can-create-community";
import canMod from "./can-mod"; import canMod from "./can-mod";
import isBanned from "./is-banned"; import isBanned from "./is-banned";
import moderatesSomething from "./moderates-something";
export { export {
amAdmin, amAdmin,
@ -18,4 +19,5 @@ export {
canCreateCommunity, canCreateCommunity,
canMod, canMod,
isBanned, isBanned,
moderatesSomething,
}; };

View 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;
}

View file

@ -1217,6 +1217,16 @@
resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.11.8.tgz#6b79032e760a0899cd4204710beede972a3a185f" resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.11.8.tgz#6b79032e760a0899cd4204710beede972a3a185f"
integrity sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A== 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": "@rollup/plugin-babel@^5.2.0":
version "5.3.1" version "5.3.1"
resolved "https://registry.yarnpkg.com/@rollup/plugin-babel/-/plugin-babel-5.3.1.tgz#04bc0608f4aa4b2e4b1aebf284344d0f68fda283" 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" resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.0.tgz#67418ae40d34d6999c95ff56016759c718c82f78"
integrity sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg== 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: immutable@^4.0.0:
version "4.3.4" version "4.3.4"
resolved "https://registry.yarnpkg.com/immutable/-/immutable-4.3.4.tgz#2e07b33837b4bb7662f288c244d1ced1ef65a78f" 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-shared "^8.0.3"
inferno-vnode-flags "^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: inferno-router@^8.2.2:
version "8.2.2" version "8.2.2"
resolved "https://registry.yarnpkg.com/inferno-router/-/inferno-router-8.2.2.tgz#3d13e2610ecb8f6bb3e36421ab569c21777a0d23" resolved "https://registry.yarnpkg.com/inferno-router/-/inferno-router-8.2.2.tgz#3d13e2610ecb8f6bb3e36421ab569c21777a0d23"
@ -7719,6 +7742,16 @@ rechoir@^0.8.0:
dependencies: dependencies:
resolve "^1.20.0" 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: reflect.getprototypeof@^1.0.4:
version "1.0.4" version "1.0.4"
resolved "https://registry.yarnpkg.com/reflect.getprototypeof/-/reflect.getprototypeof-1.0.4.tgz#aaccbf41aca3821b87bb71d9dcbc7ad0ba50a3f3" 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" resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff"
integrity sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ== 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: resolve-cwd@^3.0.0:
version "3.0.0" version "3.0.0"
resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-3.0.0.tgz#0f0075f1bb2544766cf73ba6a6e2adfebcb13f2d" resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-3.0.0.tgz#0f0075f1bb2544766cf73ba6a6e2adfebcb13f2d"