307 lines
6.4 KiB
TypeScript
Raw Normal View History

2022-10-20 11:57:30 -04:00
import get from 'lodash/get';
import isEqual from 'lodash/isEqual';
import { v4 as uuid } from 'uuid';
import {
ADD_DRAFT_ENTRY_MEDIA_FILE,
DRAFT_CHANGE_FIELD,
DRAFT_CREATE_DUPLICATE_FROM_ENTRY,
DRAFT_CREATE_EMPTY,
DRAFT_CREATE_FROM_ENTRY,
DRAFT_CREATE_FROM_LOCAL_BACKUP,
DRAFT_DISCARD,
DRAFT_LOCAL_BACKUP_DELETE,
DRAFT_LOCAL_BACKUP_RETRIEVED,
DRAFT_VALIDATION_ERRORS,
ENTRY_DELETE_SUCCESS,
ENTRY_PERSIST_FAILURE,
ENTRY_PERSIST_REQUEST,
ENTRY_PERSIST_SUCCESS,
REMOVE_DRAFT_ENTRY_MEDIA_FILE,
} from '../constants';
2022-10-20 11:57:30 -04:00
import { duplicateI18nFields, getDataPath } from '../lib/i18n';
import { set } from '../lib/util/object.util';
import type { EntriesAction } from '../actions/entries';
import type { Entry, FieldsErrors } from '../interface';
export interface EntryDraftState {
original?: Entry;
2022-10-20 11:57:30 -04:00
entry?: Entry;
fieldsErrors: FieldsErrors;
hasChanged: boolean;
key: string;
localBackup?: {
entry: Entry;
};
}
const initialState: EntryDraftState = {
fieldsErrors: {},
hasChanged: false,
key: '',
};
function entryDraftReducer(
state: EntryDraftState = initialState,
action: EntriesAction,
): EntryDraftState {
switch (action.type) {
case DRAFT_CREATE_FROM_ENTRY: {
const newState = { ...state };
const entry: Entry = {
...action.payload.entry,
newRecord: false,
};
2022-10-20 11:57:30 -04:00
// Existing Entry
return {
...newState,
entry,
original: entry,
2022-10-20 11:57:30 -04:00
fieldsErrors: {},
hasChanged: false,
key: uuid(),
};
}
case DRAFT_CREATE_EMPTY: {
const newState = { ...state };
delete newState.localBackup;
const entry: Entry = {
...action.payload,
newRecord: true,
};
2022-10-20 11:57:30 -04:00
// New Entry
return {
...newState,
entry,
original: entry,
2022-10-20 11:57:30 -04:00
fieldsErrors: {},
hasChanged: false,
key: uuid(),
};
}
case DRAFT_CREATE_FROM_LOCAL_BACKUP: {
const backupDraftEntry = state.localBackup;
if (!backupDraftEntry) {
return state;
}
const backupEntry = backupDraftEntry?.['entry'];
const newState = { ...state };
delete newState.localBackup;
const entry: Entry = {
...backupEntry,
newRecord: !backupEntry?.path,
};
2022-10-20 11:57:30 -04:00
// Local Backup
return {
...state,
entry,
original: entry,
2022-10-20 11:57:30 -04:00
fieldsErrors: {},
hasChanged: true,
key: uuid(),
};
}
case DRAFT_CREATE_DUPLICATE_FROM_ENTRY: {
const newState = { ...state };
delete newState.localBackup;
const entry: Entry = {
...action.payload,
newRecord: true,
};
2022-10-20 11:57:30 -04:00
// Duplicate Entry
return {
...newState,
entry,
original: entry,
2022-10-20 11:57:30 -04:00
fieldsErrors: {},
hasChanged: true,
};
}
case DRAFT_DISCARD:
return initialState;
case DRAFT_LOCAL_BACKUP_RETRIEVED: {
const { entry } = action.payload;
const newState = {
entry,
};
return {
...state,
localBackup: newState,
};
}
case DRAFT_LOCAL_BACKUP_DELETE: {
const newState = { ...state };
delete newState.localBackup;
return newState;
}
case DRAFT_CHANGE_FIELD: {
let newState = { ...state };
if (!newState.entry) {
return state;
}
const { path, field, value, i18n } = action.payload;
2022-10-20 11:57:30 -04:00
const dataPath = (i18n && getDataPath(i18n.currentLocale, i18n.defaultLocale)) || ['data'];
newState = {
...newState,
entry: set(newState.entry, `${dataPath.join('.')}.${path}`, value),
};
if (i18n) {
newState = duplicateI18nFields(newState, field, i18n.locales, i18n.defaultLocale);
}
const newData = get(newState.entry, dataPath) ?? {};
return {
...newState,
hasChanged: !newState.original || !isEqual(newData, get(newState.original, dataPath)),
2022-10-20 11:57:30 -04:00
};
}
case DRAFT_VALIDATION_ERRORS: {
2023-01-18 15:08:40 -05:00
const { path, errors, i18n } = action.payload;
2022-10-20 11:57:30 -04:00
const fieldsErrors = { ...state.fieldsErrors };
2023-01-18 15:08:40 -05:00
const dataPath = (i18n && getDataPath(i18n.currentLocale, i18n.defaultLocale)) || ['data'];
const fullPath = `${dataPath.join('.')}.${path}`;
2022-10-20 11:57:30 -04:00
if (errors.length === 0) {
2023-01-18 15:08:40 -05:00
delete fieldsErrors[fullPath];
2022-10-20 11:57:30 -04:00
} else {
2023-01-18 15:08:40 -05:00
fieldsErrors[fullPath] = action.payload.errors;
2022-10-20 11:57:30 -04:00
}
return {
...state,
fieldsErrors,
};
}
case ENTRY_PERSIST_REQUEST: {
if (!state.entry) {
return state;
}
return {
...state,
entry: {
...state.entry,
isPersisting: true,
},
};
}
case ENTRY_PERSIST_FAILURE: {
if (!state.entry) {
return state;
}
return {
...state,
entry: {
...state.entry,
isPersisting: false,
},
};
}
case ENTRY_PERSIST_SUCCESS: {
if (!state.entry) {
return state;
}
const newState = { ...state };
delete newState.localBackup;
const entry: Entry = {
...state.entry,
slug: action.payload.slug,
isPersisting: false,
};
2022-10-20 11:57:30 -04:00
return {
...newState,
hasChanged: false,
entry,
original: entry,
2022-10-20 11:57:30 -04:00
};
}
case ENTRY_DELETE_SUCCESS: {
if (!state.entry) {
return state;
}
const newState = { ...state };
delete newState.localBackup;
const entry: Entry = {
...state.entry,
isPersisting: false,
};
2022-10-20 11:57:30 -04:00
return {
...newState,
hasChanged: false,
entry,
2022-12-01 13:09:45 -05:00
original: entry,
2022-10-20 11:57:30 -04:00
};
}
case ADD_DRAFT_ENTRY_MEDIA_FILE: {
if (!state.entry) {
return state;
}
const mediaFiles = state.entry.mediaFiles.filter(file => file.id !== action.payload.id);
mediaFiles.unshift(action.payload);
return {
...state,
hasChanged: true,
entry: {
...state.entry,
mediaFiles,
},
};
}
case REMOVE_DRAFT_ENTRY_MEDIA_FILE: {
if (!state.entry) {
return state;
}
const mediaFiles = state.entry.mediaFiles.filter(file => file.id !== action.payload.id);
return {
...state,
hasChanged: true,
entry: {
...state.entry,
mediaFiles,
},
};
}
default:
return state;
}
}
export default entryDraftReducer;