@applica-software-guru/react-admin 1.5.247 → 1.5.249

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -8,11 +8,14 @@ type ILocalizedValue<T> = {
8
8
  declare function localizedValueHasAllLocales<T>(value?: ILocalizedValue<T>, locales?: Array<ILocale>, options?: {
9
9
  isEmpty?: (v: T) => boolean;
10
10
  }): boolean;
11
+ declare function localizedValueHasAtLeastOneLocale<T>(value?: ILocalizedValue<T>, locales?: Array<ILocale>, options?: {
12
+ isEmpty?: (v: T) => boolean;
13
+ }): boolean;
11
14
  type IGetLocalizedValueOptions = {
12
15
  fallback?: boolean;
13
16
  fallbackLocales?: Array<string>;
14
17
  };
15
18
  declare function getLocalizedValue<T>(value: ILocalizedValue<T>, locale: string, options?: IGetLocalizedValueOptions): T | undefined;
16
19
  export type { IGetLocalizedValueOptions, ILocalizedValue };
17
- export { getLocalizedValue, localizedValueHasAllLocales };
20
+ export { getLocalizedValue, localizedValueHasAllLocales, localizedValueHasAtLeastOneLocale };
18
21
  //# sourceMappingURL=localizedValue.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"localizedValue.d.ts","sourceRoot":"","sources":["../../../src/utils/localizedValue.ts"],"names":[],"mappings":"AAEA,KAAK,OAAO,GAAG;IACb,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AACF,KAAK,eAAe,CAAC,CAAC,IAAI;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,CAAC,CAAA;CAAE,CAAC;AAE/C,iBAAS,2BAA2B,CAAC,CAAC,EACpC,KAAK,GAAE,eAAe,CAAC,CAAC,CAAM,EAC9B,OAAO,GAAE,KAAK,CAAC,OAAO,CAAM,EAC5B,OAAO,GAAE;IAAE,OAAO,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,OAAO,CAAA;CAAO,GAC5C,OAAO,CAIT;AAED,KAAK,yBAAyB,GAAG;IAC/B,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,eAAe,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;CACjC,CAAC;AACF,iBAAS,iBAAiB,CAAC,CAAC,EAC1B,KAAK,EAAE,eAAe,CAAC,CAAC,CAAC,EACzB,MAAM,EAAE,MAAM,EACd,OAAO,CAAC,EAAE,yBAAyB,GAClC,CAAC,GAAG,SAAS,CAyBf;AAED,YAAY,EAAE,yBAAyB,EAAE,eAAe,EAAE,CAAC;AAC3D,OAAO,EAAE,iBAAiB,EAAE,2BAA2B,EAAE,CAAC"}
1
+ {"version":3,"file":"localizedValue.d.ts","sourceRoot":"","sources":["../../../src/utils/localizedValue.ts"],"names":[],"mappings":"AAEA,KAAK,OAAO,GAAG;IACb,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AACF,KAAK,eAAe,CAAC,CAAC,IAAI;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,CAAC,CAAA;CAAE,CAAC;AAE/C,iBAAS,2BAA2B,CAAC,CAAC,EACpC,KAAK,GAAE,eAAe,CAAC,CAAC,CAAM,EAC9B,OAAO,GAAE,KAAK,CAAC,OAAO,CAAM,EAC5B,OAAO,GAAE;IAAE,OAAO,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,OAAO,CAAA;CAAO,GAC5C,OAAO,CAIT;AAED,iBAAS,iCAAiC,CAAC,CAAC,EAC1C,KAAK,GAAE,eAAe,CAAC,CAAC,CAAM,EAC9B,OAAO,GAAE,KAAK,CAAC,OAAO,CAAM,EAC5B,OAAO,GAAE;IAAE,OAAO,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,OAAO,CAAA;CAAO,GAC5C,OAAO,CAGT;AAED,KAAK,yBAAyB,GAAG;IAC/B,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,eAAe,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;CACjC,CAAC;AACF,iBAAS,iBAAiB,CAAC,CAAC,EAC1B,KAAK,EAAE,eAAe,CAAC,CAAC,CAAC,EACzB,MAAM,EAAE,MAAM,EACd,OAAO,CAAC,EAAE,yBAAyB,GAClC,CAAC,GAAG,SAAS,CAyBf;AAED,YAAY,EAAE,yBAAyB,EAAE,eAAe,EAAE,CAAC;AAC3D,OAAO,EAAE,iBAAiB,EAAE,2BAA2B,EAAE,iCAAiC,EAAE,CAAC"}
package/package.json CHANGED
@@ -115,5 +115,5 @@
115
115
  "type": "module",
116
116
  "types": "dist/index.d.ts",
117
117
  "typings": "dist/index.d.ts",
118
- "version": "1.5.247"
118
+ "version": "1.5.249"
119
119
  }
@@ -364,7 +364,6 @@ function useBreadcrumbs() {
364
364
  }
365
365
  }
366
366
 
367
- console.log('menuItem:', menuItem);
368
367
  const urlParts = menuItem?.url?.split('/');
369
368
  const urlPartsLength = urlParts?.length || 0;
370
369
  if (pathArgs.length >= urlPartsLength) {
@@ -1,11 +1,7 @@
1
- import logoIcon from '@/assets/logo-icon.png';
2
- import logoMain from '@/assets/logo-main.png';
3
1
  import { useThemeConfig } from '@/components/Layout/ThemeProvider';
4
2
  import { ButtonBase, SxProps } from '@mui/material';
5
3
  import { Link } from 'react-router-dom';
6
4
 
7
- const defaultIcon = <img src={logoIcon} alt="Applica" width="20px" />;
8
- const defaultMain = <img src={logoMain} alt="Applica" width="100px" />;
9
5
  type LogoProps = {
10
6
  isIcon: boolean;
11
7
  sx: SxProps;
@@ -13,7 +9,7 @@ type LogoProps = {
13
9
  logoIcon: React.ReactNode;
14
10
  logoMain: React.ReactNode;
15
11
  };
16
- function Logo({ isIcon, sx, to, logoIcon = defaultIcon, logoMain = defaultMain }: LogoProps) {
12
+ function Logo({ isIcon, sx, to, logoIcon, logoMain }: LogoProps) {
17
13
  const { appDefaultPath } = useThemeConfig();
18
14
  return (
19
15
  <ButtonBase disableRipple component={Link} to={!to ? appDefaultPath : to} sx={sx}>
@@ -87,7 +87,7 @@ type LabeledInputProps = InputProps & {
87
87
  isRequired?: boolean;
88
88
  source?: string;
89
89
  display?: 'legend' | 'label';
90
- helperText?: string | boolean;
90
+ helperText?: string | boolean | React.ReactElement | null;
91
91
  divider?: boolean;
92
92
  };
93
93
 
@@ -1,9 +1,16 @@
1
1
  import { TextInput } from './TextInput';
2
2
  import { LabeledInput, LabeledInputProps } from '@/components/ra-inputs/LabeledInput';
3
- import { localizedValueHasAllLocales } from '@/utils';
3
+ import { localizedValueHasAllLocales, localizedValueHasAtLeastOneLocale } from '@/utils';
4
4
  import { Box, Chip, ListItemText, Menu, MenuItem, PopoverOrigin, Typography } from '@mui/material';
5
5
  import _ from 'lodash';
6
- import { useInput, useLocaleState, useLocales } from 'ra-core';
6
+ import {
7
+ ValidationError,
8
+ ValidationErrorMessage,
9
+ composeValidators,
10
+ useInput,
11
+ useLocaleState,
12
+ useLocales
13
+ } from 'ra-core';
7
14
  import { TextInputProps } from 'ra-ui-materialui';
8
15
  import { ReactElement, useCallback, useMemo, useState } from 'react';
9
16
  import { useWatch } from 'react-hook-form';
@@ -11,14 +18,49 @@ import { useWatch } from 'react-hook-form';
11
18
  const ANCHOR_ORIGIN: PopoverOrigin = { vertical: 'bottom', horizontal: 'right' };
12
19
  const TRANSFORM_ORIGIN: PopoverOrigin = { vertical: 'top', horizontal: 'right' };
13
20
 
14
- type ILocalizedTextInputProps = TextInputProps & LabeledInputProps;
21
+ type ILocalizedTextInputProps = TextInputProps &
22
+ LabeledInputProps & {
23
+ /**
24
+ * Indicates if at least one locale is required.
25
+ */
26
+ requiredAtLeastOneLocale?: boolean;
27
+ /**
28
+ * Indicates the locale that is required.
29
+ * If not provided, one of the locales will be required.
30
+ */
31
+ requiredLocale?: string;
32
+ };
15
33
 
16
- function LocalizedTextInput(props: ILocalizedTextInputProps) {
34
+ function LocalizedTextInput({
35
+ requiredAtLeastOneLocale,
36
+ requiredLocale,
37
+ validate: _validate,
38
+ required: _required,
39
+ ...props
40
+ }: ILocalizedTextInputProps) {
17
41
  const { source } = props;
18
- const { fieldState } = useInput(props);
19
- const value = useWatch({ name: source });
20
- const { error } = fieldState;
21
42
  const locales = useLocales();
43
+ const required = useCallback(
44
+ (requiredMessage = 'ra.validation.required', specificRequiredMessage = 'ra.validation.required_locale') => {
45
+ return (value: any) => {
46
+ if (requiredAtLeastOneLocale && !requiredLocale && !localizedValueHasAtLeastOneLocale(value, locales)) {
47
+ return requiredMessage;
48
+ } else if (requiredLocale && (!_.has(value, requiredLocale) || _.isEmpty(_.get(value, requiredLocale)))) {
49
+ return { message: specificRequiredMessage, args: { locale: requiredLocale } };
50
+ } else if (!requiredAtLeastOneLocale && _required && !localizedValueHasAllLocales(value, locales)) {
51
+ return requiredMessage;
52
+ }
53
+ return undefined;
54
+ };
55
+ },
56
+ [requiredAtLeastOneLocale, requiredLocale, locales, _required]
57
+ );
58
+ const validate = useMemo(() => {
59
+ return composeValidators(_validate, required());
60
+ }, [_validate, required]);
61
+ const { fieldState } = useInput({ ...props, validate });
62
+ const { error } = fieldState;
63
+ const value = useWatch({ name: source });
22
64
  const isMissingLocalizations = !localizedValueHasAllLocales(value, locales);
23
65
  const [currentLocale] = useLocaleState();
24
66
  const [locale, setLocale] = useState(currentLocale);
@@ -29,6 +71,7 @@ function LocalizedTextInput(props: ILocalizedTextInputProps) {
29
71
  [open, setAnchorEl]
30
72
  );
31
73
  const handleClose = useCallback(() => setAnchorEl(null), [setAnchorEl]);
74
+
32
75
  const MenuItems: Array<ReactElement> = useMemo(() => {
33
76
  return _.map(locales, (l, index) => {
34
77
  return (
@@ -44,9 +87,14 @@ function LocalizedTextInput(props: ILocalizedTextInputProps) {
44
87
  );
45
88
  });
46
89
  }, [locales, setLocale, handleClose, value]);
47
-
48
90
  return (
49
- <LabeledInput {...props} helperText={error?.message}>
91
+ <LabeledInput
92
+ {...props}
93
+ validate={validate}
94
+ helperText={
95
+ error?.message ? <ValidationError error={error?.message as ValidationErrorMessage} /> : props?.helperText
96
+ }
97
+ >
50
98
  <>
51
99
  <Box flex={1}>
52
100
  {_.map(locales, (l, index) => {
@@ -57,6 +105,8 @@ function LocalizedTextInput(props: ILocalizedTextInputProps) {
57
105
  source={`${source}.${l.locale}`}
58
106
  sx={{ width: '100%', display: l.locale === locale ? 'inline-flex' : 'none' }}
59
107
  label={false}
108
+ helperText={false}
109
+ required={false}
60
110
  InputProps={{
61
111
  endAdornment: (
62
112
  <Chip
@@ -1,9 +1,17 @@
1
- import { BooleanInput, SimpleForm, TextInput } from '@/';
1
+ import { BooleanInput, LocalizedTextInput, SimpleForm, required } from '@/';
2
2
 
3
+ function requiredAtLeastOneTranslation(message = 'ra.validation.at_least_one_translation') {
4
+ return (value, values) => {
5
+ if (!value || !Object.keys(value).length) {
6
+ return message;
7
+ }
8
+ return undefined;
9
+ };
10
+ }
3
11
  function CategoryForm(props) {
4
12
  return (
5
13
  <SimpleForm {...props}>
6
- <TextInput source="description" fullWidth />
14
+ <LocalizedTextInput source="description" fullWidth validate={requiredAtLeastOneTranslation()} />
7
15
  <BooleanInput source="active" />
8
16
  </SimpleForm>
9
17
  );
@@ -1,4 +1,5 @@
1
1
  import {
2
+ DateField,
2
3
  ReadonlyField,
3
4
  SimpleForm,
4
5
  TextInput,
@@ -16,7 +17,9 @@ function DeviceForm() {
16
17
  <Grid container spacing={spacing}>
17
18
  {record?.id ? (
18
19
  <Grid item xs={12} sm={12}>
19
- <ReadonlyField source="registrationDate" fullWidth />
20
+ <ReadonlyField source="registrationDate" fullWidth>
21
+ <DateField showTime />
22
+ </ReadonlyField>
20
23
  </Grid>
21
24
  ) : null}
22
25
  <Grid item xs={12} sm={12}>
@@ -7,6 +7,7 @@ import {
7
7
  Empty,
8
8
  FilterButton,
9
9
  List,
10
+ LocalizedTextField,
10
11
  SearchInput,
11
12
  SimpleForm,
12
13
  TextField,
@@ -51,7 +52,7 @@ function CategoryList() {
51
52
  empty={<Empty actions={<CategoryAddButton />} />}
52
53
  >
53
54
  <Datagrid>
54
- <TextField source="description" />
55
+ <LocalizedTextField source="description" />
55
56
  <EditInDialogButton>
56
57
  <CategoryForm />
57
58
  </EditInDialogButton>
@@ -4,7 +4,7 @@ if (appUrl.endsWith(':3000/') || appUrl.indexOf(':51') !== -1) {
4
4
  appUrl = 'http://localhost:8080/';
5
5
  environment = 'DEVELOPER';
6
6
  }
7
- const APP_NAME = 'RApplica';
7
+ const APP_NAME = 'Applica';
8
8
  const APP_URL = appUrl;
9
9
  const API_URL = `${APP_URL}api`;
10
10
  const ENVIRONMENT = environment;
@@ -20,13 +20,6 @@ export const menu = [
20
20
  type: 'item',
21
21
  url: '/entities/notification',
22
22
  icon: NotificationOutlined
23
- },
24
- {
25
- id: 'entities/order',
26
- title: 'ra.menu.item.order',
27
- type: 'item',
28
- url: '/entities/order',
29
- icon: TableOutlined
30
23
  }
31
24
  ]
32
25
  },
@@ -16,6 +16,15 @@ function localizedValueHasAllLocales<T>(
16
16
  return !_.some(locales, (l) => isEmpty((value ?? {})[l.locale]));
17
17
  }
18
18
 
19
+ function localizedValueHasAtLeastOneLocale<T>(
20
+ value: ILocalizedValue<T> = {},
21
+ locales: Array<ILocale> = [],
22
+ options: { isEmpty?: (v: T) => boolean } = {}
23
+ ): boolean {
24
+ const { isEmpty = _.isEmpty } = options;
25
+ return _.some(locales, (l) => !isEmpty((value ?? {})[l.locale]));
26
+ }
27
+
19
28
  type IGetLocalizedValueOptions = {
20
29
  fallback?: boolean;
21
30
  fallbackLocales?: Array<string>;
@@ -52,4 +61,4 @@ function getLocalizedValue<T>(
52
61
  }
53
62
 
54
63
  export type { IGetLocalizedValueOptions, ILocalizedValue };
55
- export { getLocalizedValue, localizedValueHasAllLocales };
64
+ export { getLocalizedValue, localizedValueHasAllLocales, localizedValueHasAtLeastOneLocale };