pl-fe: backups, polls reducers
Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
This commit is contained in:
parent
0811af7ad7
commit
542ba9ab78
9 changed files with 64 additions and 41 deletions
|
@ -2765,8 +2765,6 @@ class PlApiClient {
|
|||
|
||||
return response.json as {};
|
||||
},
|
||||
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import { getClient } from '../api';
|
||||
|
||||
import type { Backup } from 'pl-api';
|
||||
import type { AppDispatch, RootState } from 'pl-fe/store';
|
||||
|
||||
const BACKUPS_FETCH_REQUEST = 'BACKUPS_FETCH_REQUEST' as const;
|
||||
|
@ -10,27 +11,63 @@ const BACKUPS_CREATE_REQUEST = 'BACKUPS_CREATE_REQUEST' as const;
|
|||
const BACKUPS_CREATE_SUCCESS = 'BACKUPS_CREATE_SUCCESS' as const;
|
||||
const BACKUPS_CREATE_FAIL = 'BACKUPS_CREATE_FAIL' as const;
|
||||
|
||||
interface BackupsFetchRequestAction {
|
||||
type: typeof BACKUPS_FETCH_REQUEST;
|
||||
}
|
||||
|
||||
interface BackupsFetchSuccessAction {
|
||||
type: typeof BACKUPS_FETCH_SUCCESS;
|
||||
backups: Array<Backup>;
|
||||
}
|
||||
|
||||
interface BackupsFetchFailAction {
|
||||
type: typeof BACKUPS_FETCH_FAIL;
|
||||
error: unknown;
|
||||
}
|
||||
|
||||
const fetchBackups = () =>
|
||||
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||
dispatch({ type: BACKUPS_FETCH_REQUEST });
|
||||
dispatch<BackupsFetchRequestAction>({ type: BACKUPS_FETCH_REQUEST });
|
||||
|
||||
return getClient(getState).settings.getBackups().then((backups) =>
|
||||
dispatch({ type: BACKUPS_FETCH_SUCCESS, backups }),
|
||||
dispatch<BackupsFetchSuccessAction>({ type: BACKUPS_FETCH_SUCCESS, backups }),
|
||||
).catch(error => {
|
||||
dispatch({ type: BACKUPS_FETCH_FAIL, error });
|
||||
dispatch<BackupsFetchFailAction>({ type: BACKUPS_FETCH_FAIL, error });
|
||||
});
|
||||
};
|
||||
|
||||
interface BackupsCreateRequestAction {
|
||||
type: typeof BACKUPS_CREATE_REQUEST;
|
||||
}
|
||||
|
||||
interface BackupsCreateSuccessAction {
|
||||
type: typeof BACKUPS_CREATE_SUCCESS;
|
||||
backups: Array<Backup>;
|
||||
}
|
||||
|
||||
interface BackupsCreateFailAction {
|
||||
type: typeof BACKUPS_CREATE_FAIL;
|
||||
error: unknown;
|
||||
}
|
||||
|
||||
const createBackup = () =>
|
||||
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||
dispatch({ type: BACKUPS_CREATE_REQUEST });
|
||||
return getClient(getState).settings.createBackup().then((backups) =>
|
||||
dispatch({ type: BACKUPS_CREATE_SUCCESS, backups }),
|
||||
dispatch<BackupsCreateRequestAction>({ type: BACKUPS_CREATE_REQUEST });
|
||||
return getClient(getState).settings.createBackup().then((backup) =>
|
||||
dispatch<BackupsCreateSuccessAction>({ type: BACKUPS_CREATE_SUCCESS, backups: [backup] }),
|
||||
).catch(error => {
|
||||
dispatch({ type: BACKUPS_CREATE_FAIL, error });
|
||||
dispatch<BackupsCreateFailAction>({ type: BACKUPS_CREATE_FAIL, error });
|
||||
});
|
||||
};
|
||||
|
||||
type BackupsAction =
|
||||
| BackupsFetchRequestAction
|
||||
| BackupsFetchSuccessAction
|
||||
| BackupsFetchFailAction
|
||||
| BackupsCreateRequestAction
|
||||
| BackupsCreateSuccessAction
|
||||
| BackupsCreateFailAction;
|
||||
|
||||
export {
|
||||
BACKUPS_FETCH_REQUEST,
|
||||
BACKUPS_FETCH_SUCCESS,
|
||||
|
@ -40,4 +77,5 @@ export {
|
|||
BACKUPS_CREATE_FAIL,
|
||||
fetchBackups,
|
||||
createBackup,
|
||||
type BackupsAction,
|
||||
};
|
||||
|
|
|
@ -76,7 +76,6 @@ const updateNotifications = (notification: BaseNotification) =>
|
|||
statuses: [getNotificationStatus(notification)],
|
||||
}));
|
||||
|
||||
|
||||
if (showInColumn) {
|
||||
const normalizedNotification = normalizeNotification(notification);
|
||||
|
||||
|
|
|
@ -97,7 +97,7 @@ const editStatus = (statusId: string) => (dispatch: AppDispatch, getState: () =>
|
|||
const state = getState();
|
||||
|
||||
const status = state.statuses[statusId]!;
|
||||
const poll = status.poll_id ? state.polls.get(status.poll_id) : undefined;
|
||||
const poll = status.poll_id ? state.polls[status.poll_id] : undefined;
|
||||
|
||||
dispatch({ type: STATUS_FETCH_SOURCE_REQUEST });
|
||||
|
||||
|
@ -134,7 +134,7 @@ const deleteStatus = (statusId: string, withRedraft = false) =>
|
|||
const state = getState();
|
||||
|
||||
const status = state.statuses[statusId]!;
|
||||
const poll = status.poll_id ? state.polls.get(status.poll_id) : undefined;
|
||||
const poll = status.poll_id ? state.polls[status.poll_id] : undefined;
|
||||
|
||||
dispatch({ type: STATUS_DELETE_REQUEST, params: status });
|
||||
|
||||
|
|
|
@ -30,7 +30,7 @@ const Poll: React.FC<IPoll> = ({ id, status }): JSX.Element | null => {
|
|||
const intl = useIntl();
|
||||
|
||||
const isLoggedIn = useAppSelector((state) => state.me);
|
||||
const poll = useAppSelector((state) => state.polls.get(id));
|
||||
const poll = useAppSelector((state) => state.polls[id]);
|
||||
|
||||
const [selected, setSelected] = useState({} as Selected);
|
||||
|
||||
|
|
|
@ -65,7 +65,7 @@ const Backups = () => {
|
|||
const intl = useIntl();
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
const backups = useAppSelector((state) => state.backups.toList().sortBy((backup) => backup.inserted_at));
|
||||
const backups = useAppSelector((state) => Object.values(state.backups).toSorted((a, b) => a.inserted_at.localeCompare(b.inserted_at)));
|
||||
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
|
||||
|
@ -80,7 +80,7 @@ const Backups = () => {
|
|||
}).catch(() => {});
|
||||
}, []);
|
||||
|
||||
const showLoading = isLoading && backups.count() === 0;
|
||||
const showLoading = isLoading && backups.length === 0;
|
||||
|
||||
const emptyMessage = (
|
||||
<Card variant='rounded' size='lg'>
|
||||
|
@ -96,11 +96,11 @@ const Backups = () => {
|
|||
</Card>
|
||||
);
|
||||
|
||||
const body = showLoading ? <Spinner /> : backups.isEmpty() ? emptyMessage : (
|
||||
const body = showLoading ? <Spinner /> : backups.length ? (
|
||||
<div className='mb-4 grid grid-cols-1 gap-4 sm:grid-cols-2'>
|
||||
{backups.map((backup) => <Backup key={backup.id} backup={backup} />)}
|
||||
</div>
|
||||
);
|
||||
) : emptyMessage;
|
||||
|
||||
return (
|
||||
<Column label={intl.formatMessage(messages.heading)}>
|
||||
|
|
|
@ -1,25 +1,18 @@
|
|||
import { Map as ImmutableMap } from 'immutable';
|
||||
import { create } from 'mutative';
|
||||
|
||||
import { BACKUPS_FETCH_SUCCESS, BACKUPS_CREATE_SUCCESS } from '../actions/backups';
|
||||
import { BACKUPS_FETCH_SUCCESS, BACKUPS_CREATE_SUCCESS, type BackupsAction } from '../actions/backups';
|
||||
|
||||
import type { Backup } from 'pl-api';
|
||||
import type { AnyAction } from 'redux';
|
||||
|
||||
type State = ImmutableMap<string, Backup>;
|
||||
type State = Record<string, Backup>;
|
||||
|
||||
const initialState: State = ImmutableMap();
|
||||
const initialState: State = {};
|
||||
|
||||
const importBackup = (state: State, backup: Backup) => state.set(backup.inserted_at, backup);
|
||||
|
||||
const importBackups = (state: State, backups: Array<Backup>) => state.withMutations(mutable => {
|
||||
backups.forEach(backup => importBackup(mutable, backup));
|
||||
});
|
||||
|
||||
const backups = (state = initialState, action: AnyAction) => {
|
||||
const backups = (state = initialState, action: BackupsAction) => {
|
||||
switch (action.type) {
|
||||
case BACKUPS_FETCH_SUCCESS:
|
||||
case BACKUPS_CREATE_SUCCESS:
|
||||
return importBackups(state, action.backups);
|
||||
return create(state, (draft) => action.backups.forEach((backup) => draft[backup.inserted_at] = backup));
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
|
|
|
@ -1,22 +1,17 @@
|
|||
import { Map as ImmutableMap } from 'immutable';
|
||||
import { create } from 'mutative';
|
||||
|
||||
import { POLLS_IMPORT, type ImporterAction } from 'pl-fe/actions/importer';
|
||||
|
||||
import type { Poll, Status } from 'pl-api';
|
||||
import type { Poll } from 'pl-api';
|
||||
|
||||
type State = ImmutableMap<string, Poll>;
|
||||
type State = Record<string, Poll>;
|
||||
|
||||
const importPolls = (state: State, polls: Array<Exclude<Status['poll'], null>>) =>
|
||||
state.withMutations(map =>
|
||||
polls.forEach(poll => map.set(poll.id, poll)),
|
||||
);
|
||||
|
||||
const initialState: State = ImmutableMap();
|
||||
const initialState: State = {};
|
||||
|
||||
const polls = (state: State = initialState, action: ImporterAction): State => {
|
||||
switch (action.type) {
|
||||
case POLLS_IMPORT:
|
||||
return importPolls(state, action.polls);
|
||||
return create(state, (draft) => action.polls.forEach(poll => draft[poll.id] = poll));
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
|
|
|
@ -135,7 +135,7 @@ const makeGetStatus = () => createSelector(
|
|||
if (group) return state.entities[Entities.GROUPS]?.store[group] as Group;
|
||||
return undefined;
|
||||
},
|
||||
(state: RootState, { id }: APIStatus) => state.polls.get(id) || null,
|
||||
(state: RootState, { id }: APIStatus) => state.polls[id] || null,
|
||||
(_state: RootState, { username }: APIStatus) => username,
|
||||
getFilters,
|
||||
(state: RootState) => state.me,
|
||||
|
|
Loading…
Reference in a new issue