react-simple-crud-ui
Version:
Written in React with hooks, simple CRUD UI with authentication.
571 lines (545 loc) • 27.5 kB
JavaScript
function ___$insertStyle(css) {
if (!css) {
return;
}
if (typeof window === 'undefined') {
return;
}
var style = document.createElement('style');
style.setAttribute('type', 'text/css');
style.innerHTML = css;
document.head.appendChild(style);
return css;
}
Object.defineProperty(exports, '__esModule', { value: true });
function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }
var React = require('react');
var React__default = _interopDefault(React);
var reactBootstrap = require('react-bootstrap');
var reactConfirmAlert = require('react-confirm-alert');
require('react-confirm-alert/src/react-confirm-alert.css');
var Axios = _interopDefault(require('axios'));
/*! *****************************************************************************
Copyright (c) Microsoft Corporation. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License"); you may not use
this file except in compliance with the License. You may obtain a copy of the
License at http://www.apache.org/licenses/LICENSE-2.0
THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
MERCHANTABLITY OR NON-INFRINGEMENT.
See the Apache Version 2.0 License for specific language governing permissions
and limitations under the License.
***************************************************************************** */
var __assign = function() {
__assign = Object.assign || function __assign(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];
}
return t;
};
return __assign.apply(this, arguments);
};
function __spreadArrays() {
for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length;
for (var r = Array(s), k = 0, i = 0; i < il; i++)
for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++)
r[k] = a[j];
return r;
}
var AuthSettingModel = /** @class */ (function () {
function AuthSettingModel(app, components, login) {
this.app = app;
this.components = components;
this.login = login;
}
return AuthSettingModel;
}());
var CrudSettingModel = /** @class */ (function () {
function CrudSettingModel(initialCrudState, Form, ListGenerator, filterFn, loadAllData, addCrud, loadOneCrud, editCrud, deleteCrud) {
this.initialCrudState = initialCrudState;
this.Form = Form;
this.ListGenerator = ListGenerator;
this.filterFn = filterFn;
this.loadAllData = loadAllData;
this.addCrud = addCrud;
this.loadOneCrud = loadOneCrud;
this.editCrud = editCrud;
this.deleteCrud = deleteCrud;
}
return CrudSettingModel;
}());
var MODE = {
LIST: 'List',
ADD: 'Add',
EDIT: 'Edit'
};
var ModeModel = /** @class */ (function () {
function ModeModel() {
this.List = MODE.LIST;
this.Add = MODE.ADD;
this.Edit = MODE.EDIT;
}
return ModeModel;
}());
var FilterModel = /** @class */ (function () {
function FilterModel(key, value) {
this.key = key;
this.value = value;
}
return FilterModel;
}());
var BreadcrumbModel = /** @class */ (function () {
function BreadcrumbModel(part1, part2) {
this.part1 = part1;
this.part2 = part2;
}
return BreadcrumbModel;
}());
var CrudStateModel = /** @class */ (function () {
function CrudStateModel(paginationLimit, breadcrumbHome) {
this.loading = false;
this.error = false;
this.errorMessage = '';
this.allData = [];
this.allDataFilter = [];
this.allDataPagination = [];
this.paginationLimit = paginationLimit;
this.paginationPage = 1;
this.paginationTotalPages = 1;
this.mode = MODE.LIST;
this.editId = '';
this.breadcrumb = new BreadcrumbModel(MODE.LIST, breadcrumbHome);
this.breadcrumbHome = breadcrumbHome;
this.filter = new FilterModel('', '');
}
return CrudStateModel;
}());
var calculatePaginationTotalPages = function (data) {
var roundNumber = __spreadArrays(data).length / 10;
var isRound = __spreadArrays(data).length % 10 === 0;
var calculatedTotalPages = Math.floor(roundNumber);
if (!!isRound) {
return calculatedTotalPages - 1;
}
return calculatedTotalPages;
};
var GET_ALL_START = 'GET_ALL_START';
var GET_ALL_SUCCESS = 'GET_ALL_SUCCESS';
var GET_ALL_FAIL = 'GET_ALL_FAIL';
var CHANGE_PAGE = 'CHANGE_PAGE';
var FILTER = 'FILTER';
var CHANGE_MODE = 'CHANGE_MODE';
var BREADCRUMB_RETURN_HOME = 'BREADCRUMB_RETURN_HOME';
var START = 'START';
var END = 'END';
var crudReducerGenerator = function (filterFn) {
var crudReducer = function (state, action) {
var MODE = new ModeModel();
switch (action.type) {
case GET_ALL_START:
return __assign(__assign({}, state), { loading: true });
case GET_ALL_SUCCESS:
var allDataGetAll = action.payload.sort();
return __assign(__assign({}, state), { allData: __spreadArrays(allDataGetAll), allDataFilter: __spreadArrays(allDataGetAll), allDataPagination: __spreadArrays(allDataGetAll).slice(0, state.paginationLimit), paginationTotalPages: calculatePaginationTotalPages(__spreadArrays(allDataGetAll)), loading: false, error: false, errorMessage: '' });
case GET_ALL_FAIL:
return __assign(__assign({}, state), { allData: [], error: true, errorMessage: action.payload });
case CHANGE_PAGE:
var changePageCountriesPagination = __spreadArrays(state.allDataFilter).slice(state.paginationLimit * action.payload, (state.paginationLimit * action.payload) + state.paginationLimit);
return __assign(__assign({}, state), { paginationPage: action.payload, allDataPagination: changePageCountriesPagination });
case FILTER:
if (action.payload === undefined) {
console.log('Invalid Filter Payload, no value is found!');
return __assign({}, state);
}
var filtered = action.payload.value === '' ? __spreadArrays(state.allData) : __spreadArrays(state.allData).filter(function (i) { return filterFn(i, action.payload); });
var currentFilterTotalPages = calculatePaginationTotalPages(__spreadArrays(filtered));
var filteredPagination = filtered.slice(0, state.paginationLimit);
return __assign(__assign({}, state), { allDataFilter: filtered, allDataPagination: filteredPagination, paginationPage: 1, filter: action.payload, paginationTotalPages: currentFilterTotalPages === 0 ? 1 : currentFilterTotalPages });
case CHANGE_MODE:
return __assign(__assign({}, state), { mode: action.payload, editId: action.payload === MODE.Edit ? action.editId : '', breadcrumb: {
part1: MODE.List,
part2: action.payload
} });
case BREADCRUMB_RETURN_HOME:
return __assign(__assign({}, state), { mode: MODE.List, breadcrumb: {
part1: MODE.List,
part2: state.breadcrumbHome,
} });
case START:
return __assign(__assign({}, state), { loading: true });
case END:
return __assign(__assign({}, state), { loading: false });
default:
return __assign({}, state);
}
};
return crudReducer;
};
function generateShowRange(totalPages, currentPage) {
var showRange = [];
for (var i = 1; i <= totalPages; i++) {
if (i === currentPage) {
showRange.push(i);
}
else if (i === currentPage - 1) {
showRange.push(i);
}
else if (i === currentPage - 2) {
showRange.push(i);
}
else if (i === currentPage + 1) {
showRange.push(i);
}
else if (i === currentPage + 2) {
showRange.push(i);
}
else {
showRange.push(0);
}
}
var newShowRange = [];
for (var i = 0; i < showRange.length; i++) {
var item = showRange[i];
if (i + 1 === showRange.length) {
var willPush1 = totalPages;
var willPush2 = totalPages - 1;
var willPush3 = totalPages - 2;
if (!newShowRange.includes(willPush3)) {
newShowRange.push(willPush3);
}
if (!newShowRange.includes(willPush2)) {
newShowRange.push(willPush2);
}
if (!newShowRange.includes(willPush1)) {
newShowRange.push(willPush1);
}
continue;
}
if (i === 0) {
newShowRange.push(item);
continue;
}
var previousItem = showRange[i - 1];
if (item !== previousItem) {
newShowRange.push(item);
}
}
var preFilter = __spreadArrays(newShowRange.filter(function (i) { return i >= 0; }));
if ((preFilter.includes(1) || preFilter.includes(2) || preFilter.includes(3)) && preFilter.length <= 4) {
return preFilter.filter(function (i) { return i !== 0; });
}
return preFilter;
}
function PaginationComponent(props) {
var totalPages = props.totalPages;
var currentPage = props.currentPage;
var paginationItemComponent = function (pageNumber, active, key) {
if (pageNumber === 0) {
return React__default.createElement(reactBootstrap.Pagination.Ellipsis, { key: key });
}
if (!!active) {
return React__default.createElement(reactBootstrap.Pagination.Item, { key: key, active: true }, pageNumber);
}
else {
return React__default.createElement(reactBootstrap.Pagination.Item, { key: key, onClick: function () { return props.onChange(pageNumber); } }, pageNumber);
}
};
var showRange = generateShowRange(totalPages, currentPage);
var handlePageNumber = function (page) {
if (page <= 0) {
return 1;
}
if (page >= totalPages) {
return totalPages;
}
return page;
};
return (React__default.createElement(reactBootstrap.Pagination, null,
React__default.createElement(reactBootstrap.Pagination.First, { onClick: function () { return props.onChange(1); } }),
React__default.createElement(reactBootstrap.Pagination.Prev, { onClick: function () { return props.onChange(handlePageNumber(currentPage - 1)); } }),
showRange.map(function (i) {
var key = new Date().getTime() + i + (1000000 * Math.random());
return (paginationItemComponent(i, currentPage === i, key));
}),
React__default.createElement(reactBootstrap.Pagination.Next, { onClick: function () { return props.onChange(handlePageNumber(currentPage + 1)); } }),
React__default.createElement(reactBootstrap.Pagination.Last, { onClick: function () { return props.onChange(handlePageNumber(totalPages)); } })));
}
function List(props) {
var _a = props.crudReducer, crudState = _a.crudState, dispatchCrud = _a.dispatchCrud;
var MODE = new ModeModel();
React.useEffect(function () {
var mounted = true;
dispatchCrud({ type: 'GET_ALL_START' });
props.loadAllData(props.appReducer, props.crudReducer, mounted);
return function () {
mounted = false;
};
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
//pagination
var onPaginationChange = function (page) {
dispatchCrud({ type: 'CHANGE_PAGE', payload: page });
};
return (React__default.createElement(React__default.Fragment, null,
!crudState.loading ?
React__default.createElement("div", { className: "row" },
React__default.createElement("div", { className: "col-10 text-left" },
React__default.createElement("button", { style: { display: 'none' }, type: "button", className: "btn btn-danger" }, "Reload")),
React__default.createElement("div", { className: "col-2 text-right" },
React__default.createElement("button", { type: "button", className: "btn btn-info", onClick: function () { return dispatchCrud({ type: 'CHANGE_MODE', payload: MODE.Add }); } }, "+")))
: '',
!!crudState.loading ?
React__default.createElement("div", { className: "spinner-grow text-danger", role: "status" },
React__default.createElement("span", { className: "sr-only" }, "Loading..."))
: '',
crudState.allData.length > 0 && !crudState.loading ?
(React__default.createElement("div", null,
props.ListGenerator(crudState, dispatchCrud, MODE),
React__default.createElement("div", { className: "flex-center-all margin-top-20" },
React__default.createElement(PaginationComponent, { currentPage: crudState.paginationPage, totalPages: crudState.paginationTotalPages, onChange: onPaginationChange }))))
:
''));
}
function Add(props) {
var dispatchCrud = props.crudReducer.dispatchCrud;
var Form = props.Form;
var onSubmitAdding = function (data) {
props.addCrud(props.appReducer, props.crudReducer, __assign({}, data));
dispatchCrud({ type: 'BREADCRUMB_RETURN_HOME' });
};
return (React__default.createElement("div", null,
React__default.createElement("span", null,
React__default.createElement("b", null, "Add Country")),
React__default.createElement(Form, { form: {}, onSubmit: onSubmitAdding })));
}
function Edit(props) {
var _a = props.crudReducer, crudState = _a.crudState, dispatchCrud = _a.dispatchCrud;
var Form = props.Form;
var _b = React.useState(undefined), thisCrud = _b[0], setThisCrud = _b[1];
var loadOneCrudContainer = function () {
props.loadOneCrud(props.appReducer, props.crudReducer, setThisCrud);
};
var useMountEffect = function (fun) { return React.useEffect(fun, []); };
useMountEffect(loadOneCrudContainer);
var onSubmitEditing = function (data) {
props.editCrud(props.appReducer, props.crudReducer, __assign({}, data));
dispatchCrud({ type: 'BREADCRUMB_RETURN_HOME' });
};
var onSubmitDeleting = function (data) {
reactConfirmAlert.confirmAlert({
customUI: function (_a) {
var onClose = _a.onClose;
return (React__default.createElement("div", { className: 'custom-delete-confirm-ui' },
React__default.createElement("h1", null, "Are you sure?"),
React__default.createElement("p", null, "You want to delete this?"),
React__default.createElement("button", { onClick: onClose }, "No"),
React__default.createElement("button", { onClick: function () {
props.deleteCrud(props.appReducer, props.crudReducer, __assign({}, data));
dispatchCrud({ type: 'BREADCRUMB_RETURN_HOME' });
onClose();
} }, "Yes, Delete it!")));
}
});
};
return (React__default.createElement("div", null,
React__default.createElement("span", null,
React__default.createElement("b", null, "Edit Country")),
!crudState.loading && thisCrud !== undefined ? React__default.createElement(Form, { form: thisCrud, onSubmit: onSubmitEditing, onSubmitDeleting: onSubmitDeleting }) : ''));
}
function BreadcrumbComponent(props) {
var _a = props.reducer, bcState = _a.bcState, bcDispatch = _a.bcDispatch;
var part1Click = function (value) {
bcDispatch({ type: 'BREADCRUMB_RETURN_HOME', payload: value });
};
return (React__default.createElement(reactBootstrap.Breadcrumb, null,
React__default.createElement(reactBootstrap.Breadcrumb.Item, { onClick: function () { return part1Click(bcState.breadcrumb.part1); } }, bcState.breadcrumb.part1),
React__default.createElement(reactBootstrap.Breadcrumb.Item, { active: true }, bcState.breadcrumb.part2)));
}
function CrudContainer(props) {
var setting = props.setting;
var initial = new CrudStateModel(setting.initialCrudState.paginationLimit, setting.initialCrudState.breadcrumbHome);
var crudReducer = crudReducerGenerator(setting.filterFn);
var _a = React.useReducer(crudReducer, initial), crudState = _a[0], dispatchCrud = _a[1];
var MODE = new ModeModel();
return (React__default.createElement(React__default.Fragment, null,
React__default.createElement(BreadcrumbComponent, { reducer: { bcState: crudState, bcDispatch: dispatchCrud } }),
crudState.mode === MODE.List ? React__default.createElement(List, { appReducer: props.reducer, crudReducer: { crudState: crudState, dispatchCrud: dispatchCrud }, loadAllData: setting.loadAllData, ListGenerator: setting.ListGenerator }) : '',
crudState.mode === MODE.Add ? React__default.createElement(Add, { appReducer: props.reducer, crudReducer: { crudState: crudState, dispatchCrud: dispatchCrud }, addCrud: setting.addCrud, Form: setting.Form }) : '',
crudState.mode === MODE.Edit ? React__default.createElement(Edit, { appReducer: props.reducer, crudReducer: { crudState: crudState, dispatchCrud: dispatchCrud }, loadOneCrud: setting.loadOneCrud, editCrud: setting.editCrud, deleteCrud: setting.deleteCrud, Form: setting.Form }) : '',
!!crudState.loading ?
React__default.createElement("div", { className: "row flex-center-all" },
React__default.createElement("div", { className: "spinner-grow text-danger", role: "status" },
React__default.createElement("span", { className: "sr-only" }, "Loading...")))
: ''));
}
function Authentication(props) {
var _a = props.reducer, appState = _a.appState, dispatchApp = _a.dispatchApp;
var setting = props.setting;
var _b = React.useState(''), username = _b[0], setUsername = _b[1];
var _c = React.useState(''), password = _c[0], setPassword = _c[1];
// API integration - start
var defaultLoginResponseHandler = function (i) {
var data = i.data;
if (data.data === undefined || data.data === null) {
console.log('error');
var errorMessage = data.errors.map(function (j) {
var itemMessage = j.message;
// const itemExtension = i.extensions.code;
// return `${itemExtension}: ${itemMessage}`;
return "" + itemMessage;
}).join(', ');
dispatchApp({ type: 'LOGIN_ERROR', payload: errorMessage });
}
else {
var accountData = JSON.stringify(data.data.login);
localStorage.setItem('account', accountData);
dispatchApp({ type: 'LOGIN_SUCCESS', payload: JSON.parse(accountData) });
}
};
var loginResponseHandler = setting.login.responseCallback === undefined ? defaultLoginResponseHandler : setting.login.responseCallback;
var defaultLoginErrorHandler = function (i) {
console.log(i);
dispatchApp({ type: 'LOGIN_ERROR', payload: JSON.stringify(i) });
};
var loginErrorHandler = setting.login.errorCallback === undefined ? defaultLoginErrorHandler : setting.login.errorCallback;
var login = function (e) {
!!e ? e.preventDefault() : console.log('No event is fired!');
dispatchApp({ type: 'START' });
setUsername('');
setPassword('');
Axios.post(setting.login.url, setting.login.data(username, password), {
headers: setting.login.headers
}).then(loginResponseHandler).catch(loginErrorHandler);
};
var defaultLogout = function () {
localStorage.removeItem('account');
dispatchApp({ type: 'LOGOUT' });
};
var logout = setting.login.logout === undefined ? defaultLogout : setting.login.logout;
// API integration - end
// child components - start
var loginComponent = setting.components.LoginComponentGenerator === undefined ? function (loginFn, setUsernameFn, setPasswordFn) {
return (React__default.createElement("form", { onSubmit: loginFn, className: "margin-top-20" },
React__default.createElement("div", { className: "form-group" },
React__default.createElement("input", { type: "text", className: "form-control", id: "username", placeholder: "Username", value: username, onChange: function (e) { return setUsernameFn(e.target.value); } })),
React__default.createElement("div", { className: "form-group" },
React__default.createElement("input", { type: "password", className: "form-control", id: "password", placeholder: "Password", value: password, onChange: function (e) { return setPasswordFn(e.target.value); } })),
React__default.createElement("button", { type: "submit", className: "btn btn-primary" }, "Login")));
} : setting.components.LoginComponentGenerator;
var errorComponent = setting.components.ErrorComponent === undefined ? function () {
return (React__default.createElement("div", { style: { marginTop: '10px' } },
React__default.createElement("span", { style: { color: 'red' } }, appState.errorMessage)));
} : setting.components.ErrorComponent;
var authHeaderComponent = setting.components.HeaderComponent === undefined ? function () {
return (!!appState.auth ? React__default.createElement("div", { className: "width-100" },
React__default.createElement("p", { style: { display: 'none' } },
React__default.createElement("b", null, "Username: "),
appState.account.username),
React__default.createElement("p", { style: { display: 'none' } },
React__default.createElement("b", null, "Email: "),
appState.account.email),
React__default.createElement("div", { className: "row" },
React__default.createElement("div", { className: "col-6 text-left" },
React__default.createElement("i", null,
"Welcome back, ",
appState.account.firstName,
" ",
appState.account.lastName,
"! ",
React__default.createElement("span", { style: { display: 'none' } },
"(",
appState.account.role,
")"))),
React__default.createElement("div", { className: "col-6 text-right" }, logoutComponent))) : '');
} : setting.components.HeaderComponent;
var loadingComponent = (!!appState.loading ?
React__default.createElement("button", { style: { marginTop: '15px' }, className: "btn btn-primary", type: "button", disabled: true },
React__default.createElement("span", { className: "spinner-grow spinner-grow-sm", role: "status", "aria-hidden": "true" }),
"Loading...")
: '');
var logoutComponent = (React__default.createElement("button", { type: "button", className: "btn btn-danger", onClick: logout }, "Logout"));
// child components - end
return (React__default.createElement(React__default.Fragment, null,
React__default.createElement("header", { className: "margin-top-20 flex-center-all break-all" },
!!appState.auth ? React__default.createElement("h1", null, setting.app.title) : React__default.createElement("h1", null, setting.app.loginTitle),
authHeaderComponent()),
React__default.createElement("div", { className: "flex-center-all" }, loadingComponent),
!appState.loading ?
React__default.createElement("main", { className: "flex-center-all" },
!appState.auth ? loginComponent(login, setUsername, setPassword) : '',
setting.components.CustomComponentGenerator(),
!!appState.error ? errorComponent() : '')
: ''));
}
var appReducer = function (state, action) {
switch (action.type) {
case 'START':
return __assign(__assign({}, state), { loading: true });
case 'END':
return __assign(__assign({}, state), { loading: false });
case 'CHANGE':
return __assign(__assign({}, state), action.payload);
case 'LOGIN_ERROR':
return __assign(__assign({}, state), { error: true, errorMessage: action.payload, loading: false, auth: false, account: {} });
case 'LOGIN_SUCCESS':
return __assign(__assign({}, state), { error: false, errorMessage: '', loading: false, auth: true, account: action.payload });
case 'LOGOUT':
return __assign(__assign({}, state), { error: false, errorMessage: '', loading: false, auth: false, account: {} });
default:
return state;
}
};
var checkAuth = function () {
var cache = localStorage.getItem('account');
if (cache !== null && cache !== undefined) {
return true;
}
return false;
};
var getAccountCache = function () {
if (checkAuth()) {
var account = localStorage.getItem('account');
if (account !== null) {
return JSON.parse(account);
}
return {};
}
else {
return {};
}
};
var AppStateModel = /** @class */ (function () {
function AppStateModel(auth, account, loading, error, errorMessage) {
if (auth === void 0) { auth = checkAuth(); }
if (account === void 0) { account = getAccountCache(); }
if (loading === void 0) { loading = false; }
if (error === void 0) { error = false; }
if (errorMessage === void 0) { errorMessage = false; }
this.auth = auth;
this.account = account;
this.loading = loading;
this.error = error;
this.errorMessage = errorMessage;
}
return AppStateModel;
}());
var index = {
components: {
CRUD: CrudContainer,
AuthenticationLayer: Authentication
},
reducers: {
appReducer: appReducer
},
models: {
AppStateModel: AppStateModel,
CrudStateModel: CrudStateModel,
FilterModel: FilterModel,
CrudSettingModel: CrudSettingModel,
AuthSettingModel: AuthSettingModel
}
};
exports.default = index;
//# sourceMappingURL=index.js.map