Refactor route data

This commit is contained in:
abias 2023-05-29 20:40:00 -04:00
parent 7bcf079acf
commit feb4c434d1
18 changed files with 451 additions and 308 deletions

View file

@ -129,7 +129,7 @@ server.get("/*", async (req, res) => {
// This bypasses errors, so that the client can hit the error on its own, // This bypasses errors, so that the client can hit the error on its own,
// in order to remove the jwt on the browser. Necessary for wrong jwts // in order to remove the jwt on the browser. Necessary for wrong jwts
let site: GetSiteResponse | undefined = undefined; let site: GetSiteResponse | undefined = undefined;
let routeData: any[] = []; let routeData: Record<string, any> = {};
let errorPageData: ErrorPageData | undefined; let errorPageData: ErrorPageData | undefined;
try { try {
let try_site: any = await client.getSite(getSiteForm); let try_site: any = await client.getSite(getSiteForm);
@ -160,18 +160,27 @@ server.get("/*", async (req, res) => {
}; };
if (activeRoute?.fetchInitialData) { if (activeRoute?.fetchInitialData) {
routeData = await Promise.all([ const routeDataKeysAndVals = await Promise.all(
...activeRoute.fetchInitialData(initialFetchReq), Object.entries(activeRoute.fetchInitialData(initialFetchReq)).map(
]); async ([key, val]) => [key, await val]
)
);
routeData = routeDataKeysAndVals.reduce((acc, [key, val]) => {
acc[key] = val;
return acc;
}, {});
} }
} }
} catch (error) { } catch (error) {
errorPageData = getErrorPageData(error, site); errorPageData = getErrorPageData(error, site);
} }
const error = Object.values(routeData).find(val => val?.error)?.error;
// Redirect to the 404 if there's an API error // Redirect to the 404 if there's an API error
if (routeData[0] && routeData[0].error) { if (error) {
const error = routeData[0].error;
console.error(error); console.error(error);
if (error === "instance_is_private") { if (error === "instance_is_private") {
return res.redirect(`/signup`); return res.redirect(`/signup`);

View file

@ -16,6 +16,7 @@ import { i18n } from "../../i18next";
import { WebSocketService } from "../../services"; import { WebSocketService } from "../../services";
import { import {
QueryParams, QueryParams,
WithPromiseKeys,
getPageFromString, getPageFromString,
getQueryParams, getQueryParams,
getQueryString, getQueryString,
@ -36,6 +37,10 @@ import { CommunityLink } from "./community-link";
const communityLimit = 50; const communityLimit = 50;
interface CommunitiesData {
listCommunitiesResponse: ListCommunitiesResponse;
}
interface CommunitiesState { interface CommunitiesState {
listCommunitiesResponse?: ListCommunitiesResponse; listCommunitiesResponse?: ListCommunitiesResponse;
loading: boolean; loading: boolean;
@ -88,7 +93,7 @@ function refetch() {
export class Communities extends Component<any, CommunitiesState> { export class Communities extends Component<any, CommunitiesState> {
private subscription?: Subscription; private subscription?: Subscription;
private isoData = setIsoData(this.context); private isoData = setIsoData<CommunitiesData>(this.context);
state: CommunitiesState = { state: CommunitiesState = {
loading: true, loading: true,
siteRes: this.isoData.site_res, siteRes: this.isoData.site_res,
@ -105,10 +110,11 @@ export class Communities extends Component<any, CommunitiesState> {
// Only fetch the data if coming from another route // Only fetch the data if coming from another route
if (this.isoData.path === this.context.router.route.match.url) { if (this.isoData.path === this.context.router.route.match.url) {
const listRes = this.isoData.routeData[0] as ListCommunitiesResponse; const { listCommunitiesResponse } = this.isoData.routeData;
this.state = { this.state = {
...this.state, ...this.state,
listCommunitiesResponse: listRes, listCommunitiesResponse,
loading: false, loading: false,
}; };
} else { } else {
@ -312,7 +318,9 @@ export class Communities extends Component<any, CommunitiesState> {
query: { listingType, page }, query: { listingType, page },
client, client,
auth, auth,
}: InitialFetchRequest<QueryParams<CommunitiesProps>>): Promise<any>[] { }: InitialFetchRequest<
QueryParams<CommunitiesProps>
>): WithPromiseKeys<CommunitiesData> {
const listCommunitiesForm: ListCommunities = { const listCommunitiesForm: ListCommunities = {
type_: getListingTypeFromQuery(listingType), type_: getListingTypeFromQuery(listingType),
sort: "TopMonth", sort: "TopMonth",
@ -321,7 +329,9 @@ export class Communities extends Component<any, CommunitiesState> {
auth: auth, auth: auth,
}; };
return [client.listCommunities(listCommunitiesForm)]; return {
listCommunitiesResponse: client.listCommunities(listCommunitiesForm),
};
} }
parseMessage(msg: any) { parseMessage(msg: any) {

View file

@ -33,6 +33,7 @@ import {
import { UserService, WebSocketService } from "../../services"; import { UserService, WebSocketService } from "../../services";
import { import {
QueryParams, QueryParams,
WithPromiseKeys,
commentsToFlatNodes, commentsToFlatNodes,
communityRSSUrl, communityRSSUrl,
createCommentLikeRes, createCommentLikeRes,
@ -76,6 +77,12 @@ import { SiteSidebar } from "../home/site-sidebar";
import { PostListings } from "../post/post-listings"; import { PostListings } from "../post/post-listings";
import { CommunityLink } from "./community-link"; import { CommunityLink } from "./community-link";
interface CommunityData {
communityResponse: GetCommunityResponse;
postsResponse?: GetPostsResponse;
commentsResponse?: GetCommentsResponse;
}
interface State { interface State {
communityRes?: GetCommunityResponse; communityRes?: GetCommunityResponse;
communityLoading: boolean; communityLoading: boolean;
@ -115,7 +122,7 @@ export class Community extends Component<
RouteComponentProps<{ name: string }>, RouteComponentProps<{ name: string }>,
State State
> { > {
private isoData = setIsoData(this.context); private isoData = setIsoData<CommunityData>(this.context);
private subscription?: Subscription; private subscription?: Subscription;
state: State = { state: State = {
communityLoading: true, communityLoading: true,
@ -137,23 +144,20 @@ export class Community extends Component<
// Only fetch the data if coming from another route // Only fetch the data if coming from another route
if (this.isoData.path == this.context.router.route.match.url) { if (this.isoData.path == this.context.router.route.match.url) {
const { communityResponse, commentsResponse, postsResponse } =
this.isoData.routeData;
this.state = { this.state = {
...this.state, ...this.state,
communityRes: this.isoData.routeData[0] as GetCommunityResponse, communityRes: communityResponse,
}; };
const postsRes = this.isoData.routeData[1] as
| GetPostsResponse
| undefined;
const commentsRes = this.isoData.routeData[2] as
| GetCommentsResponse
| undefined;
if (postsRes) { if (postsResponse) {
this.state = { ...this.state, posts: postsRes.posts }; this.state = { ...this.state, posts: postsResponse.posts };
} }
if (commentsRes) { if (commentsResponse) {
this.state = { ...this.state, comments: commentsRes.comments }; this.state = { ...this.state, comments: commentsResponse.comments };
} }
this.state = { this.state = {
@ -189,16 +193,16 @@ export class Community extends Component<
path, path,
query: { dataType: urlDataType, page: urlPage, sort: urlSort }, query: { dataType: urlDataType, page: urlPage, sort: urlSort },
auth, auth,
}: InitialFetchRequest<QueryParams<CommunityProps>>): Promise<any>[] { }: InitialFetchRequest<
QueryParams<CommunityProps>
>): WithPromiseKeys<CommunityData> {
const pathSplit = path.split("/"); const pathSplit = path.split("/");
const promises: Promise<any>[] = [];
const communityName = pathSplit[2]; const communityName = pathSplit[2];
const communityForm: GetCommunity = { const communityForm: GetCommunity = {
name: communityName, name: communityName,
auth, auth,
}; };
promises.push(client.getCommunity(communityForm));
const dataType = getDataTypeFromQuery(urlDataType); const dataType = getDataTypeFromQuery(urlDataType);
@ -206,6 +210,9 @@ export class Community extends Component<
const page = getPageFromString(urlPage); const page = getPageFromString(urlPage);
let postsResponse: Promise<GetPostsResponse> | undefined = undefined;
let commentsResponse: Promise<GetCommentsResponse> | undefined = undefined;
if (dataType === DataType.Post) { if (dataType === DataType.Post) {
const getPostsForm: GetPosts = { const getPostsForm: GetPosts = {
community_name: communityName, community_name: communityName,
@ -216,8 +223,8 @@ export class Community extends Component<
saved_only: false, saved_only: false,
auth, auth,
}; };
promises.push(client.getPosts(getPostsForm));
promises.push(Promise.resolve()); postsResponse = client.getPosts(getPostsForm);
} else { } else {
const getCommentsForm: GetComments = { const getCommentsForm: GetComments = {
community_name: communityName, community_name: communityName,
@ -228,11 +235,15 @@ export class Community extends Component<
saved_only: false, saved_only: false,
auth, auth,
}; };
promises.push(Promise.resolve());
promises.push(client.getComments(getCommentsForm)); commentsResponse = client.getComments(getCommentsForm);
} }
return promises; return {
communityResponse: client.getCommunity(communityForm),
commentsResponse,
postsResponse,
};
} }
get documentTitle(): string { get documentTitle(): string {

View file

@ -2,7 +2,6 @@ import autosize from "autosize";
import { Component, linkEvent } from "inferno"; import { Component, linkEvent } from "inferno";
import { import {
BannedPersonsResponse, BannedPersonsResponse,
GetBannedPersons,
GetFederatedInstancesResponse, GetFederatedInstancesResponse,
GetSiteResponse, GetSiteResponse,
PersonView, PersonView,
@ -16,6 +15,7 @@ import { i18n } from "../../i18next";
import { InitialFetchRequest } from "../../interfaces"; import { InitialFetchRequest } from "../../interfaces";
import { WebSocketService } from "../../services"; import { WebSocketService } from "../../services";
import { import {
WithPromiseKeys,
capitalizeFirstLetter, capitalizeFirstLetter,
isBrowser, isBrowser,
myAuth, myAuth,
@ -35,6 +35,11 @@ import RateLimitForm from "./rate-limit-form";
import { SiteForm } from "./site-form"; import { SiteForm } from "./site-form";
import { TaglineForm } from "./tagline-form"; import { TaglineForm } from "./tagline-form";
interface AdminSettingsData {
bannedPersonsResponse: BannedPersonsResponse;
federatedInstancesResponse: GetFederatedInstancesResponse;
}
interface AdminSettingsState { interface AdminSettingsState {
siteRes: GetSiteResponse; siteRes: GetSiteResponse;
instancesRes?: GetFederatedInstancesResponse; instancesRes?: GetFederatedInstancesResponse;
@ -45,7 +50,7 @@ interface AdminSettingsState {
export class AdminSettings extends Component<any, AdminSettingsState> { export class AdminSettings extends Component<any, AdminSettingsState> {
private siteConfigTextAreaId = `site-config-${randomStr()}`; private siteConfigTextAreaId = `site-config-${randomStr()}`;
private isoData = setIsoData(this.context); private isoData = setIsoData<AdminSettingsData>(this.context);
private subscription?: Subscription; private subscription?: Subscription;
state: AdminSettingsState = { state: AdminSettingsState = {
siteRes: this.isoData.site_res, siteRes: this.isoData.site_res,
@ -62,11 +67,13 @@ export class AdminSettings extends Component<any, AdminSettingsState> {
// Only fetch the data if coming from another route // Only fetch the data if coming from another route
if (this.isoData.path == this.context.router.route.match.url) { if (this.isoData.path == this.context.router.route.match.url) {
const { bannedPersonsResponse, federatedInstancesResponse } =
this.isoData.routeData;
this.state = { this.state = {
...this.state, ...this.state,
banned: (this.isoData.routeData[0] as BannedPersonsResponse).banned, banned: bannedPersonsResponse.banned,
instancesRes: this.isoData instancesRes: federatedInstancesResponse,
.routeData[1] as GetFederatedInstancesResponse,
loading: false, loading: false,
}; };
} else { } else {
@ -84,17 +91,16 @@ export class AdminSettings extends Component<any, AdminSettingsState> {
} }
} }
static fetchInitialData(req: InitialFetchRequest): Promise<any>[] { static fetchInitialData({
let promises: Promise<any>[] = []; auth,
client,
let auth = req.auth; }: InitialFetchRequest): WithPromiseKeys<AdminSettingsData> {
if (auth) { return {
let bannedPersonsForm: GetBannedPersons = { auth }; bannedPersonsResponse: client.getBannedPersons({ auth: auth as string }),
promises.push(req.client.getBannedPersons(bannedPersonsForm)); federatedInstancesResponse: client.getFederatedInstances({
promises.push(req.client.getFederatedInstances({ auth })); auth: auth as string,
} }) as Promise<GetFederatedInstancesResponse>,
};
return promises;
} }
componentDidMount() { componentDidMount() {

View file

@ -69,6 +69,7 @@ import {
toast, toast,
trendingFetchLimit, trendingFetchLimit,
updatePersonBlock, updatePersonBlock,
WithPromiseKeys,
wsClient, wsClient,
wsSubscribe, wsSubscribe,
} from "../../utils"; } from "../../utils";
@ -103,6 +104,12 @@ interface HomeProps {
page: number; page: number;
} }
interface HomeData {
postsResponse?: GetPostsResponse;
commentsResponse?: GetCommentsResponse;
trendingResponse: ListCommunitiesResponse;
}
function getDataTypeFromQuery(type?: string): DataType { function getDataTypeFromQuery(type?: string): DataType {
return type ? DataType[type] : DataType.Post; return type ? DataType[type] : DataType.Post;
} }
@ -237,7 +244,7 @@ function getRss(listingType: ListingType) {
} }
export class Home extends Component<any, HomeState> { export class Home extends Component<any, HomeState> {
private isoData = setIsoData(this.context); private isoData = setIsoData<HomeData>(this.context);
private subscription?: Subscription; private subscription?: Subscription;
state: HomeState = { state: HomeState = {
trendingCommunities: [], trendingCommunities: [],
@ -264,22 +271,15 @@ export class Home extends Component<any, HomeState> {
// Only fetch the data if coming from another route // Only fetch the data if coming from another route
if (this.isoData.path === this.context.router.route.match.url) { if (this.isoData.path === this.context.router.route.match.url) {
const postsRes = this.isoData.routeData[0] as const { trendingResponse, commentsResponse, postsResponse } =
| GetPostsResponse this.isoData.routeData;
| undefined;
const commentsRes = this.isoData.routeData[1] as
| GetCommentsResponse
| undefined;
const trendingRes = this.isoData.routeData[2] as
| ListCommunitiesResponse
| undefined;
if (postsRes) { if (postsResponse) {
this.state = { ...this.state, posts: postsRes.posts }; this.state = { ...this.state, posts: postsResponse.posts };
} }
if (commentsRes) { if (commentsResponse) {
this.state = { ...this.state, comments: commentsRes.comments }; this.state = { ...this.state, comments: commentsResponse.comments };
} }
if (isBrowser()) { if (isBrowser()) {
@ -290,7 +290,7 @@ export class Home extends Component<any, HomeState> {
const taglines = this.state?.siteRes?.taglines ?? []; const taglines = this.state?.siteRes?.taglines ?? [];
this.state = { this.state = {
...this.state, ...this.state,
trendingCommunities: trendingRes?.communities ?? [], trendingCommunities: trendingResponse?.communities ?? [],
loading: false, loading: false,
tagline: getRandomFromList(taglines)?.content, tagline: getRandomFromList(taglines)?.content,
}; };
@ -317,7 +317,7 @@ export class Home extends Component<any, HomeState> {
client, client,
auth, auth,
query: { dataType: urlDataType, listingType, page: urlPage, sort: urlSort }, query: { dataType: urlDataType, listingType, page: urlPage, sort: urlSort },
}: InitialFetchRequest<QueryParams<HomeProps>>): Promise<any>[] { }: InitialFetchRequest<QueryParams<HomeProps>>): WithPromiseKeys<HomeData> {
const dataType = getDataTypeFromQuery(urlDataType); const dataType = getDataTypeFromQuery(urlDataType);
// TODO figure out auth default_listingType, default_sort_type // TODO figure out auth default_listingType, default_sort_type
@ -328,6 +328,9 @@ export class Home extends Component<any, HomeState> {
const promises: Promise<any>[] = []; const promises: Promise<any>[] = [];
let postsResponse: Promise<GetPostsResponse> | undefined = undefined;
let commentsResponse: Promise<GetCommentsResponse> | undefined = undefined;
if (dataType === DataType.Post) { if (dataType === DataType.Post) {
const getPostsForm: GetPosts = { const getPostsForm: GetPosts = {
type_, type_,
@ -338,8 +341,7 @@ export class Home extends Component<any, HomeState> {
auth, auth,
}; };
promises.push(client.getPosts(getPostsForm)); postsResponse = client.getPosts(getPostsForm);
promises.push(Promise.resolve());
} else { } else {
const getCommentsForm: GetComments = { const getCommentsForm: GetComments = {
page, page,
@ -349,8 +351,8 @@ export class Home extends Component<any, HomeState> {
saved_only: false, saved_only: false,
auth, auth,
}; };
promises.push(Promise.resolve());
promises.push(client.getComments(getCommentsForm)); commentsResponse = client.getComments(getCommentsForm);
} }
const trendingCommunitiesForm: ListCommunities = { const trendingCommunitiesForm: ListCommunities = {
@ -361,7 +363,11 @@ export class Home extends Component<any, HomeState> {
}; };
promises.push(client.listCommunities(trendingCommunitiesForm)); promises.push(client.listCommunities(trendingCommunitiesForm));
return promises; return {
trendingResponse: client.listCommunities(trendingCommunitiesForm),
commentsResponse,
postsResponse,
};
} }
get documentTitle(): string { get documentTitle(): string {

View file

@ -12,6 +12,7 @@ import { i18n } from "../../i18next";
import { InitialFetchRequest } from "../../interfaces"; import { InitialFetchRequest } from "../../interfaces";
import { WebSocketService } from "../../services"; import { WebSocketService } from "../../services";
import { import {
WithPromiseKeys,
isBrowser, isBrowser,
relTags, relTags,
setIsoData, setIsoData,
@ -21,6 +22,10 @@ import {
} from "../../utils"; } from "../../utils";
import { HtmlTags } from "../common/html-tags"; import { HtmlTags } from "../common/html-tags";
interface InstancesData {
federatedInstancesResponse: GetFederatedInstancesResponse;
}
interface InstancesState { interface InstancesState {
siteRes: GetSiteResponse; siteRes: GetSiteResponse;
instancesRes?: GetFederatedInstancesResponse; instancesRes?: GetFederatedInstancesResponse;
@ -28,7 +33,7 @@ interface InstancesState {
} }
export class Instances extends Component<any, InstancesState> { export class Instances extends Component<any, InstancesState> {
private isoData = setIsoData(this.context); private isoData = setIsoData<InstancesData>(this.context);
state: InstancesState = { state: InstancesState = {
siteRes: this.isoData.site_res, siteRes: this.isoData.site_res,
loading: true, loading: true,
@ -45,8 +50,7 @@ export class Instances extends Component<any, InstancesState> {
if (this.isoData.path == this.context.router.route.match.url) { if (this.isoData.path == this.context.router.route.match.url) {
this.state = { this.state = {
...this.state, ...this.state,
instancesRes: this.isoData instancesRes: this.isoData.routeData.federatedInstancesResponse,
.routeData[0] as GetFederatedInstancesResponse,
loading: false, loading: false,
}; };
} else { } else {
@ -54,12 +58,14 @@ export class Instances extends Component<any, InstancesState> {
} }
} }
static fetchInitialData(req: InitialFetchRequest): Promise<any>[] { static fetchInitialData({
let promises: Promise<any>[] = []; client,
}: InitialFetchRequest): WithPromiseKeys<InstancesData> {
promises.push(req.client.getFederatedInstances({})); return {
federatedInstancesResponse: client.getFederatedInstances(
return promises; {}
) as Promise<GetFederatedInstancesResponse>,
};
} }
get documentTitle(): string { get documentTitle(): string {

View file

@ -39,6 +39,7 @@ import { WebSocketService } from "../services";
import { import {
Choice, Choice,
QueryParams, QueryParams,
WithPromiseKeys,
amAdmin, amAdmin,
amMod, amMod,
debounce, debounce,
@ -83,6 +84,13 @@ type View =
| AdminPurgePostView | AdminPurgePostView
| AdminPurgeCommentView; | AdminPurgeCommentView;
interface ModlogData {
modlogResponse: GetModlogResponse;
communityResponse?: GetCommunityResponse;
modUserResponse?: GetPersonDetailsResponse;
userResponse?: GetPersonDetailsResponse;
}
interface ModlogType { interface ModlogType {
id: number; id: number;
type_: ModlogActionType; type_: ModlogActionType;
@ -642,7 +650,7 @@ export class Modlog extends Component<
RouteComponentProps<{ communityId?: string }>, RouteComponentProps<{ communityId?: string }>,
ModlogState ModlogState
> { > {
private isoData = setIsoData(this.context); private isoData = setIsoData<ModlogData>(this.context);
private subscription?: Subscription; private subscription?: Subscription;
state: ModlogState = { state: ModlogState = {
@ -667,35 +675,35 @@ export class Modlog extends Component<
// Only fetch the data if coming from another route // Only fetch the data if coming from another route
if (this.isoData.path === this.context.router.route.match.url) { if (this.isoData.path === this.context.router.route.match.url) {
const {
modlogResponse,
communityResponse,
modUserResponse,
userResponse,
} = this.isoData.routeData;
this.state = { this.state = {
...this.state, ...this.state,
res: this.isoData.routeData[0] as GetModlogResponse, res: modlogResponse,
}; };
const communityRes: GetCommunityResponse | undefined =
this.isoData.routeData[1];
// Getting the moderators // Getting the moderators
this.state = { this.state = {
...this.state, ...this.state,
communityMods: communityRes?.moderators, communityMods: communityResponse?.moderators,
}; };
const filteredModRes: GetPersonDetailsResponse | undefined = if (modUserResponse) {
this.isoData.routeData[2];
if (filteredModRes) {
this.state = { this.state = {
...this.state, ...this.state,
modSearchOptions: [personToChoice(filteredModRes.person_view)], modSearchOptions: [personToChoice(modUserResponse.person_view)],
}; };
} }
const filteredUserRes: GetPersonDetailsResponse | undefined = if (userResponse) {
this.isoData.routeData[3];
if (filteredUserRes) {
this.state = { this.state = {
...this.state, ...this.state,
userSearchOptions: [personToChoice(filteredUserRes.person_view)], userSearchOptions: [personToChoice(userResponse.person_view)],
}; };
} }
@ -986,9 +994,10 @@ export class Modlog extends Component<
query: { modId: urlModId, page, userId: urlUserId, actionType }, query: { modId: urlModId, page, userId: urlUserId, actionType },
auth, auth,
site, site,
}: InitialFetchRequest<QueryParams<ModlogProps>>): Promise<any>[] { }: InitialFetchRequest<
QueryParams<ModlogProps>
>): WithPromiseKeys<ModlogData> {
const pathSplit = path.split("/"); const pathSplit = path.split("/");
const promises: Promise<any>[] = [];
const communityId = getIdFromString(pathSplit[2]); const communityId = getIdFromString(pathSplit[2]);
const modId = !site.site_view.local_site.hide_modlog_mod_names const modId = !site.site_view.local_site.hide_modlog_mod_names
? getIdFromString(urlModId) ? getIdFromString(urlModId)
@ -1005,41 +1014,47 @@ export class Modlog extends Component<
auth, auth,
}; };
promises.push(client.getModlog(modlogForm)); let communityResponse: Promise<GetCommunityResponse> | undefined =
undefined;
if (communityId) { if (communityId) {
const communityForm: GetCommunity = { const communityForm: GetCommunity = {
id: communityId, id: communityId,
auth, auth,
}; };
promises.push(client.getCommunity(communityForm));
} else { communityResponse = client.getCommunity(communityForm);
promises.push(Promise.resolve());
} }
let modUserResponse: Promise<GetPersonDetailsResponse> | undefined =
undefined;
if (modId) { if (modId) {
const getPersonForm: GetPersonDetails = { const getPersonForm: GetPersonDetails = {
person_id: modId, person_id: modId,
auth, auth,
}; };
promises.push(client.getPersonDetails(getPersonForm)); modUserResponse = client.getPersonDetails(getPersonForm);
} else {
promises.push(Promise.resolve());
} }
let userResponse: Promise<GetPersonDetailsResponse> | undefined = undefined;
if (userId) { if (userId) {
const getPersonForm: GetPersonDetails = { const getPersonForm: GetPersonDetails = {
person_id: userId, person_id: userId,
auth, auth,
}; };
promises.push(client.getPersonDetails(getPersonForm)); userResponse = client.getPersonDetails(getPersonForm);
} else {
promises.push(Promise.resolve());
} }
return promises; return {
modlogResponse: client.getModlog(modlogForm),
communityResponse,
modUserResponse,
userResponse,
};
} }
parseMessage(msg: any) { parseMessage(msg: any) {

View file

@ -29,6 +29,7 @@ import { i18n } from "../../i18next";
import { CommentViewType, InitialFetchRequest } from "../../interfaces"; import { CommentViewType, InitialFetchRequest } from "../../interfaces";
import { UserService, WebSocketService } from "../../services"; import { UserService, WebSocketService } from "../../services";
import { import {
WithPromiseKeys,
commentsToFlatNodes, commentsToFlatNodes,
createCommentLikeRes, createCommentLikeRes,
editCommentRes, editCommentRes,
@ -69,6 +70,13 @@ enum ReplyEnum {
Mention, Mention,
Message, Message,
} }
interface InboxData {
repliesResponse: GetRepliesResponse;
personMentionsResponse: GetPersonMentionsResponse;
privateMessagesResponse: PrivateMessagesResponse;
}
type ReplyType = { type ReplyType = {
id: number; id: number;
type_: ReplyEnum; type_: ReplyEnum;
@ -90,7 +98,7 @@ interface InboxState {
} }
export class Inbox extends Component<any, InboxState> { export class Inbox extends Component<any, InboxState> {
private isoData = setIsoData(this.context); private isoData = setIsoData<InboxData>(this.context);
private subscription?: Subscription; private subscription?: Subscription;
state: InboxState = { state: InboxState = {
unreadOrAll: UnreadOrAll.Unread, unreadOrAll: UnreadOrAll.Unread,
@ -115,17 +123,18 @@ export class Inbox extends Component<any, InboxState> {
this.subscription = wsSubscribe(this.parseMessage); this.subscription = wsSubscribe(this.parseMessage);
// Only fetch the data if coming from another route // Only fetch the data if coming from another route
if (this.isoData.path == this.context.router.route.match.url) { if (this.isoData.path === this.context.router.route.match.url) {
const {
personMentionsResponse,
privateMessagesResponse,
repliesResponse,
} = this.isoData.routeData;
this.state = { this.state = {
...this.state, ...this.state,
replies: replies: repliesResponse.replies ?? [],
(this.isoData.routeData[0] as GetRepliesResponse).replies || [], mentions: personMentionsResponse.mentions ?? [],
mentions: messages: privateMessagesResponse.private_messages ?? [],
(this.isoData.routeData[1] as GetPersonMentionsResponse).mentions ||
[],
messages:
(this.isoData.routeData[2] as PrivateMessagesResponse)
.private_messages || [],
loading: false, loading: false,
}; };
this.state = { ...this.state, combined: this.buildCombined() }; this.state = { ...this.state, combined: this.buildCombined() };
@ -481,53 +490,51 @@ export class Inbox extends Component<any, InboxState> {
i.refetch(); i.refetch();
} }
static fetchInitialData(req: InitialFetchRequest): Promise<any>[] { static fetchInitialData({
let promises: Promise<any>[] = []; auth,
client,
}: InitialFetchRequest): WithPromiseKeys<InboxData> {
const sort: CommentSortType = "New";
let sort: CommentSortType = "New"; // It can be /u/me, or /username/1
let auth = req.auth; const repliesForm: GetReplies = {
sort,
unread_only: true,
page: 1,
limit: fetchLimit,
auth: auth as string,
};
if (auth) { const personMentionsForm: GetPersonMentions = {
// It can be /u/me, or /username/1 sort,
let repliesForm: GetReplies = { unread_only: true,
sort: "New", page: 1,
unread_only: true, limit: fetchLimit,
page: 1, auth: auth as string,
limit: fetchLimit, };
auth,
};
promises.push(req.client.getReplies(repliesForm));
let personMentionsForm: GetPersonMentions = { const privateMessagesForm: GetPrivateMessages = {
sort, unread_only: true,
unread_only: true, page: 1,
page: 1, limit: fetchLimit,
limit: fetchLimit, auth: auth as string,
auth, };
};
promises.push(req.client.getPersonMentions(personMentionsForm));
let privateMessagesForm: GetPrivateMessages = { return {
unread_only: true, privateMessagesResponse: client.getPrivateMessages(privateMessagesForm),
page: 1, personMentionsResponse: client.getPersonMentions(personMentionsForm),
limit: fetchLimit, repliesResponse: client.getReplies(repliesForm),
auth, };
};
promises.push(req.client.getPrivateMessages(privateMessagesForm));
}
return promises;
} }
refetch() { refetch() {
let sort = this.state.sort; const { sort, page, unreadOrAll } = this.state;
let unread_only = this.state.unreadOrAll == UnreadOrAll.Unread; const unread_only = unreadOrAll === UnreadOrAll.Unread;
let page = this.state.page; const limit = fetchLimit;
let limit = fetchLimit; const auth = myAuth();
let auth = myAuth();
if (auth) { if (auth) {
let repliesForm: GetReplies = { const repliesForm: GetReplies = {
sort, sort,
unread_only, unread_only,
page, page,
@ -536,7 +543,7 @@ export class Inbox extends Component<any, InboxState> {
}; };
WebSocketService.Instance.send(wsClient.getReplies(repliesForm)); WebSocketService.Instance.send(wsClient.getReplies(repliesForm));
let personMentionsForm: GetPersonMentions = { const personMentionsForm: GetPersonMentions = {
sort, sort,
unread_only, unread_only,
page, page,
@ -547,7 +554,7 @@ export class Inbox extends Component<any, InboxState> {
wsClient.getPersonMentions(personMentionsForm) wsClient.getPersonMentions(personMentionsForm)
); );
let privateMessagesForm: GetPrivateMessages = { const privateMessagesForm: GetPrivateMessages = {
unread_only, unread_only,
page, page,
limit, limit,

View file

@ -29,6 +29,7 @@ import { InitialFetchRequest, PersonDetailsView } from "../../interfaces";
import { UserService, WebSocketService } from "../../services"; import { UserService, WebSocketService } from "../../services";
import { import {
QueryParams, QueryParams,
WithPromiseKeys,
canMod, canMod,
capitalizeFirstLetter, capitalizeFirstLetter,
createCommentLikeRes, createCommentLikeRes,
@ -67,6 +68,10 @@ import { CommunityLink } from "../community/community-link";
import { PersonDetails } from "./person-details"; import { PersonDetails } from "./person-details";
import { PersonListing } from "./person-listing"; import { PersonListing } from "./person-listing";
interface ProfileData {
personResponse: GetPersonDetailsResponse;
}
interface ProfileState { interface ProfileState {
personRes?: GetPersonDetailsResponse; personRes?: GetPersonDetailsResponse;
loading: boolean; loading: boolean;
@ -152,7 +157,7 @@ export class Profile extends Component<
RouteComponentProps<{ username: string }>, RouteComponentProps<{ username: string }>,
ProfileState ProfileState
> { > {
private isoData = setIsoData(this.context); private isoData = setIsoData<ProfileData>(this.context);
private subscription?: Subscription; private subscription?: Subscription;
state: ProfileState = { state: ProfileState = {
loading: true, loading: true,
@ -175,7 +180,7 @@ export class Profile extends Component<
if (this.isoData.path === this.context.router.route.match.url) { if (this.isoData.path === this.context.router.route.match.url) {
this.state = { this.state = {
...this.state, ...this.state,
personRes: this.isoData.routeData[0] as GetPersonDetailsResponse, personRes: this.isoData.routeData.personResponse,
loading: false, loading: false,
}; };
} else { } else {
@ -223,7 +228,9 @@ export class Profile extends Component<
path, path,
query: { page, sort, view: urlView }, query: { page, sort, view: urlView },
auth, auth,
}: InitialFetchRequest<QueryParams<ProfileProps>>): Promise<any>[] { }: InitialFetchRequest<
QueryParams<ProfileProps>
>): WithPromiseKeys<ProfileData> {
const pathSplit = path.split("/"); const pathSplit = path.split("/");
const username = pathSplit[2]; const username = pathSplit[2];
@ -238,7 +245,9 @@ export class Profile extends Component<
auth, auth,
}; };
return [client.getPersonDetails(form)]; return {
personResponse: client.getPersonDetails(form),
};
} }
componentDidMount() { componentDidMount() {

View file

@ -13,6 +13,7 @@ import { i18n } from "../../i18next";
import { InitialFetchRequest } from "../../interfaces"; import { InitialFetchRequest } from "../../interfaces";
import { UserService, WebSocketService } from "../../services"; import { UserService, WebSocketService } from "../../services";
import { import {
WithPromiseKeys,
fetchLimit, fetchLimit,
isBrowser, isBrowser,
myAuth, myAuth,
@ -33,6 +34,10 @@ enum UnreadOrAll {
All, All,
} }
interface RegistrationApplicationsData {
listRegistrationApplicationsResponse: ListRegistrationApplicationsResponse;
}
interface RegistrationApplicationsState { interface RegistrationApplicationsState {
listRegistrationApplicationsResponse?: ListRegistrationApplicationsResponse; listRegistrationApplicationsResponse?: ListRegistrationApplicationsResponse;
siteRes: GetSiteResponse; siteRes: GetSiteResponse;
@ -45,7 +50,7 @@ export class RegistrationApplications extends Component<
any, any,
RegistrationApplicationsState RegistrationApplicationsState
> { > {
private isoData = setIsoData(this.context); private isoData = setIsoData<RegistrationApplicationsData>(this.context);
private subscription?: Subscription; private subscription?: Subscription;
state: RegistrationApplicationsState = { state: RegistrationApplicationsState = {
siteRes: this.isoData.site_res, siteRes: this.isoData.site_res,
@ -63,11 +68,11 @@ export class RegistrationApplications extends Component<
this.subscription = wsSubscribe(this.parseMessage); this.subscription = wsSubscribe(this.parseMessage);
// Only fetch the data if coming from another route // Only fetch the data if coming from another route
if (this.isoData.path == this.context.router.route.match.url) { if (this.isoData.path === this.context.router.route.match.url) {
this.state = { this.state = {
...this.state, ...this.state,
listRegistrationApplicationsResponse: this.isoData listRegistrationApplicationsResponse:
.routeData[0] as ListRegistrationApplicationsResponse, this.isoData.routeData.listRegistrationApplicationsResponse,
loading: false, loading: false,
}; };
} else { } else {
@ -192,21 +197,21 @@ export class RegistrationApplications extends Component<
this.refetch(); this.refetch();
} }
static fetchInitialData(req: InitialFetchRequest): Promise<any>[] { static fetchInitialData({
let promises: Promise<any>[] = []; auth,
client,
}: InitialFetchRequest): WithPromiseKeys<RegistrationApplicationsData> {
const form: ListRegistrationApplications = {
unread_only: true,
page: 1,
limit: fetchLimit,
auth: auth as string,
};
let auth = req.auth; return {
if (auth) { listRegistrationApplicationsResponse:
let form: ListRegistrationApplications = { client.listRegistrationApplications(form),
unread_only: true, };
page: 1,
limit: fetchLimit,
auth,
};
promises.push(req.client.listRegistrationApplications(form));
}
return promises;
} }
refetch() { refetch() {

View file

@ -22,6 +22,7 @@ import { i18n } from "../../i18next";
import { InitialFetchRequest } from "../../interfaces"; import { InitialFetchRequest } from "../../interfaces";
import { UserService, WebSocketService } from "../../services"; import { UserService, WebSocketService } from "../../services";
import { import {
WithPromiseKeys,
amAdmin, amAdmin,
fetchLimit, fetchLimit,
isBrowser, isBrowser,
@ -60,6 +61,12 @@ enum MessageEnum {
PrivateMessageReport, PrivateMessageReport,
} }
interface ReportsData {
commentReportsResponse: ListCommentReportsResponse;
postReportsResponse: ListPostReportsResponse;
privateMessageReportsResponse?: ListPrivateMessageReportsResponse;
}
type ItemType = { type ItemType = {
id: number; id: number;
type_: MessageEnum; type_: MessageEnum;
@ -80,7 +87,7 @@ interface ReportsState {
} }
export class Reports extends Component<any, ReportsState> { export class Reports extends Component<any, ReportsState> {
private isoData = setIsoData(this.context); private isoData = setIsoData<ReportsData>(this.context);
private subscription?: Subscription; private subscription?: Subscription;
state: ReportsState = { state: ReportsState = {
unreadOrAll: UnreadOrAll.Unread, unreadOrAll: UnreadOrAll.Unread,
@ -100,21 +107,20 @@ export class Reports extends Component<any, ReportsState> {
this.subscription = wsSubscribe(this.parseMessage); this.subscription = wsSubscribe(this.parseMessage);
// Only fetch the data if coming from another route // Only fetch the data if coming from another route
if (this.isoData.path == this.context.router.route.match.url) { if (this.isoData.path === this.context.router.route.match.url) {
const {
commentReportsResponse,
postReportsResponse,
privateMessageReportsResponse,
} = this.isoData.routeData;
this.state = { this.state = {
...this.state, ...this.state,
listCommentReportsResponse: this.isoData listCommentReportsResponse: commentReportsResponse,
.routeData[0] as ListCommentReportsResponse, listPostReportsResponse: postReportsResponse,
listPostReportsResponse: this.isoData listPrivateMessageReportsResponse: privateMessageReportsResponse,
.routeData[1] as ListPostReportsResponse,
}; };
if (amAdmin()) {
this.state = {
...this.state,
listPrivateMessageReportsResponse: this.isoData
.routeData[2] as ListPrivateMessageReportsResponse,
};
}
this.state = { this.state = {
...this.state, ...this.state,
combined: this.buildCombined(), combined: this.buildCombined(),
@ -432,73 +438,78 @@ export class Reports extends Component<any, ReportsState> {
i.refetch(); i.refetch();
} }
static fetchInitialData(req: InitialFetchRequest): Promise<any>[] { static fetchInitialData({
let promises: Promise<any>[] = []; auth,
client,
}: InitialFetchRequest): WithPromiseKeys<ReportsData> {
const unresolved_only = true;
const page = 1;
const limit = fetchLimit;
let unresolved_only = true; const commentReportsForm: ListCommentReports = {
let page = 1; unresolved_only,
let limit = fetchLimit; page,
let auth = req.auth; limit,
auth: auth as string,
};
if (auth) { const postReportsForm: ListPostReports = {
let commentReportsForm: ListCommentReports = { unresolved_only,
page,
limit,
auth: auth as string,
};
const data: WithPromiseKeys<ReportsData> = {
commentReportsResponse: client.listCommentReports(commentReportsForm),
postReportsResponse: client.listPostReports(postReportsForm),
};
if (amAdmin()) {
const privateMessageReportsForm: ListPrivateMessageReports = {
unresolved_only, unresolved_only,
page, page,
limit, limit,
auth, auth: auth as string,
}; };
promises.push(req.client.listCommentReports(commentReportsForm));
let postReportsForm: ListPostReports = { data.privateMessageReportsResponse = client.listPrivateMessageReports(
unresolved_only, privateMessageReportsForm
page, );
limit,
auth,
};
promises.push(req.client.listPostReports(postReportsForm));
if (amAdmin()) {
let privateMessageReportsForm: ListPrivateMessageReports = {
unresolved_only,
page,
limit,
auth,
};
promises.push(
req.client.listPrivateMessageReports(privateMessageReportsForm)
);
}
} }
return promises; return data;
} }
refetch() { refetch() {
let unresolved_only = this.state.unreadOrAll == UnreadOrAll.Unread; const unresolved_only = this.state.unreadOrAll === UnreadOrAll.Unread;
let page = this.state.page; const page = this.state.page;
let limit = fetchLimit; const limit = fetchLimit;
let auth = myAuth(); const auth = myAuth();
if (auth) { if (auth) {
let commentReportsForm: ListCommentReports = { const commentReportsForm: ListCommentReports = {
unresolved_only, unresolved_only,
page, page,
limit, limit,
auth, auth,
}; };
WebSocketService.Instance.send( WebSocketService.Instance.send(
wsClient.listCommentReports(commentReportsForm) wsClient.listCommentReports(commentReportsForm)
); );
let postReportsForm: ListPostReports = { const postReportsForm: ListPostReports = {
unresolved_only, unresolved_only,
page, page,
limit, limit,
auth, auth,
}; };
WebSocketService.Instance.send(wsClient.listPostReports(postReportsForm)); WebSocketService.Instance.send(wsClient.listPostReports(postReportsForm));
if (amAdmin()) { if (amAdmin()) {
let privateMessageReportsForm: ListPrivateMessageReports = { const privateMessageReportsForm: ListPrivateMessageReports = {
unresolved_only, unresolved_only,
page, page,
limit, limit,

View file

@ -16,6 +16,7 @@ import { WebSocketService } from "../../services";
import { import {
Choice, Choice,
QueryParams, QueryParams,
WithPromiseKeys,
enableDownvotes, enableDownvotes,
enableNsfw, enableNsfw,
getIdFromString, getIdFromString,
@ -36,6 +37,10 @@ export interface CreatePostProps {
communityId?: number; communityId?: number;
} }
interface CreatePostData {
communityResponse?: GetCommunityResponse;
}
function getCreatePostQueryParams() { function getCreatePostQueryParams() {
return getQueryParams<CreatePostProps>({ return getQueryParams<CreatePostProps>({
communityId: getIdFromString, communityId: getIdFromString,
@ -52,7 +57,7 @@ export class CreatePost extends Component<
RouteComponentProps<Record<string, never>>, RouteComponentProps<Record<string, never>>,
CreatePostState CreatePostState
> { > {
private isoData = setIsoData(this.context); private isoData = setIsoData<CreatePostData>(this.context);
private subscription?: Subscription; private subscription?: Subscription;
state: CreatePostState = { state: CreatePostState = {
siteRes: this.isoData.site_res, siteRes: this.isoData.site_res,
@ -71,14 +76,12 @@ export class CreatePost extends Component<
// Only fetch the data if coming from another route // Only fetch the data if coming from another route
if (this.isoData.path === this.context.router.route.match.url) { if (this.isoData.path === this.context.router.route.match.url) {
const communityRes = this.isoData.routeData[0] as const { communityResponse } = this.isoData.routeData;
| GetCommunityResponse
| undefined;
if (communityRes) { if (communityResponse) {
const communityChoice: Choice = { const communityChoice: Choice = {
label: communityRes.community_view.community.name, label: communityResponse.community_view.community.name,
value: communityRes.community_view.community.id.toString(), value: communityResponse.community_view.community.id.toString(),
}; };
this.state = { this.state = {
@ -206,8 +209,10 @@ export class CreatePost extends Component<
client, client,
query: { communityId }, query: { communityId },
auth, auth,
}: InitialFetchRequest<QueryParams<CreatePostProps>>): Promise<any>[] { }: InitialFetchRequest<
const promises: Promise<any>[] = []; QueryParams<CreatePostProps>
>): WithPromiseKeys<CreatePostData> {
const data: WithPromiseKeys<CreatePostData> = {};
if (communityId) { if (communityId) {
const form: GetCommunity = { const form: GetCommunity = {
@ -215,12 +220,10 @@ export class CreatePost extends Component<
id: getIdFromString(communityId), id: getIdFromString(communityId),
}; };
promises.push(client.getCommunity(form)); data.communityResponse = client.getCommunity(form);
} else {
promises.push(Promise.resolve());
} }
return promises; return data;
} }
parseMessage(msg: any) { parseMessage(msg: any) {

View file

@ -60,6 +60,7 @@ import {
toast, toast,
trendingFetchLimit, trendingFetchLimit,
updatePersonBlock, updatePersonBlock,
WithPromiseKeys,
wsClient, wsClient,
wsSubscribe, wsSubscribe,
} from "../../utils"; } from "../../utils";
@ -72,6 +73,11 @@ import { PostListing } from "./post-listing";
const commentsShownInterval = 15; const commentsShownInterval = 15;
interface PostData {
postResponse: GetPostResponse;
commentsResponse: GetCommentsResponse;
}
interface PostState { interface PostState {
postId?: number; postId?: number;
commentId?: number; commentId?: number;
@ -91,7 +97,7 @@ interface PostState {
export class Post extends Component<any, PostState> { export class Post extends Component<any, PostState> {
private subscription?: Subscription; private subscription?: Subscription;
private isoData = setIsoData(this.context); private isoData = setIsoData<PostData>(this.context);
private commentScrollDebounced: () => void; private commentScrollDebounced: () => void;
state: PostState = { state: PostState = {
postId: getIdFromProps(this.props), postId: getIdFromProps(this.props),
@ -115,11 +121,13 @@ export class Post extends Component<any, PostState> {
this.state = { ...this.state, commentSectionRef: createRef() }; this.state = { ...this.state, commentSectionRef: createRef() };
// Only fetch the data if coming from another route // Only fetch the data if coming from another route
if (this.isoData.path == this.context.router.route.match.url) { if (this.isoData.path === this.context.router.route.match.url) {
const { commentsResponse, postResponse } = this.isoData.routeData;
this.state = { this.state = {
...this.state, ...this.state,
postRes: this.isoData.routeData[0] as GetPostResponse, postRes: postResponse,
commentsRes: this.isoData.routeData[1] as GetCommentsResponse, commentsRes: commentsResponse,
}; };
if (this.state.commentsRes) { if (this.state.commentsRes) {
@ -197,19 +205,18 @@ export class Post extends Component<any, PostState> {
} }
} }
static fetchInitialData(req: InitialFetchRequest): Promise<any>[] { static fetchInitialData(req: InitialFetchRequest): WithPromiseKeys<PostData> {
let pathSplit = req.path.split("/"); const pathSplit = req.path.split("/");
let promises: Promise<any>[] = [];
let pathType = pathSplit.at(1); const pathType = pathSplit.at(1);
let id = pathSplit.at(2) ? Number(pathSplit.at(2)) : undefined; const id = pathSplit.at(2) ? Number(pathSplit.at(2)) : undefined;
let auth = req.auth; const auth = req.auth;
let postForm: GetPost = { const postForm: GetPost = {
auth, auth,
}; };
let commentsForm: GetComments = { const commentsForm: GetComments = {
max_depth: commentTreeMaxDepth, max_depth: commentTreeMaxDepth,
sort: "Hot", sort: "Hot",
type_: "All", type_: "All",
@ -218,7 +225,7 @@ export class Post extends Component<any, PostState> {
}; };
// Set the correct id based on the path type // Set the correct id based on the path type
if (pathType == "post") { if (pathType === "post") {
postForm.id = id; postForm.id = id;
commentsForm.post_id = id; commentsForm.post_id = id;
} else { } else {
@ -226,10 +233,10 @@ export class Post extends Component<any, PostState> {
commentsForm.parent_id = id; commentsForm.parent_id = id;
} }
promises.push(req.client.getPost(postForm)); return {
promises.push(req.client.getComments(commentsForm)); postResponse: req.client.getPost(postForm),
commentsResponse: req.client.getComments(commentsForm),
return promises; };
} }
componentWillUnmount() { componentWillUnmount() {

View file

@ -12,6 +12,7 @@ import { i18n } from "../../i18next";
import { InitialFetchRequest } from "../../interfaces"; import { InitialFetchRequest } from "../../interfaces";
import { WebSocketService } from "../../services"; import { WebSocketService } from "../../services";
import { import {
WithPromiseKeys,
getRecipientIdFromProps, getRecipientIdFromProps,
isBrowser, isBrowser,
myAuth, myAuth,
@ -24,6 +25,10 @@ import { HtmlTags } from "../common/html-tags";
import { Spinner } from "../common/icon"; import { Spinner } from "../common/icon";
import { PrivateMessageForm } from "./private-message-form"; import { PrivateMessageForm } from "./private-message-form";
interface CreatePrivateMessageData {
recipientDetailsResponse: GetPersonDetailsResponse;
}
interface CreatePrivateMessageState { interface CreatePrivateMessageState {
siteRes: GetSiteResponse; siteRes: GetSiteResponse;
recipientDetailsRes?: GetPersonDetailsResponse; recipientDetailsRes?: GetPersonDetailsResponse;
@ -35,7 +40,7 @@ export class CreatePrivateMessage extends Component<
any, any,
CreatePrivateMessageState CreatePrivateMessageState
> { > {
private isoData = setIsoData(this.context); private isoData = setIsoData<CreatePrivateMessageData>(this.context);
private subscription?: Subscription; private subscription?: Subscription;
state: CreatePrivateMessageState = { state: CreatePrivateMessageState = {
siteRes: this.isoData.site_res, siteRes: this.isoData.site_res,
@ -52,11 +57,10 @@ export class CreatePrivateMessage extends Component<
this.subscription = wsSubscribe(this.parseMessage); this.subscription = wsSubscribe(this.parseMessage);
// Only fetch the data if coming from another route // Only fetch the data if coming from another route
if (this.isoData.path == this.context.router.route.match.url) { if (this.isoData.path === this.context.router.route.match.url) {
this.state = { this.state = {
...this.state, ...this.state,
recipientDetailsRes: this.isoData recipientDetailsRes: this.isoData.routeData.recipientDetailsResponse,
.routeData[0] as GetPersonDetailsResponse,
loading: false, loading: false,
}; };
} else { } else {
@ -74,15 +78,21 @@ export class CreatePrivateMessage extends Component<
WebSocketService.Instance.send(wsClient.getPersonDetails(form)); WebSocketService.Instance.send(wsClient.getPersonDetails(form));
} }
static fetchInitialData(req: InitialFetchRequest): Promise<any>[] { static fetchInitialData(
let person_id = Number(req.path.split("/").pop()); req: InitialFetchRequest
let form: GetPersonDetails = { ): WithPromiseKeys<CreatePrivateMessageData> {
const person_id = Number(req.path.split("/").pop());
const form: GetPersonDetails = {
person_id, person_id,
sort: "New", sort: "New",
saved_only: false, saved_only: false,
auth: req.auth, auth: req.auth,
}; };
return [req.client.getPersonDetails(form)];
return {
recipientDetailsResponse: req.client.getPersonDetails(form),
};
} }
get documentTitle(): string { get documentTitle(): string {

View file

@ -32,6 +32,7 @@ import { WebSocketService } from "../services";
import { import {
Choice, Choice,
QueryParams, QueryParams,
WithPromiseKeys,
capitalizeFirstLetter, capitalizeFirstLetter,
commentsToFlatNodes, commentsToFlatNodes,
communityToChoice, communityToChoice,
@ -80,6 +81,14 @@ interface SearchProps {
page: number; page: number;
} }
interface SearchData {
communityResponse?: GetCommunityResponse;
listCommunitiesResponse?: ListCommunitiesResponse;
creatorDetailsResponse?: GetPersonDetailsResponse;
searchResponse?: SearchResponse;
resolveObjectResponse?: ResolveObjectResponse;
}
type FilterType = "creator" | "community"; type FilterType = "creator" | "community";
interface SearchState { interface SearchState {
@ -237,7 +246,7 @@ function getListing(
} }
export class Search extends Component<any, SearchState> { export class Search extends Component<any, SearchState> {
private isoData = setIsoData(this.context); private isoData = setIsoData<SearchData>(this.context);
private subscription?: Subscription; private subscription?: Subscription;
state: SearchState = { state: SearchState = {
searchLoading: false, searchLoading: false,
@ -271,45 +280,44 @@ export class Search extends Component<any, SearchState> {
// Only fetch the data if coming from another route // Only fetch the data if coming from another route
if (this.isoData.path === this.context.router.route.match.url) { if (this.isoData.path === this.context.router.route.match.url) {
const communityRes = this.isoData.routeData[0] as const {
| GetCommunityResponse communityResponse,
| undefined; creatorDetailsResponse,
const communitiesRes = this.isoData.routeData[1] as listCommunitiesResponse,
| ListCommunitiesResponse resolveObjectResponse,
| undefined; searchResponse,
} = this.isoData.routeData;
// This can be single or multiple communities given // This can be single or multiple communities given
if (communitiesRes) { if (listCommunitiesResponse) {
this.state = { this.state = {
...this.state, ...this.state,
communities: communitiesRes.communities, communities: listCommunitiesResponse.communities,
}; };
} }
if (communityRes) { if (communityResponse) {
this.state = { this.state = {
...this.state, ...this.state,
communities: [communityRes.community_view], communities: [communityResponse.community_view],
communitySearchOptions: [ communitySearchOptions: [
communityToChoice(communityRes.community_view), communityToChoice(communityResponse.community_view),
], ],
}; };
} }
const creatorRes = this.isoData.routeData[2] as GetPersonDetailsResponse;
this.state = { this.state = {
...this.state, ...this.state,
creatorDetails: creatorRes, creatorDetails: creatorDetailsResponse,
creatorSearchOptions: creatorRes creatorSearchOptions: creatorDetailsResponse
? [personToChoice(creatorRes.person_view)] ? [personToChoice(creatorDetailsResponse.person_view)]
: [], : [],
}; };
if (q !== "") { if (q !== "") {
this.state = { this.state = {
...this.state, ...this.state,
searchResponse: this.isoData.routeData[3] as SearchResponse, searchResponse,
resolveObjectResponse: this.isoData resolveObjectResponse,
.routeData[4] as ResolveObjectResponse,
searchLoading: false, searchLoading: false,
}; };
} else { } else {
@ -342,17 +350,21 @@ export class Search extends Component<any, SearchState> {
client, client,
auth, auth,
query: { communityId, creatorId, q, type, sort, listingType, page }, query: { communityId, creatorId, q, type, sort, listingType, page },
}: InitialFetchRequest<QueryParams<SearchProps>>): Promise<any>[] { }: InitialFetchRequest<
const promises: Promise<any>[] = []; QueryParams<SearchProps>
>): WithPromiseKeys<SearchData> {
const community_id = getIdFromString(communityId); const community_id = getIdFromString(communityId);
let communityResponse: Promise<GetCommunityResponse> | undefined =
undefined;
let listCommunitiesResponse: Promise<ListCommunitiesResponse> | undefined =
undefined;
if (community_id) { if (community_id) {
const getCommunityForm: GetCommunity = { const getCommunityForm: GetCommunity = {
id: community_id, id: community_id,
auth, auth,
}; };
promises.push(client.getCommunity(getCommunityForm));
promises.push(Promise.resolve()); communityResponse = client.getCommunity(getCommunityForm);
} else { } else {
const listCommunitiesForm: ListCommunities = { const listCommunitiesForm: ListCommunities = {
type_: defaultListingType, type_: defaultListingType,
@ -360,23 +372,29 @@ export class Search extends Component<any, SearchState> {
limit: fetchLimit, limit: fetchLimit,
auth, auth,
}; };
promises.push(Promise.resolve());
promises.push(client.listCommunities(listCommunitiesForm)); listCommunitiesResponse = client.listCommunities(listCommunitiesForm);
} }
const creator_id = getIdFromString(creatorId); const creator_id = getIdFromString(creatorId);
let creatorDetailsResponse: Promise<GetPersonDetailsResponse> | undefined =
undefined;
if (creator_id) { if (creator_id) {
const getCreatorForm: GetPersonDetails = { const getCreatorForm: GetPersonDetails = {
person_id: creator_id, person_id: creator_id,
auth, auth,
}; };
promises.push(client.getPersonDetails(getCreatorForm));
} else { creatorDetailsResponse = client.getPersonDetails(getCreatorForm);
promises.push(Promise.resolve());
} }
const query = getSearchQueryFromQuery(q); const query = getSearchQueryFromQuery(q);
let searchResponse: Promise<SearchResponse> | undefined = undefined;
let resolveObjectResponse:
| Promise<ResolveObjectResponse | undefined>
| undefined = undefined;
if (query) { if (query) {
const form: SearchForm = { const form: SearchForm = {
q: query, q: query,
@ -391,21 +409,26 @@ export class Search extends Component<any, SearchState> {
}; };
if (query !== "") { if (query !== "") {
promises.push(client.search(form)); searchResponse = client.search(form);
if (auth) { if (auth) {
const resolveObjectForm: ResolveObject = { const resolveObjectForm: ResolveObject = {
q: query, q: query,
auth, auth,
}; };
promises.push(client.resolveObject(resolveObjectForm)); resolveObjectResponse = client
.resolveObject(resolveObjectForm)
.catch(() => undefined);
} }
} else {
promises.push(Promise.resolve());
promises.push(Promise.resolve());
} }
} }
return promises; return {
communityResponse,
creatorDetailsResponse,
listCommunitiesResponse,
resolveObjectResponse,
searchResponse,
};
} }
get documentTitle(): string { get documentTitle(): string {

View file

@ -5,15 +5,15 @@ import { ErrorPageData } from "./utils";
/** /**
* This contains serialized data, it needs to be deserialized before use. * This contains serialized data, it needs to be deserialized before use.
*/ */
export interface IsoData { export interface IsoData<T extends object = any> {
path: string; path: string;
routeData: any[]; routeData: T;
site_res: GetSiteResponse; site_res: GetSiteResponse;
errorPageData?: ErrorPageData; errorPageData?: ErrorPageData;
} }
export type IsoDataOptionalSite = Partial<IsoData> & export type IsoDataOptionalSite<T extends object = any> = Partial<IsoData<T>> &
Pick<IsoData, Exclude<keyof IsoData, "site_res">>; Pick<IsoData<T>, Exclude<keyof IsoData<T>, "site_res">>;
export interface ILemmyConfig { export interface ILemmyConfig {
wsHost?: string; wsHost?: string;

View file

@ -22,13 +22,14 @@ import { Post } from "./components/post/post";
import { CreatePrivateMessage } from "./components/private_message/create-private-message"; import { CreatePrivateMessage } from "./components/private_message/create-private-message";
import { Search } from "./components/search"; import { Search } from "./components/search";
import { InitialFetchRequest } from "./interfaces"; import { InitialFetchRequest } from "./interfaces";
import { WithPromiseKeys } from "./utils";
interface IRoutePropsWithFetch extends IRouteProps { interface IRoutePropsWithFetch<T extends object> extends IRouteProps {
// TODO Make sure this one is good. // TODO Make sure this one is good.
fetchInitialData?(req: InitialFetchRequest): Promise<any>[]; fetchInitialData?(req: InitialFetchRequest): WithPromiseKeys<T>;
} }
export const routes: IRoutePropsWithFetch[] = [ export const routes: IRoutePropsWithFetch<Record<string, any>>[] = [
{ {
path: `/`, path: `/`,
component: Home, component: Home,

View file

@ -1262,7 +1262,7 @@ export function isBrowser() {
return typeof window !== "undefined"; return typeof window !== "undefined";
} }
export function setIsoData(context: any): IsoData { export function setIsoData<T extends object>(context: any): IsoData<T> {
// If its the browser, you need to deserialize the data from the window // If its the browser, you need to deserialize the data from the window
if (isBrowser()) { if (isBrowser()) {
return window.isoData; return window.isoData;
@ -1557,6 +1557,10 @@ export type QueryParams<T extends Record<string, any>> = {
[key in keyof T]?: string; [key in keyof T]?: string;
}; };
export type WithPromiseKeys<T extends object> = {
[K in keyof T]: Promise<T[K]>;
};
export function getQueryParams<T extends Record<string, any>>(processors: { export function getQueryParams<T extends Record<string, any>>(processors: {
[K in keyof T]: (param: string) => T[K]; [K in keyof T]: (param: string) => T[K];
}): T { }): T {