UNPKG

drf-react-by-schema

Version:

Components and Tools for building a React App having Django Rest Framework (DRF) as server

580 lines (579 loc) 24.2 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __rest = (this && this.__rest) || function (s, e) { var t = {}; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p]; if (s != null && typeof Object.getOwnPropertySymbols === "function") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) { if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) t[p[i]] = s[p[i]]; } return t; }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const react_1 = __importStar(require("react")); const useMediaQuery_1 = __importDefault(require("@mui/material/useMediaQuery")); const utils_1 = require("../utils"); const DialogActions_1 = __importDefault(require("../components/DialogActions")); const DRFReactBySchemaContext_1 = require("./DRFReactBySchemaContext"); const api_1 = require("../api"); const APIWrapperContext_1 = require("./APIWrapperContext"); const DialogFormBySchema_1 = __importDefault(require("../components/forms/DialogFormBySchema")); const initialPageForm = { id: '', schema: null, columns: null, initialValues: null, validationSchema: null, }; function APIWrapper({ handleLoading, setSnackBar, setDialog, children }) { const { serverEndPoint, theme } = (0, DRFReactBySchemaContext_1.useDRFReactBySchema)(); const isMobile = (0, useMediaQuery_1.default)(theme.breakpoints.down('md')); const [usuaria, setUsuaria] = (0, react_1.useState)(null); const [optionsAC, setOptionsAC] = (0, react_1.useReducer)((utils_1.reducer), null); const [pageForm, setPageForm] = (0, react_1.useReducer)((utils_1.reducer), initialPageForm); const editModel = (0, react_1.useRef)({}); // BASIC OPERATIONS DEPENDING DIRECTLY ON SERVER_ENDPOINT: const localGetRawData = (0, react_1.useCallback)((route) => { return (0, api_1.getRawData)({ path: route, serverEndPoint }); }, [serverEndPoint]); const localGetAutoComplete = (0, react_1.useCallback)((model) => { return (0, api_1.getAutoComplete)({ model, serverEndPoint }); }, [serverEndPoint]); const localGetGenericModelList = (0, react_1.useCallback)((params) => { return (0, api_1.getGenericModelList)(Object.assign(Object.assign({}, params), { serverEndPoint })); }, [serverEndPoint]); const localGetGenericModel = (0, react_1.useCallback)((params) => { return (0, api_1.getGenericModel)(Object.assign(Object.assign({}, params), { serverEndPoint })); }, [serverEndPoint]); const localGetAllModels = (0, react_1.useCallback)(() => __awaiter(this, void 0, void 0, function* () { const response = yield (0, api_1.getAllModels)(serverEndPoint); if ('isAxiosError' in response) { return []; } return response; }), [serverEndPoint]); const localLoginByPayload = (0, react_1.useCallback)((payload) => __awaiter(this, void 0, void 0, function* () { const response = yield (0, api_1.loginByPayload)(payload, serverEndPoint); if (typeof response !== 'boolean') { console.log({ error: response, payload, }); return false; } return response; }), [serverEndPoint]); const localSignUp = (0, react_1.useCallback)((data) => __awaiter(this, void 0, void 0, function* () { const response = yield (0, api_1.signUp)(data, serverEndPoint); if ('isAxiosError' in response) { return false; } return response; }), [serverEndPoint]); const localGetSignupOptions = (0, react_1.useCallback)(() => __awaiter(this, void 0, void 0, function* () { const response = yield (0, api_1.getSignUpOptions)(serverEndPoint); if ('isAxiosError' in response) { return false; } return response; }), [serverEndPoint]); const signOut = (0, react_1.useCallback)(() => { (0, api_1.clearJWT)(); setUsuaria(null); }, []); const localUpdateModel = (0, react_1.useCallback)((params) => __awaiter(this, void 0, void 0, function* () { const response = yield (0, api_1.updateData)(Object.assign(Object.assign({}, params), { serverEndPoint })); if ('isAxiosError' in response) { return false; } return response; }), [serverEndPoint]); const postData = (0, react_1.useCallback)((params) => __awaiter(this, void 0, void 0, function* () { const response = yield (0, api_1.createData)(Object.assign(Object.assign({}, params), { serverEndPoint })); if ('isAxiosError' in response) { return false; } return response; }), [serverEndPoint]); const updateUsuaria = (0, react_1.useCallback)(() => { (0, api_1.isLoggedIn)(serverEndPoint).then((newUsuaria) => { setUsuaria(newUsuaria || { erro: 'token inválido' }); }); }, [serverEndPoint]); // END OF SERVER_ENDPOINT DEPENDENT FUNCTIONS const onTriggerSnackBar = (0, react_1.useCallback)(({ msg, severity = 'info' }) => { setSnackBar({ open: true, msg, severity, }); }, [setSnackBar]); const populateInitialValues = (0, react_1.useCallback)((_a) => { var { id, extraValidators, fieldsLayout } = _a, object = __rest(_a, ["id", "extraValidators", "fieldsLayout"]); const values = (0, utils_1.populateValues)(object); const uiFields = fieldsLayout ? (0, utils_1.getFieldsFromFieldsLayout)(fieldsLayout) : object.columns ? Object.keys(object.columns) : undefined; const yupSchema = (0, utils_1.buildGenericYupValidationSchema)(Object.assign(Object.assign({}, object), { data: values, extraValidators, uiFields })); const customFieldLabelsAr = fieldsLayout === null || fieldsLayout === void 0 ? void 0 : fieldsLayout.map((fieldLayout) => fieldLayout.customLabels); const schema = Object.assign({}, object.schema); if (customFieldLabelsAr) { for (const customFieldLabels of customFieldLabelsAr) { if (!customFieldLabels) { continue; } for (const key of Object.keys(customFieldLabels)) { if (customFieldLabels[key] && (!uiFields || uiFields.includes(key))) { schema[key].label = customFieldLabels[key]; } } } } setPageForm({ id, schema, columns: object.columns, initialValues: values, validationSchema: yupSchema, forceReload: false, }); return values; }, []); const populateOptionsAC = (0, react_1.useCallback)((optionsACModels) => __awaiter(this, void 0, void 0, function* () { const promises = []; for (const model of optionsACModels) { promises.push(localGetAutoComplete(model)); } const results = yield Promise.all(promises); const newOptionsAC = {}; results.map((result, index) => { if (result !== false) { newOptionsAC[optionsACModels[index]] = result; } }); setOptionsAC(newOptionsAC); }), [localGetAutoComplete]); const loadSinglePageData = (0, react_1.useCallback)((_a) => __awaiter(this, [_a], void 0, function* ({ model, objId, optionsACModels, defaults = {}, extraValidators, fieldsLayout, }) { handleLoading(true); if (!objId || objId === 'novo') { objId = (0, utils_1.getTmpId)(); } const object = yield (0, api_1.getGenericModel)({ model, serverEndPoint, id: (0, utils_1.isTmpId)(objId) ? null : objId, }); if (object === false) { setPageForm({ schema: undefined, columns: undefined, id: '' }); console.log('Houve um erro ao tentar carregar os dados!'); return false; } handleLoading(false); if (optionsACModels) { populateOptionsAC(optionsACModels); } for (const [field, value] of Object.entries(defaults)) { if (!object.data[field] && typeof object.data[field] !== 'boolean') { object.data[field] = value; } } const values = populateInitialValues(Object.assign({ id: objId, extraValidators, fieldsLayout }, object)); return values; }), [handleLoading, populateInitialValues, populateOptionsAC, serverEndPoint]); const onSubmit = (0, react_1.useCallback)((model, id, data) => __awaiter(this, void 0, void 0, function* () { if (!pageForm || !pageForm.schema) { console.log('there must be a pageForm!'); return false; } handleLoading(true); const response = yield (0, api_1.updateDataBySchema)({ model, modelObjectId: id, serverEndPoint, data, schema: pageForm.schema, }); handleLoading(false); if ('isAxiosError' in response) { onTriggerSnackBar({ msg: 'Houve um problema ao salvar seus dados! Por favor, entre em contato', severity: 'error', }); console.log({ msg: 'Error saving model', errors: response, data, }); return false; } if (optionsAC) { populateOptionsAC(Object.keys(optionsAC)); } onTriggerSnackBar({ msg: id ? 'Dados atualizados com sucesso!' : 'Criado com sucesso!', }); return response.id; }), [handleLoading, onTriggerSnackBar, optionsAC, pageForm, populateOptionsAC, serverEndPoint]); const onEditModelSave = (0, react_1.useCallback)((data) => __awaiter(this, void 0, void 0, function* () { setDialog({ open: false }); handleLoading(true); const { fieldKey, index, model, id, setValue, getValues, schema } = editModel.current; const response = yield (0, api_1.updateDataBySchema)({ model, modelObjectId: id, serverEndPoint, data, schema, }); if ('isAxiosError' in response) { onTriggerSnackBar({ msg: 'Houve um problema ao salvar seus dados.', severity: 'error', }); console.log({ msg: 'Error saving model', response, data, }); return false; } onTriggerSnackBar({ msg: 'Alterações salvas com sucesso!', severity: 'info', }); if (setValue && getValues) { const targetKey = fieldKey && index >= 0 ? `${fieldKey}.${index}.${model}` : model; const value = getValues(targetKey); const newValue = Array.isArray(value) ? value.map((item) => { return item.id === response.id ? response : item; }) : Object.assign({}, response); setValue(targetKey, newValue); populateOptionsAC([model]); } handleLoading(false); return true; }), [handleLoading, onTriggerSnackBar, populateOptionsAC, serverEndPoint, setDialog]); const onEditModelDataGridSave = (0, react_1.useCallback)((_a) => __awaiter(this, [_a], void 0, function* ({ model, newRow, schema }) { const response = yield (0, api_1.updateDataBySchema)({ model, modelObjectId: newRow.id, serverEndPoint, data: newRow, schema, path: model, }); if ('isAxiosError' in response) { onTriggerSnackBar({ msg: 'Não foi possível salvar os dados. Confira os erros.', severity: 'error', }); console.log({ msg: 'Error saving model', response, data: newRow, }); return false; } onTriggerSnackBar({ msg: 'Alterações salvas com sucesso!', severity: 'info', }); return response; }), [onTriggerSnackBar, serverEndPoint]); const onEditModel = (0, react_1.useCallback)(({ fieldKey, index, model, id, labelKey, setValue, getValues, fieldsLayout, initialValuesPartial, }) => { setDialog({ open: true, loading: true, }); (0, api_1.getGenericModel)({ model, serverEndPoint, id }).then((result) => { if (result === false) { setDialog({ open: true, loading: false, title: 'Falha ao carregar o formulário', Body: react_1.default.createElement(react_1.default.Fragment, null, "N\u00E3o foi poss\u00EDvel carregar o formul\u00E1rio!"), }); return false; } const populatedValues = (0, utils_1.populateValues)(result); const uiFields = fieldsLayout ? (0, utils_1.getFieldsFromFieldsLayout)(fieldsLayout) : result.columns ? result.columns.map(({ field }) => field) : undefined; const yupSchema = (0, utils_1.buildGenericYupValidationSchema)({ schema: result.schema, data: populatedValues, uiFields, }); const values = (0, utils_1.isTmpId)(id) && initialValuesPartial ? Object.assign(Object.assign({}, populatedValues), initialValuesPartial) : Object.assign({}, populatedValues); setDialog({ open: true, loading: false, title: 'Editar', Body: (react_1.default.createElement(DialogFormBySchema_1.default, { schema: result.schema, validationSchema: yupSchema, initialValues: values, setDialog: setDialog, getAutoComplete: localGetAutoComplete, onEditModelSave: onEditModelSave, fieldsLayout: fieldsLayout, isCancelDisabled: true, forceSaveEnabled: true, optionsAC: optionsAC, setOptionsAC: setOptionsAC })), Actions: react_1.default.createElement(react_1.default.Fragment, null), isCancelDisabled: true, }); editModel.current = { fieldKey, index, model, id, labelKey, setValue, getValues, schema: result.schema, }; }); }, [localGetAutoComplete, onEditModelSave, optionsAC, serverEndPoint, setDialog]); const onDeleteModelSave = (0, react_1.useCallback)((model, id, onSuccess, event) => __awaiter(this, void 0, void 0, function* () { setDialog({ open: false }); handleLoading(true); const ret = yield (0, api_1.deleteData)(model, serverEndPoint, id); if (ret === true) { onTriggerSnackBar({ msg: 'Apagado com com sucesso!', severity: 'info', }); if (onSuccess && event) { onSuccess(event); } return true; } handleLoading(false); onTriggerSnackBar({ msg: 'Houve um problema ao remover o item! Por favor, entre em contato.', severity: 'error', }); return false; }), [handleLoading, onTriggerSnackBar, serverEndPoint, setDialog]); const onDeleteModel = (0, react_1.useCallback)((model, id, onSuccess) => { setDialog({ open: true, loading: false, title: 'Apagar', Body: 'Tem certeza de que deseja apagar este item?', Actions: (react_1.default.createElement(DialogActions_1.default, { setDialog: setDialog, handleSave: (event) => { return onDeleteModelSave(model, id, onSuccess, event); }, btnConfirm: "Sim, apagar" })), }); }, [onDeleteModelSave, setDialog]); const onEditRelatedModelSave = (0, react_1.useCallback)((_a) => __awaiter(this, [_a], void 0, function* ({ model, id, relatedModel, newRow, schema, onlyAddExisting, }) { const updateUrl = `${model}/${id}/${relatedModel}`; if (onlyAddExisting) { const response = yield (0, api_1.addExistingRelatedModel)({ model, id, serverEndPoint, data: { onlyAddExisting: { key: relatedModel, value: newRow.id_to_add, }, }, }); if ('isAxiosError' in response) { console.log(response); onTriggerSnackBar({ msg: 'Houve um problema ao salvar a alteração! Por favor, entre em contato.', severity: 'error', }); return false; } onTriggerSnackBar({ msg: 'Alterações salvas com sucesso!', severity: 'info', }); const object = yield (0, api_1.getGenericModel)({ model, id, serverEndPoint, relatedModel, relatedModelId: newRow.id_to_add, }); return object; } // This is important for related data if (schema[model] && !newRow[model]) { newRow[model] = id; } const response = yield (0, api_1.updateDataBySchema)({ model: relatedModel, modelObjectId: newRow.id, serverEndPoint, data: newRow, schema, path: updateUrl, }); if ('isAxiosError' in response) { onTriggerSnackBar({ msg: 'Não foi possível salvar os dados. Confira os erros.', severity: 'error', }); console.log({ error: response, data: newRow, }); return false; } onTriggerSnackBar({ msg: 'Alterações salvas com sucesso!', severity: 'info', }); return response; }), [onTriggerSnackBar, serverEndPoint]); const onDeleteRelatedModel = (0, react_1.useCallback)((_a) => __awaiter(this, [_a], void 0, function* ({ model, id, relatedModel, relatedModelId }) { const deleteUrl = `${model}/${id}/${relatedModel}`; const response = yield (0, api_1.deleteData)(deleteUrl, serverEndPoint, relatedModelId); if (response !== true) { onTriggerSnackBar({ msg: 'Houve um problema ao remover o item! Por favor, entre em contato.', severity: 'error', }); console.log({ error: response, id, }); return false; } onTriggerSnackBar({ msg: 'Alterações salvas com sucesso!', severity: 'info', }); return response; }), [onTriggerSnackBar, serverEndPoint]); (0, react_1.useEffect)(() => { updateUsuaria(); setPageForm(initialPageForm); // eslint-disable-next-line react-hooks/exhaustive-deps }, []); const contextValue = (0, react_1.useMemo)(() => { return { usuaria, updateUsuaria, onSubmit, loadSinglePageData, handleLoading, optionsACState: [optionsAC, setOptionsAC], optionsAC, setOptionsAC, pageFormState: [pageForm, setPageForm], pageForm, setPageForm, onEditModel, onEditModelSave, onEditModelDataGridSave, onDeleteModel, onEditRelatedModelSave, onDeleteRelatedModel, onTriggerSnackBar, setDialog, // api utils: getRawData: localGetRawData, getAutoComplete: localGetAutoComplete, getGenericModel: localGetGenericModel, getGenericModelList: localGetGenericModelList, getAllModels: localGetAllModels, loginByPayload: localLoginByPayload, getSignUpOptions: localGetSignupOptions, signUp: localSignUp, signOut, postData: postData, // Remove after integrating new "onEditModel" to package: // serverEndPoint, editModel, updateModel: localUpdateModel, populateOptionsAC, isMobile, }; }, [ handleLoading, isMobile, loadSinglePageData, localGetAllModels, localGetAutoComplete, localGetGenericModel, localGetGenericModelList, localGetRawData, localGetSignupOptions, localLoginByPayload, localSignUp, localUpdateModel, onDeleteModel, onDeleteRelatedModel, onEditModel, onEditModelDataGridSave, onEditModelSave, onEditRelatedModelSave, onSubmit, onTriggerSnackBar, optionsAC, pageForm, populateOptionsAC, postData, setDialog, signOut, updateUsuaria, usuaria, ]); if (!serverEndPoint) { console.error('There must be a serverEndPoint properly configured for apiWrapper to work!'); return react_1.default.createElement(react_1.default.Fragment, null, children); } return react_1.default.createElement(APIWrapperContext_1.APIWrapperContext.Provider, { value: contextValue }, children); } exports.default = react_1.default.memo(APIWrapper);