simplify settings thunks

This commit is contained in:
Athou
2026-05-03 19:14:50 +02:00
parent b170e0bc17
commit 8645c57d13
5 changed files with 80 additions and 370 deletions

View File

@@ -1,32 +1,8 @@
import { t } from "@lingui/core/macro"
import { showNotification } from "@mantine/notifications"
import { createSlice, isAnyOf, type PayloadAction } from "@reduxjs/toolkit"
import { createSlice, type PayloadAction } from "@reduxjs/toolkit"
import type { LocalSettings, Settings, UserModel, ViewMode } from "@/app/types"
import {
changeCustomContextMenu,
changeDisablePullToRefresh,
changeEntriesToKeepOnTopWhenScrolling,
changeExternalLinkIconDisplayMode,
changeLanguage,
changeMarkAllAsReadConfirmation,
changeMarkAllAsReadNavigateToUnread,
changeMobileFooter,
changePrimaryColor,
changePushNotificationSettings,
changeReadingMode,
changeReadingOrder,
changeScrollMarks,
changeScrollMode,
changeScrollSpeed,
changeSharingSetting,
changeShowRead,
changeStarIconDisplayMode,
changeUnreadCountFavicon,
changeUnreadCountTitle,
reloadProfile,
reloadSettings,
reloadTags,
} from "./thunks"
import { changeSettings, reloadProfile, reloadSettings, reloadTags } from "./thunks"
interface UserState {
settings?: Settings
@@ -73,115 +49,16 @@ export const userSlice = createSlice({
builder.addCase(reloadTags.fulfilled, (state, action) => {
state.tags = action.payload
})
builder.addCase(changeReadingMode.pending, (state, action) => {
builder.addCase(changeSettings.pending, (state, action) => {
if (!state.settings) return
state.settings.readingMode = action.meta.arg
state.settings = { ...state.settings, ...action.meta.arg }
})
builder.addCase(changeReadingOrder.pending, (state, action) => {
if (!state.settings) return
state.settings.readingOrder = action.meta.arg
builder.addCase(changeSettings.fulfilled, () => {
showNotification({
message: t`Settings saved.`,
color: "green",
})
})
builder.addCase(changeLanguage.pending, (state, action) => {
if (!state.settings) return
state.settings.language = action.meta.arg
})
builder.addCase(changeScrollSpeed.pending, (state, action) => {
if (!state.settings) return
state.settings.scrollSpeed = action.meta.arg ? 400 : 0
})
builder.addCase(changeShowRead.pending, (state, action) => {
if (!state.settings) return
state.settings.showRead = action.meta.arg
})
builder.addCase(changeScrollMarks.pending, (state, action) => {
if (!state.settings) return
state.settings.scrollMarks = action.meta.arg
})
builder.addCase(changeScrollMode.pending, (state, action) => {
if (!state.settings) return
state.settings.scrollMode = action.meta.arg
})
builder.addCase(changeEntriesToKeepOnTopWhenScrolling.pending, (state, action) => {
if (!state.settings) return
state.settings.entriesToKeepOnTopWhenScrolling = action.meta.arg
})
builder.addCase(changeStarIconDisplayMode.pending, (state, action) => {
if (!state.settings) return
state.settings.starIconDisplayMode = action.meta.arg
})
builder.addCase(changeExternalLinkIconDisplayMode.pending, (state, action) => {
if (!state.settings) return
state.settings.externalLinkIconDisplayMode = action.meta.arg
})
builder.addCase(changeMarkAllAsReadConfirmation.pending, (state, action) => {
if (!state.settings) return
state.settings.markAllAsReadConfirmation = action.meta.arg
})
builder.addCase(changeMarkAllAsReadNavigateToUnread.pending, (state, action) => {
if (!state.settings) return
state.settings.markAllAsReadNavigateToNextUnread = action.meta.arg
})
builder.addCase(changeCustomContextMenu.pending, (state, action) => {
if (!state.settings) return
state.settings.customContextMenu = action.meta.arg
})
builder.addCase(changeMobileFooter.pending, (state, action) => {
if (!state.settings) return
state.settings.mobileFooter = action.meta.arg
})
builder.addCase(changeUnreadCountTitle.pending, (state, action) => {
if (!state.settings) return
state.settings.unreadCountTitle = action.meta.arg
})
builder.addCase(changeUnreadCountFavicon.pending, (state, action) => {
if (!state.settings) return
state.settings.unreadCountFavicon = action.meta.arg
})
builder.addCase(changeDisablePullToRefresh.pending, (state, action) => {
if (!state.settings) return
state.settings.disablePullToRefresh = action.meta.arg
})
builder.addCase(changePrimaryColor.pending, (state, action) => {
if (!state.settings) return
state.settings.primaryColor = action.meta.arg
})
builder.addCase(changeSharingSetting.pending, (state, action) => {
if (!state.settings) return
state.settings.sharingSettings[action.meta.arg.site] = action.meta.arg.value
})
builder.addCase(changePushNotificationSettings.pending, (state, action) => {
if (!state.settings) return
state.settings.pushNotificationSettings = action.meta.arg
})
builder.addMatcher(
isAnyOf(
changeLanguage.fulfilled,
changeScrollSpeed.fulfilled,
changeShowRead.fulfilled,
changeScrollMarks.fulfilled,
changeScrollMode.fulfilled,
changeEntriesToKeepOnTopWhenScrolling.fulfilled,
changeStarIconDisplayMode.fulfilled,
changeExternalLinkIconDisplayMode.fulfilled,
changeMarkAllAsReadConfirmation.fulfilled,
changeMarkAllAsReadNavigateToUnread.fulfilled,
changeCustomContextMenu.fulfilled,
changeMobileFooter.fulfilled,
changeUnreadCountTitle.fulfilled,
changeUnreadCountFavicon.fulfilled,
changeDisablePullToRefresh.fulfilled,
changePrimaryColor.fulfilled,
changeSharingSetting.fulfilled,
changePushNotificationSettings.fulfilled
),
() => {
showNotification({
message: t`Settings saved.`,
color: "green",
})
}
)
},
})

View File

@@ -1,7 +1,6 @@
import { createAppAsyncThunk } from "@/app/async-thunk"
import { client } from "@/app/client"
import { reloadEntries } from "@/app/entries/thunks"
import type { IconDisplayMode, PushNotificationSettings, ReadingMode, ReadingOrder, ScrollMode, SharingSettings } from "@/app/types"
import type { Settings } from "@/app/types"
export const reloadSettings = createAppAsyncThunk("settings/reload", async () => await client.user.getSettings().then(r => r.data))
@@ -9,163 +8,8 @@ export const reloadProfile = createAppAsyncThunk("profile/reload", async () => a
export const reloadTags = createAppAsyncThunk("entries/tags", async () => await client.entry.getTags().then(r => r.data))
export const changeReadingMode = createAppAsyncThunk("settings/readingMode", (readingMode: ReadingMode, thunkApi) => {
export const changeSettings = createAppAsyncThunk("settings/change", async (newSettings: Partial<Settings>, thunkApi) => {
const { settings } = thunkApi.getState().user
if (!settings) return
client.user.saveSettings({ ...settings, readingMode })
thunkApi.dispatch(reloadEntries())
await client.user.saveSettings({ ...settings, ...newSettings })
})
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 = 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 = createAppAsyncThunk("settings/showRead", (showRead: boolean, thunkApi) => {
const { settings } = thunkApi.getState().user
if (!settings) return
client.user.saveSettings({ ...settings, showRead })
})
export const changeScrollMarks = createAppAsyncThunk("settings/scrollMarks", (scrollMarks: boolean, thunkApi) => {
const { settings } = thunkApi.getState().user
if (!settings) return
client.user.saveSettings({ ...settings, scrollMarks })
})
export const changeScrollMode = createAppAsyncThunk("settings/scrollMode", (scrollMode: ScrollMode, thunkApi) => {
const { settings } = thunkApi.getState().user
if (!settings) return
client.user.saveSettings({ ...settings, scrollMode })
})
export const changeEntriesToKeepOnTopWhenScrolling = createAppAsyncThunk(
"settings/entriesToKeepOnTopWhenScrolling",
(entriesToKeepOnTopWhenScrolling: number, thunkApi) => {
const { settings } = thunkApi.getState().user
if (!settings) return
client.user.saveSettings({ ...settings, entriesToKeepOnTopWhenScrolling })
}
)
export const changeStarIconDisplayMode = createAppAsyncThunk(
"settings/starIconDisplayMode",
(starIconDisplayMode: IconDisplayMode, thunkApi) => {
const { settings } = thunkApi.getState().user
if (!settings) return
client.user.saveSettings({ ...settings, starIconDisplayMode })
}
)
export const changeExternalLinkIconDisplayMode = createAppAsyncThunk(
"settings/externalLinkIconDisplayMode",
(externalLinkIconDisplayMode: IconDisplayMode, thunkApi) => {
const { settings } = thunkApi.getState().user
if (!settings) return
client.user.saveSettings({ ...settings, externalLinkIconDisplayMode })
}
)
export const changeMarkAllAsReadConfirmation = createAppAsyncThunk(
"settings/markAllAsReadConfirmation",
(markAllAsReadConfirmation: boolean, thunkApi) => {
const { settings } = thunkApi.getState().user
if (!settings) return
client.user.saveSettings({ ...settings, markAllAsReadConfirmation })
}
)
export const changeMarkAllAsReadNavigateToUnread = createAppAsyncThunk(
"settings/markAllAsReadNavigateToUnread",
(markAllAsReadNavigateToNextUnread: boolean, thunkApi) => {
const { settings } = thunkApi.getState().user
if (!settings) return
client.user.saveSettings({ ...settings, markAllAsReadNavigateToNextUnread })
}
)
export const changeCustomContextMenu = createAppAsyncThunk("settings/customContextMenu", (customContextMenu: boolean, thunkApi) => {
const { settings } = thunkApi.getState().user
if (!settings) return
client.user.saveSettings({ ...settings, customContextMenu })
})
export const changeMobileFooter = createAppAsyncThunk("settings/mobileFooter", (mobileFooter: boolean, thunkApi) => {
const { settings } = thunkApi.getState().user
if (!settings) return
client.user.saveSettings({ ...settings, mobileFooter })
})
export const changeUnreadCountTitle = createAppAsyncThunk("settings/unreadCountTitle", (unreadCountTitle: boolean, thunkApi) => {
const { settings } = thunkApi.getState().user
if (!settings) return
client.user.saveSettings({ ...settings, unreadCountTitle })
})
export const changeUnreadCountFavicon = createAppAsyncThunk("settings/unreadCountFavicon", (unreadCountFavicon: boolean, thunkApi) => {
const { settings } = thunkApi.getState().user
if (!settings) return
client.user.saveSettings({ ...settings, unreadCountFavicon })
})
export const changeDisablePullToRefresh = createAppAsyncThunk(
"settings/disablePullToRefresh",
(disablePullToRefresh: boolean, thunkApi) => {
const { settings } = thunkApi.getState().user
if (!settings) return
client.user.saveSettings({ ...settings, disablePullToRefresh })
}
)
export const changePrimaryColor = createAppAsyncThunk("settings/primaryColor", (primaryColor: string, thunkApi) => {
const { settings } = thunkApi.getState().user
if (!settings) return
client.user.saveSettings({ ...settings, primaryColor })
})
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 changePushNotificationSettings = createAppAsyncThunk(
"settings/pushNotificationSettings",
(pushNotificationSettings: PushNotificationSettings, thunkApi) => {
const { settings } = thunkApi.getState().user
if (!settings) return
client.user.saveSettings({
...settings,
pushNotificationSettings,
})
}
)

View File

@@ -19,7 +19,7 @@ import {
} from "react-icons/tb"
import { markAllAsReadWithConfirmationIfRequired, reloadEntries, search, selectNextEntry, selectPreviousEntry } from "@/app/entries/thunks"
import { useAppDispatch, useAppSelector } from "@/app/store"
import { changeReadingMode, changeReadingOrder } from "@/app/user/thunks"
import { changeSettings } from "@/app/user/thunks"
import { ActionButton } from "@/components/ActionButton"
import { Loader } from "@/components/Loader"
import { useActionButton } from "@/hooks/useActionButton"
@@ -73,6 +73,25 @@ export function Header() {
}, [setValues, searchFromStore])
if (!settings) return <Loader />
const toggleReadingMode = async () => {
await dispatch(
changeSettings({
readingMode: settings.readingMode === "all" ? "unread" : "all",
})
)
dispatch(reloadEntries())
}
const toggleReadingOrder = async () => {
await dispatch(
changeSettings({
readingOrder: settings.readingOrder === "asc" ? "desc" : "asc",
})
)
dispatch(reloadEntries())
}
return (
<Center className="cf-toolbar-wrapper">
<HeaderToolbar>
@@ -121,12 +140,12 @@ export function Header() {
<ActionButton
icon={settings.readingMode === "all" ? <TbEye size={iconSize} /> : <TbEyeOff size={iconSize} />}
label={settings.readingMode === "all" ? msg`All` : msg`Unread`}
onClick={async () => await dispatch(changeReadingMode(settings.readingMode === "all" ? "unread" : "all"))}
onClick={toggleReadingMode}
/>
<ActionButton
icon={settings.readingOrder === "asc" ? <TbSortAscending size={iconSize} /> : <TbSortDescending size={iconSize} />}
label={settings.readingOrder === "asc" ? msg`Asc` : msg`Desc`}
onClick={async () => await dispatch(changeReadingOrder(settings.readingOrder === "asc" ? "desc" : "asc"))}
onClick={toggleReadingOrder}
/>
<Popover>

View File

@@ -6,6 +6,7 @@ import {
type ComboboxData,
Divider,
Group,
Loader,
NumberInput,
Radio,
Select,
@@ -18,45 +19,11 @@ import type { ReactNode } from "react"
import { Constants } from "@/app/constants"
import { useAppDispatch, useAppSelector } from "@/app/store"
import type { IconDisplayMode, ScrollMode, SharingSettings } from "@/app/types"
import {
changeCustomContextMenu,
changeDisablePullToRefresh,
changeEntriesToKeepOnTopWhenScrolling,
changeExternalLinkIconDisplayMode,
changeLanguage,
changeMarkAllAsReadConfirmation,
changeMarkAllAsReadNavigateToUnread,
changeMobileFooter,
changePrimaryColor,
changeScrollMarks,
changeScrollMode,
changeScrollSpeed,
changeSharingSetting,
changeShowRead,
changeStarIconDisplayMode,
changeUnreadCountFavicon,
changeUnreadCountTitle,
} from "@/app/user/thunks"
import { changeSettings } from "@/app/user/thunks"
import { locales } from "@/i18n"
export function DisplaySettings() {
const language = useAppSelector(state => state.user.settings?.language)
const scrollSpeed = useAppSelector(state => state.user.settings?.scrollSpeed)
const showRead = useAppSelector(state => state.user.settings?.showRead)
const scrollMarks = useAppSelector(state => state.user.settings?.scrollMarks)
const scrollMode = useAppSelector(state => state.user.settings?.scrollMode)
const entriesToKeepOnTop = useAppSelector(state => state.user.settings?.entriesToKeepOnTopWhenScrolling)
const starIconDisplayMode = useAppSelector(state => state.user.settings?.starIconDisplayMode)
const externalLinkIconDisplayMode = useAppSelector(state => state.user.settings?.externalLinkIconDisplayMode)
const markAllAsReadConfirmation = useAppSelector(state => state.user.settings?.markAllAsReadConfirmation)
const markAllAsReadNavigateToNextUnread = useAppSelector(state => state.user.settings?.markAllAsReadNavigateToNextUnread)
const customContextMenu = useAppSelector(state => state.user.settings?.customContextMenu)
const mobileFooter = useAppSelector(state => state.user.settings?.mobileFooter)
const unreadCountTitle = useAppSelector(state => state.user.settings?.unreadCountTitle)
const unreadCountFavicon = useAppSelector(state => state.user.settings?.unreadCountFavicon)
const disablePullToRefresh = useAppSelector(state => state.user.settings?.disablePullToRefresh)
const sharingSettings = useAppSelector(state => state.user.settings?.sharingSettings)
const primaryColor = useAppSelector(state => state.user.settings?.primaryColor) || Constants.theme.defaultPrimaryColor
const settings = useAppSelector(state => state.user.settings)
const { _ } = useLingui()
const dispatch = useAppDispatch()
@@ -108,50 +75,51 @@ export function DisplaySettings() {
</Group>
)
if (!settings) return <Loader />
return (
<Stack>
<Divider label={<Trans>Display</Trans>} labelPosition="center" />
<Select
label={<Trans>Language</Trans>}
value={language}
value={settings.language}
data={locales.map(l => ({
value: l.key,
label: l.label,
}))}
onChange={async s => await (s && dispatch(changeLanguage(s)))}
onChange={language => language && dispatch(changeSettings({ language }))}
/>
<Select
label={<Trans>Primary color</Trans>}
data={colorData}
value={primaryColor}
onChange={async value => value && (await dispatch(changePrimaryColor(value)))}
value={settings.primaryColor}
onChange={primaryColor => primaryColor && dispatch(changeSettings({ primaryColor }))}
renderOption={colorRenderer}
/>
<Switch
label={<Trans>Show feeds and categories with no unread entries</Trans>}
checked={showRead}
onChange={async e => await dispatch(changeShowRead(e.currentTarget.checked))}
checked={settings.showRead}
onChange={e => dispatch(changeSettings({ showRead: e.currentTarget.checked }))}
/>
<Switch
label={<Trans>Show confirmation when marking all entries as read</Trans>}
checked={markAllAsReadConfirmation}
onChange={async e => await dispatch(changeMarkAllAsReadConfirmation(e.currentTarget.checked))}
checked={settings.markAllAsReadConfirmation}
onChange={e => dispatch(changeSettings({ markAllAsReadConfirmation: e.currentTarget.checked }))}
/>
<Switch
label={<Trans>Navigate to the next category/feed with unread entries when marking all entries as read</Trans>}
checked={markAllAsReadNavigateToNextUnread}
onChange={async e => await dispatch(changeMarkAllAsReadNavigateToUnread(e.currentTarget.checked))}
checked={settings.markAllAsReadNavigateToNextUnread}
onChange={e => dispatch(changeSettings({ markAllAsReadNavigateToNextUnread: e.currentTarget.checked }))}
/>
<Switch
label={<Trans>On mobile, show action buttons at the bottom of the screen</Trans>}
checked={mobileFooter}
onChange={async e => await dispatch(changeMobileFooter(e.currentTarget.checked))}
checked={settings.mobileFooter}
onChange={e => dispatch(changeSettings({ mobileFooter: e.currentTarget.checked }))}
/>
<Divider label={<Trans>Scrolling</Trans>} labelPosition="center" />
@@ -159,14 +127,14 @@ export function DisplaySettings() {
<Switch
label={<Trans>Disable "Pull to refresh" browser behavior</Trans>}
description={<Trans>This setting can cause scrolling issues on some browsers (e.g. Safari)</Trans>}
checked={disablePullToRefresh}
onChange={async e => await dispatch(changeDisablePullToRefresh(e.currentTarget.checked))}
checked={settings.disablePullToRefresh}
onChange={e => dispatch(changeSettings({ disablePullToRefresh: e.currentTarget.checked }))}
/>
<Radio.Group
label={<Trans>Scroll selected entry to the top of the page</Trans>}
value={scrollMode}
onChange={async value => await dispatch(changeScrollMode(value as ScrollMode))}
value={settings.scrollMode}
onChange={value => dispatch(changeSettings({ scrollMode: value }))}
>
<Group mt="xs">
{Object.entries(scrollModeOptions).map(e => (
@@ -179,56 +147,56 @@ export function DisplaySettings() {
label={<Trans>Entries to keep above the selected entry when scrolling</Trans>}
description={<Trans>Only applies to compact, cozy and detailed modes</Trans>}
min={0}
value={entriesToKeepOnTop}
onChange={async value => await dispatch(changeEntriesToKeepOnTopWhenScrolling(+value))}
value={settings.entriesToKeepOnTopWhenScrolling}
onChange={value => dispatch(changeSettings({ entriesToKeepOnTopWhenScrolling: +value }))}
/>
<Switch
label={<Trans>Scroll smoothly when navigating between entries</Trans>}
checked={scrollSpeed ? scrollSpeed > 0 : false}
onChange={async e => await dispatch(changeScrollSpeed(e.currentTarget.checked))}
checked={settings.scrollSpeed ? settings.scrollSpeed > 0 : false}
onChange={e => dispatch(changeSettings({ scrollSpeed: e.currentTarget.checked ? 400 : 0 }))}
/>
<Switch
label={<Trans>In expanded view, scrolling through entries mark them as read</Trans>}
checked={scrollMarks}
onChange={async e => await dispatch(changeScrollMarks(e.currentTarget.checked))}
checked={settings.scrollMarks}
onChange={e => dispatch(changeSettings({ scrollMarks: e.currentTarget.checked }))}
/>
<Divider label={<Trans>Browser tab</Trans>} labelPosition="center" />
<Switch
label={<Trans>Show unread count in tab title</Trans>}
checked={unreadCountTitle}
onChange={async e => await dispatch(changeUnreadCountTitle(e.currentTarget.checked))}
checked={settings.unreadCountTitle}
onChange={e => dispatch(changeSettings({ unreadCountTitle: e.currentTarget.checked }))}
/>
<Switch
label={<Trans>Show unread count in tab favicon</Trans>}
checked={unreadCountFavicon}
onChange={async e => await dispatch(changeUnreadCountFavicon(e.currentTarget.checked))}
checked={settings.unreadCountFavicon}
onChange={e => dispatch(changeSettings({ unreadCountFavicon: e.currentTarget.checked }))}
/>
<Divider label={<Trans>Entry headers</Trans>} labelPosition="center" />
<Select
label={<Trans>Show star icon</Trans>}
value={starIconDisplayMode}
value={settings.starIconDisplayMode}
data={displayModeData}
onChange={async s => await dispatch(changeStarIconDisplayMode(s as IconDisplayMode))}
onChange={value => dispatch(changeSettings({ starIconDisplayMode: value as IconDisplayMode }))}
/>
<Select
label={<Trans>Show external link icon</Trans>}
value={externalLinkIconDisplayMode}
value={settings.externalLinkIconDisplayMode}
data={displayModeData}
onChange={async s => await dispatch(changeExternalLinkIconDisplayMode(s as IconDisplayMode))}
onChange={value => dispatch(changeSettings({ externalLinkIconDisplayMode: value as IconDisplayMode }))}
/>
<Switch
label={<Trans>Show CommaFeed's own context menu on right click</Trans>}
checked={customContextMenu}
onChange={async e => await dispatch(changeCustomContextMenu(e.currentTarget.checked))}
checked={settings.customContextMenu}
onChange={e => dispatch(changeSettings({ customContextMenu: e.currentTarget.checked }))}
/>
<Divider label={<Trans>Sharing sites</Trans>} labelPosition="center" />
@@ -238,12 +206,14 @@ export function DisplaySettings() {
<Switch
key={site}
label={Constants.sharing[site].label}
checked={sharingSettings?.[site]}
onChange={async e =>
await dispatch(
changeSharingSetting({
site,
value: e.currentTarget.checked,
checked={settings.sharingSettings[site]}
onChange={e =>
dispatch(
changeSettings({
sharingSettings: {
...settings.sharingSettings,
[site]: e.currentTarget.checked,
},
})
)
}

View File

@@ -10,7 +10,7 @@ import { client, errorToStrings } from "@/app/client"
import { redirectToSelectedSource } from "@/app/redirect/thunks"
import { useAppDispatch, useAppSelector } from "@/app/store"
import type { PushNotificationSettings as PushNotificationSettingsModel } from "@/app/types"
import { changePushNotificationSettings } from "@/app/user/thunks"
import { changeSettings } from "@/app/user/thunks"
import { Alert } from "@/components/Alert"
export function PushNotificationSettings() {
@@ -25,7 +25,7 @@ export function PushNotificationSettings() {
}, [form.initialize, notificationSettings])
const handleSubmit = (values: PushNotificationSettingsModel) => {
dispatch(changePushNotificationSettings(values))
dispatch(changeSettings({ pushNotificationSettings: values }))
}
const sendTestPushNotification = useAsyncCallback(client.user.sendTestPushNotification)