pl-fe: Complete migration of settings store
Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
This commit is contained in:
parent
e4615b70f7
commit
97d1ce2f47
12 changed files with 51 additions and 110 deletions
|
@ -294,14 +294,14 @@ const scrollTopNotifications = (top: boolean) =>
|
||||||
|
|
||||||
const setFilter = (filterType: FilterType, abort?: boolean) =>
|
const setFilter = (filterType: FilterType, abort?: boolean) =>
|
||||||
(dispatch: AppDispatch) => {
|
(dispatch: AppDispatch) => {
|
||||||
const activeFilter = useSettingsStore.getState().settings.notifications.quickFilter.active as FilterType;
|
const settingsStore = useSettingsStore.getState();
|
||||||
|
const activeFilter = settingsStore.settings.notifications.quickFilter.active as FilterType;
|
||||||
|
|
||||||
dispatch({
|
settingsStore.changeSetting(['notifications', 'quickFilter', 'active'], filterType);
|
||||||
type: NOTIFICATIONS_FILTER_SET,
|
|
||||||
path: ['notifications', 'quickFilter', 'active'],
|
dispatch({ type: NOTIFICATIONS_FILTER_SET });
|
||||||
value: filterType,
|
|
||||||
});
|
|
||||||
dispatch(expandNotifications(undefined, undefined, abort));
|
dispatch(expandNotifications(undefined, undefined, abort));
|
||||||
|
|
||||||
if (activeFilter !== filterType) dispatch(saveSettings());
|
if (activeFilter !== filterType) dispatch(saveSettings());
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
import { useSettingsStore } from 'pl-fe/stores/settings';
|
||||||
|
|
||||||
import { getClient } from '../api';
|
import { getClient } from '../api';
|
||||||
|
|
||||||
import { fetchRelationships } from './accounts';
|
import { fetchRelationships } from './accounts';
|
||||||
|
@ -88,9 +90,10 @@ const setFilter = (value: string, filterType: SearchFilter) =>
|
||||||
(dispatch: AppDispatch) => {
|
(dispatch: AppDispatch) => {
|
||||||
dispatch(submitSearch(value, filterType));
|
dispatch(submitSearch(value, filterType));
|
||||||
|
|
||||||
|
useSettingsStore.getState().changeSetting(['search', 'filter'], filterType);
|
||||||
|
|
||||||
return dispatch({
|
return dispatch({
|
||||||
type: SEARCH_FILTER_SET,
|
type: SEARCH_FILTER_SET,
|
||||||
path: ['search', 'filter'],
|
|
||||||
value: filterType,
|
value: filterType,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
|
@ -11,8 +11,6 @@ import { isLoggedIn } from 'pl-fe/utils/auth';
|
||||||
|
|
||||||
import type { AppDispatch, RootState } from 'pl-fe/store';
|
import type { AppDispatch, RootState } from 'pl-fe/store';
|
||||||
|
|
||||||
const SETTING_CHANGE = 'SETTING_CHANGE' as const;
|
|
||||||
|
|
||||||
const FE_NAME = 'pl_fe';
|
const FE_NAME = 'pl_fe';
|
||||||
|
|
||||||
const getAccount = makeGetAccount();
|
const getAccount = makeGetAccount();
|
||||||
|
@ -129,33 +127,9 @@ const saveSuccessMessage = defineMessage({ id: 'settings.save.success', defaultM
|
||||||
// }),
|
// }),
|
||||||
// });
|
// });
|
||||||
|
|
||||||
interface SettingChangeAction {
|
|
||||||
type: typeof SETTING_CHANGE;
|
|
||||||
path: string[];
|
|
||||||
value: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
const changeSettingImmediate = (path: string[], value: any, opts?: SettingOpts) =>
|
|
||||||
(dispatch: AppDispatch) => {
|
|
||||||
const action: SettingChangeAction = {
|
|
||||||
type: SETTING_CHANGE,
|
|
||||||
path,
|
|
||||||
value,
|
|
||||||
};
|
|
||||||
|
|
||||||
dispatch(action);
|
|
||||||
dispatch(saveSettings(opts));
|
|
||||||
};
|
|
||||||
|
|
||||||
const changeSetting = (path: string[], value: any, opts?: SettingOpts) =>
|
const changeSetting = (path: string[], value: any, opts?: SettingOpts) =>
|
||||||
(dispatch: AppDispatch) => {
|
(dispatch: AppDispatch) => {
|
||||||
const action: SettingChangeAction = {
|
useSettingsStore.getState().changeSetting(path, value);
|
||||||
type: SETTING_CHANGE,
|
|
||||||
path,
|
|
||||||
value,
|
|
||||||
};
|
|
||||||
|
|
||||||
dispatch(action);
|
|
||||||
return dispatch(saveSettings(opts));
|
return dispatch(saveSettings(opts));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -214,16 +188,10 @@ const getLocale = (fallback = 'en') => {
|
||||||
return Object.keys(messages).includes(localeWithVariant) ? localeWithVariant : Object.keys(messages).includes(locale) ? locale : fallback;
|
return Object.keys(messages).includes(localeWithVariant) ? localeWithVariant : Object.keys(messages).includes(locale) ? locale : fallback;
|
||||||
};
|
};
|
||||||
|
|
||||||
type SettingsAction =
|
|
||||||
| SettingChangeAction
|
|
||||||
|
|
||||||
export {
|
export {
|
||||||
SETTING_CHANGE,
|
|
||||||
FE_NAME,
|
FE_NAME,
|
||||||
changeSettingImmediate,
|
|
||||||
changeSetting,
|
changeSetting,
|
||||||
saveSettings,
|
saveSettings,
|
||||||
updateSettingsStore,
|
updateSettingsStore,
|
||||||
getLocale,
|
getLocale,
|
||||||
type SettingsAction,
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
import { FormattedMessage, defineMessages, useIntl } from 'react-intl';
|
import { FormattedMessage, defineMessages, useIntl } from 'react-intl';
|
||||||
|
|
||||||
import { changeSettingImmediate } from 'pl-fe/actions/settings';
|
import { changeSetting } from 'pl-fe/actions/settings';
|
||||||
import { Column, Button, Form, FormActions, FormGroup, Input, Text } from 'pl-fe/components/ui';
|
import { Column, Button, Form, FormActions, FormGroup, Input, Text } from 'pl-fe/components/ui';
|
||||||
import { useAppDispatch } from 'pl-fe/hooks';
|
import { useAppDispatch } from 'pl-fe/hooks';
|
||||||
import toast from 'pl-fe/toast';
|
import toast from 'pl-fe/toast';
|
||||||
|
@ -26,7 +26,7 @@ const DevelopersChallenge = () => {
|
||||||
|
|
||||||
const handleSubmit = () => {
|
const handleSubmit = () => {
|
||||||
if (answer === 'fe-pl') {
|
if (answer === 'fe-pl') {
|
||||||
dispatch(changeSettingImmediate(['isDeveloper'], true));
|
dispatch(changeSetting(['isDeveloper'], true));
|
||||||
toast.success(intl.formatMessage(messages.success));
|
toast.success(intl.formatMessage(messages.success));
|
||||||
} else {
|
} else {
|
||||||
toast.error(intl.formatMessage(messages.fail));
|
toast.error(intl.formatMessage(messages.fail));
|
||||||
|
|
|
@ -2,7 +2,7 @@ import React from 'react';
|
||||||
import { FormattedMessage, defineMessages, useIntl } from 'react-intl';
|
import { FormattedMessage, defineMessages, useIntl } from 'react-intl';
|
||||||
import { Link, useHistory } from 'react-router-dom';
|
import { Link, useHistory } from 'react-router-dom';
|
||||||
|
|
||||||
import { changeSettingImmediate } from 'pl-fe/actions/settings';
|
import { changeSetting } from 'pl-fe/actions/settings';
|
||||||
import { Column, Text } from 'pl-fe/components/ui';
|
import { Column, Text } from 'pl-fe/components/ui';
|
||||||
import SvgIcon from 'pl-fe/components/ui/icon/svg-icon';
|
import SvgIcon from 'pl-fe/components/ui/icon/svg-icon';
|
||||||
import { useAppDispatch } from 'pl-fe/hooks';
|
import { useAppDispatch } from 'pl-fe/hooks';
|
||||||
|
@ -38,7 +38,7 @@ const Developers: React.FC = () => {
|
||||||
const leaveDevelopers = (e: React.MouseEvent<HTMLButtonElement>) => {
|
const leaveDevelopers = (e: React.MouseEvent<HTMLButtonElement>) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
dispatch(changeSettingImmediate(['isDeveloper'], false));
|
dispatch(changeSetting(['isDeveloper'], false));
|
||||||
toast.success(intl.formatMessage(messages.leave));
|
toast.success(intl.formatMessage(messages.leave));
|
||||||
history.push('/');
|
history.push('/');
|
||||||
};
|
};
|
||||||
|
|
|
@ -22,8 +22,8 @@ const STATUS_TYPE_ICONS: Record<string, string> = {
|
||||||
direct: require('@tabler/icons/outline/mail.svg'),
|
direct: require('@tabler/icons/outline/mail.svg'),
|
||||||
private: require('@tabler/icons/outline/lock.svg'),
|
private: require('@tabler/icons/outline/lock.svg'),
|
||||||
mutuals_only: require('@tabler/icons/outline/users-group.svg'),
|
mutuals_only: require('@tabler/icons/outline/users-group.svg'),
|
||||||
local: require('@tabler/icons/outline/affiliate.svg'),
|
local: require('@tabler/icons/outline/affiliate.svg'),
|
||||||
list: require('@tabler/icons/outline/list.svg'),
|
list: require('@tabler/icons/outline/list.svg'),
|
||||||
};
|
};
|
||||||
|
|
||||||
const StatusTypeIcon: React.FC<IStatusTypeIcon> = ({ status }) => {
|
const StatusTypeIcon: React.FC<IStatusTypeIcon> = ({ status }) => {
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
* globals: do things through the console.
|
* globals: do things through the console.
|
||||||
* This feature is for developers.
|
* This feature is for developers.
|
||||||
*/
|
*/
|
||||||
import { changeSettingImmediate } from 'pl-fe/actions/settings';
|
import { changeSetting } from 'pl-fe/actions/settings';
|
||||||
|
|
||||||
import type { Store } from 'pl-fe/store';
|
import type { Store } from 'pl-fe/store';
|
||||||
|
|
||||||
|
@ -14,7 +14,7 @@ const createGlobals = (store: Store) => {
|
||||||
if (![true, false].includes(bool)) {
|
if (![true, false].includes(bool)) {
|
||||||
throw `Invalid option ${bool}. Must be true or false.`;
|
throw `Invalid option ${bool}. Must be true or false.`;
|
||||||
}
|
}
|
||||||
store.dispatch(changeSettingImmediate(['isDeveloper'], bool) as any);
|
store.dispatch(changeSetting(['isDeveloper'], bool) as any);
|
||||||
return bool;
|
return bool;
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
|
@ -62,7 +62,7 @@ import {
|
||||||
} from '../actions/compose';
|
} from '../actions/compose';
|
||||||
import { EVENT_COMPOSE_CANCEL, EVENT_FORM_SET, type EventsAction } from '../actions/events';
|
import { EVENT_COMPOSE_CANCEL, EVENT_FORM_SET, type EventsAction } from '../actions/events';
|
||||||
import { ME_FETCH_SUCCESS, ME_PATCH_SUCCESS, MeAction } from '../actions/me';
|
import { ME_FETCH_SUCCESS, ME_PATCH_SUCCESS, MeAction } from '../actions/me';
|
||||||
import { SETTING_CHANGE, FE_NAME, SettingsAction } from '../actions/settings';
|
import { FE_NAME } from '../actions/settings';
|
||||||
import { TIMELINE_DELETE, TimelineAction } from '../actions/timelines';
|
import { TIMELINE_DELETE, TimelineAction } from '../actions/timelines';
|
||||||
import { unescapeHTML } from '../utils/html';
|
import { unescapeHTML } from '../utils/html';
|
||||||
|
|
||||||
|
@ -263,17 +263,17 @@ const importAccount = (compose: Compose, account: CredentialAccount) => {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const updateSetting = (compose: Compose, path: string[], value: string) => {
|
// const updateSetting = (compose: Compose, path: string[], value: string) => {
|
||||||
const pathString = path.join(',');
|
// const pathString = path.join(',');
|
||||||
switch (pathString) {
|
// switch (pathString) {
|
||||||
case 'defaultPrivacy':
|
// case 'defaultPrivacy':
|
||||||
return compose.set('privacy', value);
|
// return compose.set('privacy', value);
|
||||||
case 'defaultContentType':
|
// case 'defaultContentType':
|
||||||
return compose.set('content_type', value);
|
// return compose.set('content_type', value);
|
||||||
default:
|
// default:
|
||||||
return compose;
|
// return compose;
|
||||||
}
|
// }
|
||||||
};
|
// };
|
||||||
|
|
||||||
const updateCompose = (state: State, key: string, updater: (compose: Compose) => Compose) =>
|
const updateCompose = (state: State, key: string, updater: (compose: Compose) => Compose) =>
|
||||||
state.update(key, state.get('default')!, updater);
|
state.update(key, state.get('default')!, updater);
|
||||||
|
@ -282,7 +282,7 @@ const initialState: State = ImmutableMap({
|
||||||
default: ReducerCompose({ idempotencyKey: crypto.randomUUID(), resetFileKey: getResetFileKey() }),
|
default: ReducerCompose({ idempotencyKey: crypto.randomUUID(), resetFileKey: getResetFileKey() }),
|
||||||
});
|
});
|
||||||
|
|
||||||
const compose = (state = initialState, action: ComposeAction | EventsAction | MeAction | SettingsAction | TimelineAction) => {
|
const compose = (state = initialState, action: ComposeAction | EventsAction | MeAction | TimelineAction) => {
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
case COMPOSE_TYPE_CHANGE:
|
case COMPOSE_TYPE_CHANGE:
|
||||||
return updateCompose(state, action.composeId, compose => compose.withMutations(map => {
|
return updateCompose(state, action.composeId, compose => compose.withMutations(map => {
|
||||||
|
@ -544,8 +544,8 @@ const compose = (state = initialState, action: ComposeAction | EventsAction | Me
|
||||||
case ME_FETCH_SUCCESS:
|
case ME_FETCH_SUCCESS:
|
||||||
case ME_PATCH_SUCCESS:
|
case ME_PATCH_SUCCESS:
|
||||||
return updateCompose(state, 'default', compose => importAccount(compose, action.me));
|
return updateCompose(state, 'default', compose => importAccount(compose, action.me));
|
||||||
case SETTING_CHANGE:
|
// case SETTING_CHANGE:
|
||||||
return updateCompose(state, 'default', compose => updateSetting(compose, action.path, action.value));
|
// return updateCompose(state, 'default', compose => updateSetting(compose, action.path, action.value));
|
||||||
case COMPOSE_EDITOR_STATE_SET:
|
case COMPOSE_EDITOR_STATE_SET:
|
||||||
return updateCompose(state, action.composeId, compose => compose
|
return updateCompose(state, action.composeId, compose => compose
|
||||||
.setIn(!compose.modified_language || compose.modified_language === compose.language ? ['editorState'] : ['editorStateMap', compose.modified_language], action.editorState as string)
|
.setIn(!compose.modified_language || compose.modified_language === compose.language ? ['editorState'] : ['editorStateMap', compose.modified_language], action.editorState as string)
|
||||||
|
|
|
@ -37,7 +37,6 @@ import push_notifications from './push-notifications';
|
||||||
import scheduled_statuses from './scheduled-statuses';
|
import scheduled_statuses from './scheduled-statuses';
|
||||||
import search from './search';
|
import search from './search';
|
||||||
import security from './security';
|
import security from './security';
|
||||||
// import settings from './settings';
|
|
||||||
import status_lists from './status-lists';
|
import status_lists from './status-lists';
|
||||||
import statuses from './statuses';
|
import statuses from './statuses';
|
||||||
import suggestions from './suggestions';
|
import suggestions from './suggestions';
|
||||||
|
@ -81,7 +80,6 @@ const reducers = {
|
||||||
scheduled_statuses,
|
scheduled_statuses,
|
||||||
search,
|
search,
|
||||||
security,
|
security,
|
||||||
// settings,
|
|
||||||
status_lists,
|
status_lists,
|
||||||
statuses,
|
statuses,
|
||||||
suggestions,
|
suggestions,
|
||||||
|
|
|
@ -1,11 +0,0 @@
|
||||||
import { Map as ImmutableMap } from 'immutable';
|
|
||||||
|
|
||||||
import reducer from './settings';
|
|
||||||
|
|
||||||
describe('settings reducer', () => {
|
|
||||||
it('should return the initial state', () => {
|
|
||||||
expect(reducer(undefined, {} as any)).toEqual(ImmutableMap({
|
|
||||||
saved: true,
|
|
||||||
}));
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -1,34 +0,0 @@
|
||||||
import { produce } from 'immer';
|
|
||||||
import { AnyAction } from 'redux';
|
|
||||||
|
|
||||||
import { settingsSchema, type Settings } from 'pl-fe/schemas/pl-fe/settings';
|
|
||||||
|
|
||||||
import { NOTIFICATIONS_FILTER_SET } from '../actions/notifications';
|
|
||||||
import { SEARCH_FILTER_SET } from '../actions/search';
|
|
||||||
import { SETTING_CHANGE } from '../actions/settings';
|
|
||||||
|
|
||||||
type State = Partial<Settings>;
|
|
||||||
|
|
||||||
// Default settings are in action/settings.js
|
|
||||||
//
|
|
||||||
// Settings should be accessed with `getSettings(getState()).getIn(...)`
|
|
||||||
// instead of directly from the state.
|
|
||||||
const settings = (
|
|
||||||
state: State = settingsSchema.partial().parse({}),
|
|
||||||
action: AnyAction,
|
|
||||||
): State => {
|
|
||||||
switch (action.type) {
|
|
||||||
case NOTIFICATIONS_FILTER_SET:
|
|
||||||
case SEARCH_FILTER_SET:
|
|
||||||
case SETTING_CHANGE:
|
|
||||||
return produce(state, draft => {
|
|
||||||
// @ts-ignore
|
|
||||||
draft[action.path] = action.value;
|
|
||||||
draft.saved = false;
|
|
||||||
});
|
|
||||||
default:
|
|
||||||
return state;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
export { settings as default };
|
|
|
@ -17,10 +17,21 @@ type State = {
|
||||||
loadDefaultSettings: (settings: APIEntity) => void;
|
loadDefaultSettings: (settings: APIEntity) => void;
|
||||||
loadUserSettings: (settings: APIEntity) => void;
|
loadUserSettings: (settings: APIEntity) => void;
|
||||||
userSettingsSaving: () => void;
|
userSettingsSaving: () => void;
|
||||||
|
changeSetting: (path: string[], value: any) => void;
|
||||||
rememberEmojiUse: (emoji: Emoji) => void;
|
rememberEmojiUse: (emoji: Emoji) => void;
|
||||||
rememberLanguageUse: (language: string) => void;
|
rememberLanguageUse: (language: string) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const changeSetting = (object: APIEntity, path: string[], value: any) => {
|
||||||
|
if (path.length === 1) {
|
||||||
|
object[path[0]] = value;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof object[path[0]] !== 'object') object[path[0]] = {};
|
||||||
|
return changeSetting(object[path[0]], path.slice(1), value);
|
||||||
|
};
|
||||||
|
|
||||||
const mergeSettings = (state: State) => state.settings = { ...state.defaultSettings, ...state.userSettings };
|
const mergeSettings = (state: State) => state.settings = { ...state.defaultSettings, ...state.userSettings };
|
||||||
|
|
||||||
const useSettingsStore = create<State>((set) => ({
|
const useSettingsStore = create<State>((set) => ({
|
||||||
|
@ -49,6 +60,12 @@ const useSettingsStore = create<State>((set) => ({
|
||||||
mergeSettings(state);
|
mergeSettings(state);
|
||||||
})),
|
})),
|
||||||
|
|
||||||
|
changeSetting: (path: string[], value: any) => set(produce((state: State) => {
|
||||||
|
changeSetting(state.userSettings, path, value);
|
||||||
|
|
||||||
|
mergeSettings(state);
|
||||||
|
})),
|
||||||
|
|
||||||
rememberEmojiUse: (emoji: Emoji) => set(produce((state: State) => {
|
rememberEmojiUse: (emoji: Emoji) => set(produce((state: State) => {
|
||||||
const settings = state.userSettings;
|
const settings = state.userSettings;
|
||||||
if (!settings.frequentlyUsedEmojis) settings.frequentlyUsedEmojis = {};
|
if (!settings.frequentlyUsedEmojis) settings.frequentlyUsedEmojis = {};
|
||||||
|
|
Loading…
Reference in a new issue