ra-core
Version:
Core components of react-admin, a frontend Framework for building admin applications on top of REST services, using ES6, React
115 lines • 4.66 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.useUnique = void 0;
const react_1 = require("react");
const merge_js_1 = __importDefault(require("lodash/merge.js"));
const set_js_1 = __importDefault(require("lodash/set.js"));
const core_1 = require("../../core/index.cjs");
const dataProvider_1 = require("../../dataProvider/index.cjs");
const i18n_1 = require("../../i18n/index.cjs");
const util_1 = require("../../util/index.cjs");
const controller_1 = require("../../controller/index.cjs");
const validate_1 = require("./validate.cjs");
/**
* A hook that returns a validation function checking for a record field uniqueness
* by calling the dataProvider getList function with a filter.
*
* @example // Passing options at declaration time
* const UserCreateForm = () => {
* const unique = useUnique({ message: 'Username is already used'});
* return (
* <SimpleForm>
* <TextInput source="username" validate={unique()} />
* </SimpleForm>
* );
* }
*
* @example // Passing options at call time
* const UserCreateForm = () => {
* const unique = useUnique();
* return (
* <SimpleForm>
* <TextInput source="username" validate={unique({ message: 'Username is already used'})} />
* </SimpleForm>
* );
* }
*
* @example // With additional filters
* const UserCreateForm = () => {
* const unique = useUnique();
* return (
* <SimpleForm>
* <ReferenceInput source="organization_id" reference="organizations" />
* <FormDataConsumer>
* {({ formData }) => (
* <TextInput
* source="username"
* validate={unique({ filter: { organization_id: formData.organization_id })}
* />
* )}
* </FormDataConsumer>
* </SimpleForm>
* );
* }
*/
const useUnique = (options) => {
const dataProvider = (0, dataProvider_1.useDataProvider)();
const translateLabel = (0, i18n_1.useTranslateLabel)();
const resource = (0, core_1.useResourceContext)(options);
if (!resource) {
throw new Error('useUnique: missing resource prop or context');
}
const translate = (0, i18n_1.useTranslate)();
const record = (0, controller_1.useRecordContext)();
const debouncedGetList = (0, react_1.useRef)(
// The initial value is here to set the correct type on useRef
(0, util_1.asyncDebounce)(dataProvider.getList, options?.debounce ?? DEFAULT_DEBOUNCE));
const validateUnique = (0, react_1.useCallback)((callTimeOptions) => {
const { message, filter, debounce: interval, } = (0, merge_js_1.default)({
debounce: DEFAULT_DEBOUNCE,
filter: {},
message: 'ra.validation.unique',
}, options, callTimeOptions);
debouncedGetList.current = (0, util_1.asyncDebounce)(dataProvider.getList, interval);
return async (value, allValues, props) => {
if ((0, validate_1.isEmpty)(value)) {
return undefined;
}
try {
const finalFilter = (0, set_js_1.default)((0, merge_js_1.default)({}, filter), props.source, value);
const { data, total } = await debouncedGetList.current(resource, {
filter: finalFilter,
pagination: { page: 1, perPage: 1 },
sort: { field: 'id', order: 'ASC' },
});
if (typeof total !== 'undefined' &&
total > 0 &&
!data.some(r => r.id === record?.id)) {
return {
message,
args: {
source: props.source,
value,
field: translateLabel({
label: props.label,
source: props.source,
resource,
}),
},
};
}
}
catch (error) {
return translate('ra.notification.http_error');
}
return undefined;
};
}, [dataProvider, options, record, resource, translate, translateLabel]);
return validateUnique;
};
exports.useUnique = useUnique;
const DEFAULT_DEBOUNCE = 1000;
//# sourceMappingURL=useUnique.js.map