import { TextInput } from './TextInput'; import { LabeledInput, LabeledInputProps } from '@/components/ra-inputs/LabeledInput'; import { localizedValueHasAllLocales, localizedValueHasAtLeastOneLocale } from '@/utils'; import { Box, Chip, ListItemText, Menu, MenuItem, PopoverOrigin, Typography } from '@mui/material'; import _ from 'lodash'; import { ValidationError, ValidationErrorMessage, composeValidators, useInput, useLocaleState, useLocales } from 'ra-core'; import { TextInputProps } from 'ra-ui-materialui'; import { ReactElement, useCallback, useMemo, useState } from 'react'; import { useWatch } from 'react-hook-form'; const ANCHOR_ORIGIN: PopoverOrigin = { vertical: 'bottom', horizontal: 'right' }; const TRANSFORM_ORIGIN: PopoverOrigin = { vertical: 'top', horizontal: 'right' }; type ILocalizedTextInputProps = TextInputProps & LabeledInputProps & { /** * Indicates if at least one locale is required. */ requiredAtLeastOneLocale?: boolean; /** * Indicates the locale that is required. * If not provided, one of the locales will be required. */ requiredLocale?: string; }; function LocalizedTextInput({ requiredAtLeastOneLocale, requiredLocale, validate: _validate, required: _required, ...props }: ILocalizedTextInputProps) { const { source } = props; const locales = useLocales(); const required = useCallback( (requiredMessage = 'ra.validation.required', specificRequiredMessage = 'ra.validation.required_locale') => { return (value: any) => { if (requiredAtLeastOneLocale && !requiredLocale && !localizedValueHasAtLeastOneLocale(value, locales)) { return requiredMessage; } else if (requiredLocale && (!_.has(value, requiredLocale) || _.isEmpty(_.get(value, requiredLocale)))) { return { message: specificRequiredMessage, args: { locale: requiredLocale } }; } else if (!requiredAtLeastOneLocale && _required && !localizedValueHasAllLocales(value, locales)) { return requiredMessage; } return undefined; }; }, [requiredAtLeastOneLocale, requiredLocale, locales, _required] ); const validate = useMemo(() => { return composeValidators(_validate, required()); }, [_validate, required]); const { fieldState } = useInput({ ...props, validate }); const { error } = fieldState; const value = useWatch({ name: source }); const isMissingLocalizations = !localizedValueHasAllLocales(value, locales); const [currentLocale] = useLocaleState(); const [locale, setLocale] = useState(currentLocale); const [anchorEl, setAnchorEl] = useState(null); const open = Boolean(anchorEl); const toggle = useCallback( (e: React.MouseEvent) => setAnchorEl(open ? null : e.currentTarget), [open, setAnchorEl] ); const handleClose = useCallback(() => setAnchorEl(null), [setAnchorEl]); const MenuItems: Array = useMemo(() => { return _.map(locales, (l, index) => { return ( { setLocale(l.locale); handleClose(); }} > ); }); }, [locales, setLocale, handleClose, value]); return ( : props?.helperText } > <> {_.map(locales, (l, index) => { return ( {locale}} size="small" onClick={toggle} color={isMissingLocalizations ? 'warning' : undefined} /> ) }} /> ); })} {MenuItems} ); } export type { ILocalizedTextInputProps }; export { LocalizedTextInput };