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
JavaScript
"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);