Files
HKSingleParty/99_references/voyager-main/src/features/auth/siteSlice.ts
2025-05-28 09:55:51 +08:00

157 lines
4.2 KiB
TypeScript

import { PayloadAction, createSelector, createSlice } from "@reduxjs/toolkit";
import { GetSiteResponse } from "lemmy-js-client";
import { AppDispatch, RootState } from "../../store";
import {
clientSelector,
userHandleSelector,
handleSelector,
} from "./authSelectors";
import { getRemoteHandle } from "../../helpers/lemmy";
import { customBackOff } from "../../services/lemmy";
interface SiteState {
failedAttempt: number;
loading: boolean;
response: GetSiteResponse | undefined;
}
const initialState: SiteState = {
failedAttempt: 0,
loading: false,
response: undefined,
};
export const siteSlice = createSlice({
name: "site",
initialState,
reducers: {
loadingSite(state) {
state.loading = true;
},
failedSite(state) {
state.failedAttempt++;
state.loading = false;
},
receivedSite(state, action: PayloadAction<GetSiteResponse>) {
state.response = action.payload;
state.loading = false;
state.failedAttempt = 0;
},
resetSite() {
return initialState;
},
},
});
// Action creators are generated for each case reducer function
export const { loadingSite, failedSite, receivedSite, resetSite } =
siteSlice.actions;
export default siteSlice.reducer;
export const isAdminSelector = (state: RootState) =>
state.site.response?.my_user?.local_user_view.local_user.admin;
export const isDownvoteEnabledSelector = (state: RootState) =>
state.site.response?.site_view.local_site.enable_downvotes !== false;
export const localUserSelector = (state: RootState) =>
state.site.response?.my_user?.local_user_view.local_user;
export const userPersonSelector = (state: RootState) =>
state.site.response?.my_user?.local_user_view?.person;
export const lemmyVersionSelector = (state: RootState) =>
state.site.response?.version;
export const followIdsSelector = createSelector(
[(state: RootState) => state.site.response?.my_user?.follows],
(follows) => (follows ?? []).map((follow) => follow.community.id),
);
export const moderatesSelector = (state: RootState) =>
state.site.response?.my_user?.moderates;
/**
* Used to determine if request is stale (for other lemmy account and/or instance)
*/
const siteReqIdSelector = createSelector(
[(state: RootState) => state.auth.connectedInstance, handleSelector],
(profile, connectedInstance) =>
connectedInstance ? getSiteReqId(connectedInstance, profile) : "",
);
export const getSiteIfNeeded =
() => async (dispatch: AppDispatch, getState: () => RootState) => {
if (getState().site.response) return;
if (getState().site.loading) return;
dispatch(getSite());
};
export const getSite =
() => async (dispatch: AppDispatch, getState: () => RootState) => {
const reqId = siteReqIdSelector(getState());
let site;
dispatch(loadingSite());
try {
site = await clientSelector(getState()).getSite();
} catch (error) {
dispatch(failedSite());
(async () => {
await customBackOff(getState().site.failedAttempt);
// Site or user changed before site response resolved
if (reqId !== siteReqIdSelector(getState())) return;
dispatch(getSite());
})();
throw error;
}
// Site or user changed before site response resolved
if (reqId !== siteReqIdSelector(getState())) return;
dispatch(receivedSite(site));
};
export const showNsfw =
(show: boolean) =>
async (dispatch: AppDispatch, getState: () => RootState) => {
// https://github.com/LemmyNet/lemmy/issues/3565
const person = getState().site.response?.my_user?.local_user_view.person;
if (!person || userHandleSelector(getState()) !== getRemoteHandle(person))
throw new Error("user mismatch");
await clientSelector(getState())?.saveUserSettings({
avatar: person?.avatar || "",
show_nsfw: show,
});
await dispatch(getSite());
};
export const blockInstance =
(block: boolean, id: number) =>
async (dispatch: AppDispatch, getState: () => RootState) => {
if (!id) return;
await clientSelector(getState())?.blockInstance({
instance_id: id,
block,
});
await dispatch(getSite());
};
function getSiteReqId(instance: string, handle: string | undefined) {
if (!handle) return instance;
return `${instance}-${handle}`;
}