import { ReactNode, useEffect } from "react"; import { ActionCreatorWithPayload, configureStore } from "@reduxjs/toolkit"; import postSlice from "./features/post/postSlice"; import { Provider, TypedUseSelectorHook, useDispatch, useSelector, } from "react-redux"; import authSlice from "./features/auth/authSlice"; import commentSlice from "./features/comment/commentSlice"; import communitySlice, { getFavoriteCommunities, } from "./features/community/communitySlice"; import userSlice from "./features/user/userSlice"; import inboxSlice from "./features/inbox/inboxSlice"; import settingsSlice, { fetchSettingsFromDatabase, getBlurNsfw, getDefaultFeed, getFilteredKeywords, getFilteredWebsites, } from "./features/settings/settingsSlice"; import gestureSlice, { fetchGesturesFromDatabase, } from "./features/settings/gestures/gestureSlice"; import appIconSlice, { fetchAppIcon, } from "./features/settings/app-icon/appIconSlice"; import instancesSlice, { getInstances, } from "./features/instances/instancesSlice"; import resolveSlice from "./features/resolve/resolveSlice"; import biometricSlice, { initializeBiometricSliceDataIfNeeded, } from "./features/settings/biometric/biometricSlice"; import migrationSlice from "./features/migrate/migrationSlice"; import modSlice from "./features/moderation/modSlice"; import imageSlice from "./features/post/inFeed/large/imageSlice"; import feedSortSlice from "./features/feed/sort/feedSortSlice"; import siteSlice from "./features/auth/siteSlice"; import { handleSelector } from "./features/auth/authSelectors"; import pickJoinServerSlice from "./features/auth/login/pickJoinServer/pickJoinServerSlice"; import joinSlice from "./features/auth/login/join/joinSlice"; import networkSlice from "./core/listeners/network/networkSlice"; import spoilerSlice from "./features/shared/markdown/components/spoiler/spoilerSlice"; import deepLinkReadySlice from "./features/community/list/deepLinkReadySlice"; import redgifsSlice from "./features/media/external/redgifs/redgifsSlice"; import uploadImageSlice from "./features/shared/markdown/editing/uploadImageSlice"; import postAppearanceSlice from "./features/post/appearance/appearanceSlice"; import thumbnailSlice from "./features/post/link/thumbnail/thumbnailSlice"; const store = configureStore({ reducer: { post: postSlice, comment: commentSlice, auth: authSlice, site: siteSlice, community: communitySlice, user: userSlice, inbox: inboxSlice, settings: settingsSlice, gesture: gestureSlice, appIcon: appIconSlice, instances: instancesSlice, resolve: resolveSlice, biometric: biometricSlice, mod: modSlice, image: imageSlice, feedSort: feedSortSlice, pickJoinServer: pickJoinServerSlice, join: joinSlice, network: networkSlice, migration: migrationSlice, spoiler: spoilerSlice, deepLinkReady: deepLinkReadySlice, redgifs: redgifsSlice, uploadImage: uploadImageSlice, postAppearance: postAppearanceSlice, thumbnail: thumbnailSlice, }, }); export type RootState = ReturnType; export type AppDispatch = typeof store.dispatch; export const useAppDispatch: () => AppDispatch = useDispatch; export const useAppSelector: TypedUseSelectorHook = useSelector; export type Dispatchable = | ((val: T) => (dispatch: AppDispatch, getState: () => RootState) => void) | ActionCreatorWithPayload; export default store; // "uninitialized" so that "uninitialized" -> undefined (logged out) triggers change let lastActiveHandle: string | undefined = "uninitialized"; const activeHandleChange = () => { const state = store.getState(); const handle = handleSelector(state); if (handle === lastActiveHandle) return; lastActiveHandle = handle; store.dispatch(getFavoriteCommunities()); store.dispatch(getBlurNsfw()); store.dispatch(getFilteredKeywords()); store.dispatch(getFilteredWebsites()); store.dispatch(getDefaultFeed()); store.dispatch(getInstances()); }; export function StoreProvider({ children }: { children: ReactNode }) { useEffect(() => { (async () => { try { // Load initial settings from DB into the store await Promise.all([ store.dispatch(fetchSettingsFromDatabase()), store.dispatch(fetchGesturesFromDatabase()), store.dispatch(fetchAppIcon()), store.dispatch(initializeBiometricSliceDataIfNeeded()), ]); } finally { // Initialize with current active handle activeHandleChange(); // Subscribe to actions to handle handle changes, this can be used to react to other changes as well // to coordinate side effects between slices. store.subscribe(activeHandleChange); } })(); }, []); return {children}; }