mirror of
https://github.com/usatiuk/writer.git
synced 2025-10-29 00:17:48 +01:00
128 lines
4.2 KiB
TypeScript
128 lines
4.2 KiB
TypeScript
import { Reducer } from "react";
|
|
import { IDocumentJSON } from "~../../src/entity/Document";
|
|
import { UserAction, UserTypes } from "~redux/user/actions";
|
|
|
|
import { DocsAction, DocsTypes } from "./actions";
|
|
|
|
export interface IDocumentEntry extends IDocumentJSON {
|
|
remote: IDocumentJSON;
|
|
dirty: boolean;
|
|
}
|
|
|
|
export interface IDocsState {
|
|
all: { [key: number]: IDocumentEntry };
|
|
dirty: boolean;
|
|
|
|
fetching: boolean;
|
|
uploading: boolean;
|
|
error: string | null;
|
|
spinner: boolean;
|
|
|
|
newDocumentID: number | null;
|
|
|
|
deletedDocument: IDocumentEntry | null;
|
|
}
|
|
|
|
const defaultDocsState: IDocsState = {
|
|
all: null,
|
|
dirty: false,
|
|
fetching: false,
|
|
uploading: false,
|
|
error: null,
|
|
spinner: false,
|
|
newDocumentID: null,
|
|
deletedDocument: null,
|
|
};
|
|
|
|
export const docsReducer: Reducer<IDocsState, DocsAction> = (
|
|
state: IDocsState = defaultDocsState,
|
|
action: DocsAction | UserAction,
|
|
) => {
|
|
switch (action.type) {
|
|
case DocsTypes.DOCS_SHOW_SPINNER:
|
|
return { ...state, spinner: true };
|
|
case DocsTypes.DOCS_FETCH_START:
|
|
return { ...defaultDocsState, fetching: true };
|
|
case DocsTypes.DOCS_FETCH_SUCCESS: {
|
|
const all: { [key: number]: IDocumentEntry } = {};
|
|
action.payload.all.forEach(doc => {
|
|
all[doc.id] = { ...doc, remote: doc, dirty: false };
|
|
});
|
|
return { ...defaultDocsState, all };
|
|
}
|
|
case DocsTypes.DOC_NEW_SUCCESS: {
|
|
const all = { ...state.all };
|
|
const doc = action.payload.doc;
|
|
all[doc.id] = { ...doc, remote: doc, dirty: false };
|
|
return { ...state, all, newDocumentID: doc.id };
|
|
}
|
|
case DocsTypes.DOC_NEW_RESET: {
|
|
return { ...state, newDocumentID: null };
|
|
}
|
|
case DocsTypes.DOC_DELETE_START: {
|
|
const doc = { ...state.all[action.id] };
|
|
const all = { ...state.all };
|
|
delete all[action.id];
|
|
return { ...state, deletedDocument: doc, all };
|
|
}
|
|
case DocsTypes.DOC_DELETE_SUCCESS: {
|
|
return { ...state, deletedDocument: null };
|
|
}
|
|
case DocsTypes.DOC_DELETE_CANCEL: {
|
|
const deletedDocument = { ...state.deletedDocument };
|
|
const all = { ...state.all };
|
|
all[deletedDocument.id] = deletedDocument;
|
|
return { ...state, deletedDocument: null, all };
|
|
}
|
|
case DocsTypes.DOCS_UPLOAD_START: {
|
|
return { ...state, uploading: true };
|
|
}
|
|
case DocsTypes.DOCS_UPLOAD_FAIL: {
|
|
return { ...state, uploading: false };
|
|
}
|
|
case DocsTypes.DOCS_UPLOAD_SUCCESS: {
|
|
const all: { [key: number]: IDocumentEntry } = { ...state.all };
|
|
action.payload.all.forEach(doc => {
|
|
all[doc.id] = { ...doc, remote: doc, dirty: false };
|
|
});
|
|
return { ...state, all, uploading: false, dirty: false };
|
|
}
|
|
case DocsTypes.DOCS_FETCH_FAIL:
|
|
return { ...defaultDocsState, ...action.payload };
|
|
case UserTypes.USER_LOGOUT:
|
|
return defaultDocsState;
|
|
case DocsTypes.DOC_UPDATE: {
|
|
const all = { ...state.all };
|
|
let dirty = state.dirty;
|
|
const { payload } = action;
|
|
const doc = all[payload.id];
|
|
const remote = doc.remote;
|
|
if (
|
|
payload.content !== remote.content ||
|
|
payload.name !== remote.name
|
|
) {
|
|
all[payload.id] = {
|
|
...doc,
|
|
content: payload.content,
|
|
name: payload.name,
|
|
dirty: true,
|
|
};
|
|
dirty = true;
|
|
} else {
|
|
all[payload.id] = {
|
|
...doc,
|
|
content: payload.content,
|
|
name: payload.name,
|
|
dirty: false,
|
|
};
|
|
const dirtyDocs = Object.values(all).filter(e => e.dirty);
|
|
dirty = dirtyDocs.length > 0;
|
|
}
|
|
return { ...state, all, dirty };
|
|
}
|
|
default:
|
|
return state;
|
|
break;
|
|
}
|
|
};
|