mirror of
https://github.com/Athou/commafeed.git
synced 2026-03-21 21:37:29 +00:00
use typed createAsyncThunk
This commit is contained in:
@@ -1,8 +1,8 @@
|
||||
import { createAsyncThunk, createSlice, PayloadAction } from "@reduxjs/toolkit"
|
||||
import { createSlice, PayloadAction } from "@reduxjs/toolkit"
|
||||
import { client } from "app/client"
|
||||
import { Constants } from "app/constants"
|
||||
import { RootState } from "app/store"
|
||||
import { Entries, Entry, MarkRequest, TagRequest } from "app/types"
|
||||
import { createAppAsyncThunk, RootState } from "app/store"
|
||||
import { Entry, MarkRequest, TagRequest } from "app/types"
|
||||
import { scrollToWithCallback } from "app/utils"
|
||||
import { flushSync } from "react-dom"
|
||||
// eslint-disable-next-line import/no-cycle
|
||||
@@ -47,27 +47,24 @@ const initialState: EntriesState = {
|
||||
|
||||
const getEndpoint = (sourceType: EntrySourceType) =>
|
||||
sourceType === "category" || sourceType === "tag" ? client.category.getEntries : client.feed.getEntries
|
||||
export const loadEntries = createAsyncThunk<
|
||||
Entries,
|
||||
{ source: EntrySource; clearSearch: boolean },
|
||||
{
|
||||
state: RootState
|
||||
}
|
||||
>("entries/load", async (arg, thunkApi) => {
|
||||
if (arg.clearSearch) thunkApi.dispatch(setSearch(""))
|
||||
export const loadEntries = createAppAsyncThunk(
|
||||
"entries/load",
|
||||
async (
|
||||
arg: {
|
||||
source: EntrySource
|
||||
clearSearch: boolean
|
||||
},
|
||||
thunkApi
|
||||
) => {
|
||||
if (arg.clearSearch) thunkApi.dispatch(setSearch(""))
|
||||
|
||||
const state = thunkApi.getState()
|
||||
const endpoint = getEndpoint(arg.source.type)
|
||||
const result = await endpoint(buildGetEntriesPaginatedRequest(state, arg.source, 0))
|
||||
return result.data
|
||||
})
|
||||
export const loadMoreEntries = createAsyncThunk<
|
||||
Entries,
|
||||
void,
|
||||
{
|
||||
state: RootState
|
||||
const state = thunkApi.getState()
|
||||
const endpoint = getEndpoint(arg.source.type)
|
||||
const result = await endpoint(buildGetEntriesPaginatedRequest(state, arg.source, 0))
|
||||
return result.data
|
||||
}
|
||||
>("entries/loadMore", async (_, thunkApi) => {
|
||||
)
|
||||
export const loadMoreEntries = createAppAsyncThunk("entries/loadMore", async (_, thunkApi) => {
|
||||
const state = thunkApi.getState()
|
||||
const { source } = state.entries
|
||||
const offset =
|
||||
@@ -85,22 +82,16 @@ const buildGetEntriesPaginatedRequest = (state: RootState, source: EntrySource,
|
||||
tag: source.type === "tag" ? source.id : undefined,
|
||||
keywords: state.entries.search,
|
||||
})
|
||||
export const reloadEntries = createAsyncThunk<
|
||||
void,
|
||||
void,
|
||||
{
|
||||
state: RootState
|
||||
}
|
||||
>("entries/reload", async (arg, thunkApi) => {
|
||||
export const reloadEntries = createAppAsyncThunk("entries/reload", async (arg, thunkApi) => {
|
||||
const state = thunkApi.getState()
|
||||
thunkApi.dispatch(loadEntries({ source: state.entries.source, clearSearch: false }))
|
||||
})
|
||||
export const search = createAsyncThunk<void, string, { state: RootState }>("entries/search", async (arg, thunkApi) => {
|
||||
export const search = createAppAsyncThunk("entries/search", async (arg: string, thunkApi) => {
|
||||
const state = thunkApi.getState()
|
||||
thunkApi.dispatch(setSearch(arg))
|
||||
thunkApi.dispatch(loadEntries({ source: state.entries.source, clearSearch: false }))
|
||||
})
|
||||
export const markEntry = createAsyncThunk(
|
||||
export const markEntry = createAppAsyncThunk(
|
||||
"entries/entry/mark",
|
||||
(arg: { entry: Entry; read: boolean }) => {
|
||||
client.entry.mark({
|
||||
@@ -112,9 +103,15 @@ export const markEntry = createAsyncThunk(
|
||||
condition: arg => arg.entry.read !== arg.read,
|
||||
}
|
||||
)
|
||||
export const markMultipleEntries = createAsyncThunk(
|
||||
export const markMultipleEntries = createAppAsyncThunk(
|
||||
"entries/entry/markMultiple",
|
||||
async (arg: { entries: Entry[]; read: boolean }, thunkApi) => {
|
||||
async (
|
||||
arg: {
|
||||
entries: Entry[]
|
||||
read: boolean
|
||||
},
|
||||
thunkApi
|
||||
) => {
|
||||
const requests: MarkRequest[] = arg.entries.map(e => ({
|
||||
id: e.id,
|
||||
read: arg.read,
|
||||
@@ -123,88 +120,90 @@ export const markMultipleEntries = createAsyncThunk(
|
||||
thunkApi.dispatch(reloadTree())
|
||||
}
|
||||
)
|
||||
export const markEntriesUpToEntry = createAsyncThunk<void, Entry, { state: RootState }>(
|
||||
"entries/entry/upToEntry",
|
||||
async (arg, thunkApi) => {
|
||||
const state = thunkApi.getState()
|
||||
const { entries } = state.entries
|
||||
export const markEntriesUpToEntry = createAppAsyncThunk("entries/entry/upToEntry", async (arg: Entry, thunkApi) => {
|
||||
const state = thunkApi.getState()
|
||||
const { entries } = state.entries
|
||||
|
||||
const index = entries.findIndex(e => e.id === arg.id)
|
||||
if (index === -1) return
|
||||
const index = entries.findIndex(e => e.id === arg.id)
|
||||
if (index === -1) return
|
||||
|
||||
thunkApi.dispatch(
|
||||
markMultipleEntries({
|
||||
entries: entries.slice(0, index + 1),
|
||||
read: true,
|
||||
})
|
||||
)
|
||||
thunkApi.dispatch(
|
||||
markMultipleEntries({
|
||||
entries: entries.slice(0, index + 1),
|
||||
read: true,
|
||||
})
|
||||
)
|
||||
})
|
||||
export const markAllEntries = createAppAsyncThunk(
|
||||
"entries/entry/markAll",
|
||||
async (
|
||||
arg: {
|
||||
sourceType: EntrySourceType
|
||||
req: MarkRequest
|
||||
},
|
||||
thunkApi
|
||||
) => {
|
||||
const endpoint = arg.sourceType === "category" ? client.category.markEntries : client.feed.markEntries
|
||||
await endpoint(arg.req)
|
||||
thunkApi.dispatch(reloadEntries())
|
||||
thunkApi.dispatch(reloadTree())
|
||||
}
|
||||
)
|
||||
export const markAllEntries = createAsyncThunk<
|
||||
void,
|
||||
{ sourceType: EntrySourceType; req: MarkRequest },
|
||||
{
|
||||
state: RootState
|
||||
}
|
||||
>("entries/entry/markAll", async (arg, thunkApi) => {
|
||||
const endpoint = arg.sourceType === "category" ? client.category.markEntries : client.feed.markEntries
|
||||
await endpoint(arg.req)
|
||||
thunkApi.dispatch(reloadEntries())
|
||||
thunkApi.dispatch(reloadTree())
|
||||
})
|
||||
export const starEntry = createAsyncThunk("entries/entry/star", (arg: { entry: Entry; starred: boolean }) => {
|
||||
export const starEntry = createAppAsyncThunk("entries/entry/star", (arg: { entry: Entry; starred: boolean }) => {
|
||||
client.entry.star({
|
||||
id: arg.entry.id,
|
||||
feedId: +arg.entry.feedId,
|
||||
starred: arg.starred,
|
||||
})
|
||||
})
|
||||
export const selectEntry = createAsyncThunk<
|
||||
void,
|
||||
{
|
||||
entry: Entry
|
||||
expand: boolean
|
||||
markAsRead: boolean
|
||||
scrollToEntry: boolean
|
||||
},
|
||||
{ state: RootState }
|
||||
>("entries/entry/select", (arg, thunkApi) => {
|
||||
const state = thunkApi.getState()
|
||||
const entry = state.entries.entries.find(e => e.id === arg.entry.id)
|
||||
if (!entry) return
|
||||
export const selectEntry = createAppAsyncThunk(
|
||||
"entries/entry/select",
|
||||
(
|
||||
arg: {
|
||||
entry: Entry
|
||||
expand: boolean
|
||||
markAsRead: boolean
|
||||
scrollToEntry: boolean
|
||||
},
|
||||
thunkApi
|
||||
) => {
|
||||
const state = thunkApi.getState()
|
||||
const entry = state.entries.entries.find(e => e.id === arg.entry.id)
|
||||
if (!entry) return
|
||||
|
||||
// flushSync is required because we need the newly selected entry to be expanded
|
||||
// and the previously selected entry to be collapsed to be able to scroll to the right position
|
||||
flushSync(() => {
|
||||
// mark as read if requested
|
||||
if (arg.markAsRead) {
|
||||
thunkApi.dispatch(markEntry({ entry, read: true }))
|
||||
}
|
||||
// flushSync is required because we need the newly selected entry to be expanded
|
||||
// and the previously selected entry to be collapsed to be able to scroll to the right position
|
||||
flushSync(() => {
|
||||
// mark as read if requested
|
||||
if (arg.markAsRead) {
|
||||
thunkApi.dispatch(markEntry({ entry, read: true }))
|
||||
}
|
||||
|
||||
// set entry as selected
|
||||
thunkApi.dispatch(entriesSlice.actions.setSelectedEntry(entry))
|
||||
// set entry as selected
|
||||
thunkApi.dispatch(entriesSlice.actions.setSelectedEntry(entry))
|
||||
|
||||
// expand if requested
|
||||
const previouslySelectedEntry = state.entries.entries.find(e => e.id === state.entries.selectedEntryId)
|
||||
if (previouslySelectedEntry) {
|
||||
thunkApi.dispatch(entriesSlice.actions.setEntryExpanded({ entry: previouslySelectedEntry, expanded: false }))
|
||||
}
|
||||
thunkApi.dispatch(entriesSlice.actions.setEntryExpanded({ entry, expanded: arg.expand }))
|
||||
})
|
||||
// expand if requested
|
||||
const previouslySelectedEntry = state.entries.entries.find(e => e.id === state.entries.selectedEntryId)
|
||||
if (previouslySelectedEntry) {
|
||||
thunkApi.dispatch(entriesSlice.actions.setEntryExpanded({ entry: previouslySelectedEntry, expanded: false }))
|
||||
}
|
||||
thunkApi.dispatch(entriesSlice.actions.setEntryExpanded({ entry, expanded: arg.expand }))
|
||||
})
|
||||
|
||||
if (arg.scrollToEntry) {
|
||||
const entryElement = document.getElementById(Constants.dom.entryId(entry))
|
||||
if (entryElement) {
|
||||
const alwaysScrollToEntry = state.user.settings?.alwaysScrollToEntry
|
||||
const entryEntirelyVisible = Constants.layout.isTopVisible(entryElement) && Constants.layout.isBottomVisible(entryElement)
|
||||
if (alwaysScrollToEntry || !entryEntirelyVisible) {
|
||||
const scrollSpeed = state.user.settings?.scrollSpeed
|
||||
thunkApi.dispatch(entriesSlice.actions.setScrollingToEntry(true))
|
||||
scrollToEntry(entryElement, scrollSpeed, () => thunkApi.dispatch(entriesSlice.actions.setScrollingToEntry(false)))
|
||||
if (arg.scrollToEntry) {
|
||||
const entryElement = document.getElementById(Constants.dom.entryId(entry))
|
||||
if (entryElement) {
|
||||
const alwaysScrollToEntry = state.user.settings?.alwaysScrollToEntry
|
||||
const entryEntirelyVisible = Constants.layout.isTopVisible(entryElement) && Constants.layout.isBottomVisible(entryElement)
|
||||
if (alwaysScrollToEntry || !entryEntirelyVisible) {
|
||||
const scrollSpeed = state.user.settings?.scrollSpeed
|
||||
thunkApi.dispatch(entriesSlice.actions.setScrollingToEntry(true))
|
||||
scrollToEntry(entryElement, scrollSpeed, () => thunkApi.dispatch(entriesSlice.actions.setScrollingToEntry(false)))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
)
|
||||
const scrollToEntry = (entryElement: HTMLElement, scrollSpeed: number | undefined, onScrollEnded: () => void) => {
|
||||
scrollToWithCallback({
|
||||
options: {
|
||||
@@ -216,59 +215,57 @@ const scrollToEntry = (entryElement: HTMLElement, scrollSpeed: number | undefine
|
||||
})
|
||||
}
|
||||
|
||||
export const selectPreviousEntry = createAsyncThunk<
|
||||
void,
|
||||
{
|
||||
expand: boolean
|
||||
markAsRead: boolean
|
||||
scrollToEntry: boolean
|
||||
},
|
||||
{ state: RootState }
|
||||
>("entries/entry/selectPrevious", (arg, thunkApi) => {
|
||||
const state = thunkApi.getState()
|
||||
const { entries } = state.entries
|
||||
const previousIndex = entries.findIndex(e => e.id === state.entries.selectedEntryId) - 1
|
||||
if (previousIndex >= 0) {
|
||||
thunkApi.dispatch(
|
||||
selectEntry({
|
||||
entry: entries[previousIndex],
|
||||
expand: arg.expand,
|
||||
markAsRead: arg.markAsRead,
|
||||
scrollToEntry: arg.scrollToEntry,
|
||||
})
|
||||
)
|
||||
export const selectPreviousEntry = createAppAsyncThunk(
|
||||
"entries/entry/selectPrevious",
|
||||
(
|
||||
arg: {
|
||||
expand: boolean
|
||||
markAsRead: boolean
|
||||
scrollToEntry: boolean
|
||||
},
|
||||
thunkApi
|
||||
) => {
|
||||
const state = thunkApi.getState()
|
||||
const { entries } = state.entries
|
||||
const previousIndex = entries.findIndex(e => e.id === state.entries.selectedEntryId) - 1
|
||||
if (previousIndex >= 0) {
|
||||
thunkApi.dispatch(
|
||||
selectEntry({
|
||||
entry: entries[previousIndex],
|
||||
expand: arg.expand,
|
||||
markAsRead: arg.markAsRead,
|
||||
scrollToEntry: arg.scrollToEntry,
|
||||
})
|
||||
)
|
||||
}
|
||||
}
|
||||
})
|
||||
export const selectNextEntry = createAsyncThunk<
|
||||
void,
|
||||
{
|
||||
expand: boolean
|
||||
markAsRead: boolean
|
||||
scrollToEntry: boolean
|
||||
},
|
||||
{ state: RootState }
|
||||
>("entries/entry/selectNext", (arg, thunkApi) => {
|
||||
const state = thunkApi.getState()
|
||||
const { entries } = state.entries
|
||||
const nextIndex = entries.findIndex(e => e.id === state.entries.selectedEntryId) + 1
|
||||
if (nextIndex < entries.length) {
|
||||
thunkApi.dispatch(
|
||||
selectEntry({
|
||||
entry: entries[nextIndex],
|
||||
expand: arg.expand,
|
||||
markAsRead: arg.markAsRead,
|
||||
scrollToEntry: arg.scrollToEntry,
|
||||
})
|
||||
)
|
||||
)
|
||||
export const selectNextEntry = createAppAsyncThunk(
|
||||
"entries/entry/selectNext",
|
||||
(
|
||||
arg: {
|
||||
expand: boolean
|
||||
markAsRead: boolean
|
||||
scrollToEntry: boolean
|
||||
},
|
||||
thunkApi
|
||||
) => {
|
||||
const state = thunkApi.getState()
|
||||
const { entries } = state.entries
|
||||
const nextIndex = entries.findIndex(e => e.id === state.entries.selectedEntryId) + 1
|
||||
if (nextIndex < entries.length) {
|
||||
thunkApi.dispatch(
|
||||
selectEntry({
|
||||
entry: entries[nextIndex],
|
||||
expand: arg.expand,
|
||||
markAsRead: arg.markAsRead,
|
||||
scrollToEntry: arg.scrollToEntry,
|
||||
})
|
||||
)
|
||||
}
|
||||
}
|
||||
})
|
||||
export const tagEntry = createAsyncThunk<
|
||||
void,
|
||||
TagRequest,
|
||||
{
|
||||
state: RootState
|
||||
}
|
||||
>("entries/entry/tag", async (arg, thunkApi) => {
|
||||
)
|
||||
export const tagEntry = createAppAsyncThunk("entries/entry/tag", async (arg: TagRequest, thunkApi) => {
|
||||
await client.entry.tag(arg)
|
||||
thunkApi.dispatch(reloadTags())
|
||||
})
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { createAsyncThunk, createSlice, PayloadAction } from "@reduxjs/toolkit"
|
||||
import { createSlice, PayloadAction } from "@reduxjs/toolkit"
|
||||
import { Constants } from "app/constants"
|
||||
import { RootState } from "app/store"
|
||||
import { createAppAsyncThunk } from "app/store"
|
||||
|
||||
interface RedirectState {
|
||||
to?: string
|
||||
@@ -8,52 +8,46 @@ interface RedirectState {
|
||||
|
||||
const initialState: RedirectState = {}
|
||||
|
||||
export const redirectToLogin = createAsyncThunk("redirect/login", (_, thunkApi) => thunkApi.dispatch(redirectTo("/login")))
|
||||
export const redirectToRegistration = createAsyncThunk("redirect/register", (_, thunkApi) => thunkApi.dispatch(redirectTo("/register")))
|
||||
export const redirectToPasswordRecovery = createAsyncThunk("redirect/passwordRecovery", (_, thunkApi) =>
|
||||
export const redirectToLogin = createAppAsyncThunk("redirect/login", (_, thunkApi) => thunkApi.dispatch(redirectTo("/login")))
|
||||
export const redirectToRegistration = createAppAsyncThunk("redirect/register", (_, thunkApi) => thunkApi.dispatch(redirectTo("/register")))
|
||||
export const redirectToPasswordRecovery = createAppAsyncThunk("redirect/passwordRecovery", (_, thunkApi) =>
|
||||
thunkApi.dispatch(redirectTo("/passwordRecovery"))
|
||||
)
|
||||
export const redirectToApiDocumentation = createAsyncThunk("redirect/api", (_, thunkApi) => thunkApi.dispatch(redirectTo("/api")))
|
||||
export const redirectToApiDocumentation = createAppAsyncThunk("redirect/api", (_, thunkApi) => thunkApi.dispatch(redirectTo("/api")))
|
||||
|
||||
export const redirectToSelectedSource = createAsyncThunk<
|
||||
void,
|
||||
void,
|
||||
{
|
||||
state: RootState
|
||||
}
|
||||
>("redirect/selectedSource", (_, thunkApi) => {
|
||||
export const redirectToSelectedSource = createAppAsyncThunk("redirect/selectedSource", (_, thunkApi) => {
|
||||
const { source } = thunkApi.getState().entries
|
||||
thunkApi.dispatch(redirectTo(`/app/${source.type}/${source.id}`))
|
||||
})
|
||||
export const redirectToCategory = createAsyncThunk("redirect/category", (id: string, thunkApi) =>
|
||||
export const redirectToCategory = createAppAsyncThunk("redirect/category", (id: string, thunkApi) =>
|
||||
thunkApi.dispatch(redirectTo(`/app/category/${id}`))
|
||||
)
|
||||
export const redirectToRootCategory = createAsyncThunk("redirect/category/root", (_, thunkApi) =>
|
||||
export const redirectToRootCategory = createAppAsyncThunk("redirect/category/root", (_, thunkApi) =>
|
||||
thunkApi.dispatch(redirectToCategory(Constants.categories.all.id))
|
||||
)
|
||||
export const redirectToCategoryDetails = createAsyncThunk("redirect/category/details", (id: string, thunkApi) =>
|
||||
export const redirectToCategoryDetails = createAppAsyncThunk("redirect/category/details", (id: string, thunkApi) =>
|
||||
thunkApi.dispatch(redirectTo(`/app/category/${id}/details`))
|
||||
)
|
||||
export const redirectToFeed = createAsyncThunk("redirect/feed", (id: string | number, thunkApi) =>
|
||||
export const redirectToFeed = createAppAsyncThunk("redirect/feed", (id: string | number, thunkApi) =>
|
||||
thunkApi.dispatch(redirectTo(`/app/feed/${id}`))
|
||||
)
|
||||
export const redirectToFeedDetails = createAsyncThunk("redirect/feed/details", (id: string, thunkApi) =>
|
||||
export const redirectToFeedDetails = createAppAsyncThunk("redirect/feed/details", (id: string, thunkApi) =>
|
||||
thunkApi.dispatch(redirectTo(`/app/feed/${id}/details`))
|
||||
)
|
||||
export const redirectToTag = createAsyncThunk("redirect/tag", (id: string, thunkApi) => thunkApi.dispatch(redirectTo(`/app/tag/${id}`)))
|
||||
export const redirectToTagDetails = createAsyncThunk("redirect/tag/details", (id: string, thunkApi) =>
|
||||
export const redirectToTag = createAppAsyncThunk("redirect/tag", (id: string, thunkApi) => thunkApi.dispatch(redirectTo(`/app/tag/${id}`)))
|
||||
export const redirectToTagDetails = createAppAsyncThunk("redirect/tag/details", (id: string, thunkApi) =>
|
||||
thunkApi.dispatch(redirectTo(`/app/tag/${id}/details`))
|
||||
)
|
||||
export const redirectToAdd = createAsyncThunk("redirect/add", (_, thunkApi) => thunkApi.dispatch(redirectTo("/app/add")))
|
||||
export const redirectToSettings = createAsyncThunk("redirect/settings", (_, thunkApi) => thunkApi.dispatch(redirectTo("/app/settings")))
|
||||
export const redirectToAdminUsers = createAsyncThunk("redirect/admin/users", (_, thunkApi) =>
|
||||
export const redirectToAdd = createAppAsyncThunk("redirect/add", (_, thunkApi) => thunkApi.dispatch(redirectTo("/app/add")))
|
||||
export const redirectToSettings = createAppAsyncThunk("redirect/settings", (_, thunkApi) => thunkApi.dispatch(redirectTo("/app/settings")))
|
||||
export const redirectToAdminUsers = createAppAsyncThunk("redirect/admin/users", (_, thunkApi) =>
|
||||
thunkApi.dispatch(redirectTo("/app/admin/users"))
|
||||
)
|
||||
export const redirectToMetrics = createAsyncThunk("redirect/admin/metrics", (_, thunkApi) =>
|
||||
export const redirectToMetrics = createAppAsyncThunk("redirect/admin/metrics", (_, thunkApi) =>
|
||||
thunkApi.dispatch(redirectTo("/app/admin/metrics"))
|
||||
)
|
||||
export const redirectToDonate = createAsyncThunk("redirect/donate", (_, thunkApi) => thunkApi.dispatch(redirectTo("/app/donate")))
|
||||
export const redirectToAbout = createAsyncThunk("redirect/about", (_, thunkApi) => thunkApi.dispatch(redirectTo("/app/about")))
|
||||
export const redirectToDonate = createAppAsyncThunk("redirect/donate", (_, thunkApi) => thunkApi.dispatch(redirectTo("/app/donate")))
|
||||
export const redirectToAbout = createAppAsyncThunk("redirect/about", (_, thunkApi) => thunkApi.dispatch(redirectTo("/app/about")))
|
||||
|
||||
export const redirectSlice = createSlice({
|
||||
name: "redirect",
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { PayloadAction, createAsyncThunk, createSlice } from "@reduxjs/toolkit"
|
||||
import { PayloadAction, createSlice } from "@reduxjs/toolkit"
|
||||
import { client } from "app/client"
|
||||
import { createAppAsyncThunk } from "app/store"
|
||||
import { ServerInfo } from "app/types"
|
||||
|
||||
interface ServerState {
|
||||
@@ -11,7 +12,7 @@ const initialState: ServerState = {
|
||||
webSocketConnected: false,
|
||||
}
|
||||
|
||||
export const reloadServerInfos = createAsyncThunk("server/infos", () => client.server.getServerInfos().then(r => r.data))
|
||||
export const reloadServerInfos = createAppAsyncThunk("server/infos", () => client.server.getServerInfos().then(r => r.data))
|
||||
export const serverSlice = createSlice({
|
||||
name: "server",
|
||||
initialState,
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { createAsyncThunk, createSlice, PayloadAction } from "@reduxjs/toolkit"
|
||||
import { createSlice, PayloadAction } from "@reduxjs/toolkit"
|
||||
import { client } from "app/client"
|
||||
import { createAppAsyncThunk } from "app/store"
|
||||
import { Category, CollapseRequest } from "app/types"
|
||||
import { visitCategoryTree } from "app/utils"
|
||||
// eslint-disable-next-line import/no-cycle
|
||||
@@ -19,8 +20,8 @@ const initialState: TreeState = {
|
||||
sidebarVisible: true,
|
||||
}
|
||||
|
||||
export const reloadTree = createAsyncThunk("tree/reload", () => client.category.getRoot().then(r => r.data))
|
||||
export const collapseTreeCategory = createAsyncThunk("tree/category/collapse", async (req: CollapseRequest) =>
|
||||
export const reloadTree = createAppAsyncThunk("tree/reload", () => client.category.getRoot().then(r => r.data))
|
||||
export const collapseTreeCategory = createAppAsyncThunk("tree/category/collapse", async (req: CollapseRequest) =>
|
||||
client.category.collapse(req)
|
||||
)
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { t } from "@lingui/macro"
|
||||
import { showNotification } from "@mantine/notifications"
|
||||
import { createAsyncThunk, createSlice, isAnyOf } from "@reduxjs/toolkit"
|
||||
import { createSlice, isAnyOf } from "@reduxjs/toolkit"
|
||||
import { client } from "app/client"
|
||||
import { RootState } from "app/store"
|
||||
import { createAppAsyncThunk } from "app/store"
|
||||
import { ReadingMode, ReadingOrder, Settings, SharingSettings, UserModel } from "app/types"
|
||||
// eslint-disable-next-line import/no-cycle
|
||||
import { reloadEntries } from "./entries"
|
||||
@@ -15,121 +15,79 @@ interface UserState {
|
||||
|
||||
const initialState: UserState = {}
|
||||
|
||||
export const reloadSettings = createAsyncThunk("settings/reload", () => client.user.getSettings().then(r => r.data))
|
||||
export const reloadProfile = createAsyncThunk("profile/reload", () => client.user.getProfile().then(r => r.data))
|
||||
export const reloadTags = createAsyncThunk("entries/tags", () => client.entry.getTags().then(r => r.data))
|
||||
export const changeReadingMode = createAsyncThunk<void, ReadingMode, { state: RootState }>(
|
||||
"settings/readingMode",
|
||||
(readingMode, thunkApi) => {
|
||||
const { settings } = thunkApi.getState().user
|
||||
if (!settings) return
|
||||
client.user.saveSettings({ ...settings, readingMode })
|
||||
thunkApi.dispatch(reloadEntries())
|
||||
}
|
||||
)
|
||||
export const changeReadingOrder = createAsyncThunk<void, ReadingOrder, { state: RootState }>(
|
||||
"settings/readingOrder",
|
||||
(readingOrder, thunkApi) => {
|
||||
const { settings } = thunkApi.getState().user
|
||||
if (!settings) return
|
||||
client.user.saveSettings({ ...settings, readingOrder })
|
||||
thunkApi.dispatch(reloadEntries())
|
||||
}
|
||||
)
|
||||
export const changeLanguage = createAsyncThunk<
|
||||
void,
|
||||
string,
|
||||
{
|
||||
state: RootState
|
||||
}
|
||||
>("settings/language", (language, thunkApi) => {
|
||||
export const reloadSettings = createAppAsyncThunk("settings/reload", () => client.user.getSettings().then(r => r.data))
|
||||
export const reloadProfile = createAppAsyncThunk("profile/reload", () => client.user.getProfile().then(r => r.data))
|
||||
export const reloadTags = createAppAsyncThunk("entries/tags", () => client.entry.getTags().then(r => r.data))
|
||||
export const changeReadingMode = createAppAsyncThunk("settings/readingMode", (readingMode: ReadingMode, thunkApi) => {
|
||||
const { settings } = thunkApi.getState().user
|
||||
if (!settings) return
|
||||
client.user.saveSettings({ ...settings, readingMode })
|
||||
thunkApi.dispatch(reloadEntries())
|
||||
})
|
||||
export const changeReadingOrder = createAppAsyncThunk("settings/readingOrder", (readingOrder: ReadingOrder, thunkApi) => {
|
||||
const { settings } = thunkApi.getState().user
|
||||
if (!settings) return
|
||||
client.user.saveSettings({ ...settings, readingOrder })
|
||||
thunkApi.dispatch(reloadEntries())
|
||||
})
|
||||
export const changeLanguage = createAppAsyncThunk("settings/language", (language: string, thunkApi) => {
|
||||
const { settings } = thunkApi.getState().user
|
||||
if (!settings) return
|
||||
client.user.saveSettings({ ...settings, language })
|
||||
})
|
||||
export const changeScrollSpeed = createAsyncThunk<
|
||||
void,
|
||||
boolean,
|
||||
{
|
||||
state: RootState
|
||||
}
|
||||
>("settings/scrollSpeed", (speed, thunkApi) => {
|
||||
export const changeScrollSpeed = createAppAsyncThunk("settings/scrollSpeed", (speed: boolean, thunkApi) => {
|
||||
const { settings } = thunkApi.getState().user
|
||||
if (!settings) return
|
||||
client.user.saveSettings({ ...settings, scrollSpeed: speed ? 400 : 0 })
|
||||
})
|
||||
export const changeShowRead = createAsyncThunk<
|
||||
void,
|
||||
boolean,
|
||||
{
|
||||
state: RootState
|
||||
}
|
||||
>("settings/showRead", (showRead, thunkApi) => {
|
||||
export const changeShowRead = createAppAsyncThunk("settings/showRead", (showRead: boolean, thunkApi) => {
|
||||
const { settings } = thunkApi.getState().user
|
||||
if (!settings) return
|
||||
client.user.saveSettings({ ...settings, showRead })
|
||||
})
|
||||
export const changeScrollMarks = createAsyncThunk<
|
||||
void,
|
||||
boolean,
|
||||
{
|
||||
state: RootState
|
||||
}
|
||||
>("settings/scrollMarks", (scrollMarks, thunkApi) => {
|
||||
export const changeScrollMarks = createAppAsyncThunk("settings/scrollMarks", (scrollMarks: boolean, thunkApi) => {
|
||||
const { settings } = thunkApi.getState().user
|
||||
if (!settings) return
|
||||
client.user.saveSettings({ ...settings, scrollMarks })
|
||||
})
|
||||
export const changeAlwaysScrollToEntry = createAsyncThunk<
|
||||
void,
|
||||
boolean,
|
||||
{
|
||||
state: RootState
|
||||
}
|
||||
>("settings/alwaysScrollToEntry", (alwaysScrollToEntry, thunkApi) => {
|
||||
export const changeAlwaysScrollToEntry = createAppAsyncThunk("settings/alwaysScrollToEntry", (alwaysScrollToEntry: boolean, thunkApi) => {
|
||||
const { settings } = thunkApi.getState().user
|
||||
if (!settings) return
|
||||
client.user.saveSettings({ ...settings, alwaysScrollToEntry })
|
||||
})
|
||||
export const changeMarkAllAsReadConfirmation = createAsyncThunk<
|
||||
void,
|
||||
boolean,
|
||||
{
|
||||
state: RootState
|
||||
export const changeMarkAllAsReadConfirmation = createAppAsyncThunk(
|
||||
"settings/markAllAsReadConfirmation",
|
||||
(markAllAsReadConfirmation: boolean, thunkApi) => {
|
||||
const { settings } = thunkApi.getState().user
|
||||
if (!settings) return
|
||||
client.user.saveSettings({ ...settings, markAllAsReadConfirmation })
|
||||
}
|
||||
>("settings/markAllAsReadConfirmation", (markAllAsReadConfirmation, thunkApi) => {
|
||||
const { settings } = thunkApi.getState().user
|
||||
if (!settings) return
|
||||
client.user.saveSettings({ ...settings, markAllAsReadConfirmation })
|
||||
})
|
||||
export const changeCustomContextMenu = createAsyncThunk<
|
||||
void,
|
||||
boolean,
|
||||
{
|
||||
state: RootState
|
||||
}
|
||||
>("settings/customContextMenu", (customContextMenu, thunkApi) => {
|
||||
)
|
||||
export const changeCustomContextMenu = createAppAsyncThunk("settings/customContextMenu", (customContextMenu: boolean, thunkApi) => {
|
||||
const { settings } = thunkApi.getState().user
|
||||
if (!settings) return
|
||||
client.user.saveSettings({ ...settings, customContextMenu })
|
||||
})
|
||||
export const changeSharingSetting = createAsyncThunk<
|
||||
void,
|
||||
{ site: keyof SharingSettings; value: boolean },
|
||||
{
|
||||
state: RootState
|
||||
}
|
||||
>("settings/sharingSetting", (sharingSetting, thunkApi) => {
|
||||
const { settings } = thunkApi.getState().user
|
||||
if (!settings) return
|
||||
client.user.saveSettings({
|
||||
...settings,
|
||||
sharingSettings: {
|
||||
...settings.sharingSettings,
|
||||
[sharingSetting.site]: sharingSetting.value,
|
||||
export const changeSharingSetting = createAppAsyncThunk(
|
||||
"settings/sharingSetting",
|
||||
(
|
||||
sharingSetting: {
|
||||
site: keyof SharingSettings
|
||||
value: boolean
|
||||
},
|
||||
})
|
||||
})
|
||||
thunkApi
|
||||
) => {
|
||||
const { settings } = thunkApi.getState().user
|
||||
if (!settings) return
|
||||
client.user.saveSettings({
|
||||
...settings,
|
||||
sharingSettings: {
|
||||
...settings.sharingSettings,
|
||||
[sharingSetting.site]: sharingSetting.value,
|
||||
},
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
export const userSlice = createSlice({
|
||||
name: "user",
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { configureStore } from "@reduxjs/toolkit"
|
||||
import { configureStore, createAsyncThunk } from "@reduxjs/toolkit"
|
||||
import { setupListeners } from "@reduxjs/toolkit/query"
|
||||
import { TypedUseSelectorHook, useDispatch, useSelector } from "react-redux"
|
||||
import entriesReducer from "./slices/entries"
|
||||
@@ -24,3 +24,7 @@ export type AppDispatch = typeof store.dispatch
|
||||
|
||||
export const useAppDispatch: () => AppDispatch = useDispatch
|
||||
export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector
|
||||
export const createAppAsyncThunk = createAsyncThunk.withTypes<{
|
||||
state: RootState
|
||||
dispatch: AppDispatch
|
||||
}>()
|
||||
|
||||
Reference in New Issue
Block a user