@acvl/frontend-components 0.0.36 → 0.0.38

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.
@@ -3,6 +3,7 @@ import React from "react";
3
3
  import { ButtonProps } from "@mui/material";
4
4
  export interface ControlledFileFieldProps extends BaseControlledFieldProps {
5
5
  extraProps?: {
6
+ multiple?: boolean;
6
7
  slotProps?: {
7
8
  input?: {
8
9
  accept?: string;
@@ -21,6 +21,7 @@ export interface FieldProps {
21
21
  fieldName: string;
22
22
  value: any;
23
23
  method: any;
24
+ showOnDetail?: boolean;
24
25
  };
25
26
  filters?: FieldFilter[];
26
27
  navigation?: {
@@ -4,7 +4,7 @@ import { ReactNode } from "react";
4
4
  import { FieldValidationProps, EditReadOnlyFields } from "../types";
5
5
  import { PageType } from "../../../../types";
6
6
  export interface SectionProps {
7
- display?: boolean | FieldValidationProps;
7
+ display?: boolean | FieldValidationProps | FieldValidationProps[];
8
8
  data?: any;
9
9
  form?: any;
10
10
  bgColor?: string;
package/dist/esm/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  'use client';
2
2
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
3
- import { useTheme, useMediaQuery, Tooltip, IconButton, Button, Grid, FormGroup, FormHelperText as FormHelperText$1, Drawer, Box, Stack, CircularProgress, Typography as Typography$1, List as List$1, ListItem as ListItem$1, ListSubheader, styled as styled$1, LinearProgress, Autocomplete, Checkbox, Slider, Switch, InputAdornment as InputAdornment$1, ToggleButtonGroup, ToggleButton, TextField as TextField$1, Dialog, DialogTitle, DialogContent as DialogContent$1, DialogActions as DialogActions$1, DialogContentText, ButtonGroup, Menu, ListItemIcon, MenuItem as MenuItem$1, Link, Card, CardHeader, Avatar, CardContent, Divider as Divider$1, Popper, Grow as Grow$1, Paper, ClickAwayListener, Badge, TablePagination, NoSsr, tooltipClasses, Collapse, Fade as Fade$1, Slide, Zoom, Snackbar, alpha as alpha$1, lighten, createTheme as createTheme$1, responsiveFontSizes } from '@mui/material';
3
+ import { useTheme, useMediaQuery, Tooltip, IconButton, Button, Grid, FormGroup, FormHelperText as FormHelperText$1, Drawer, Box, Stack, CircularProgress, Typography as Typography$1, List as List$1, ListItem as ListItem$1, ListSubheader, styled as styled$1, LinearProgress, Autocomplete, Checkbox, Slider, Switch, InputAdornment as InputAdornment$1, ToggleButtonGroup, ToggleButton, TextField as TextField$1, Dialog, DialogTitle, DialogContent as DialogContent$1, DialogActions as DialogActions$1, DialogContentText, ButtonGroup, Menu, ListItemIcon, MenuItem as MenuItem$1, Link, Card, CardHeader, Avatar, CardContent, Divider as Divider$1, Popper, Grow as Grow$1, Paper, ClickAwayListener, Badge, TablePagination, NoSsr, tooltipClasses, Popover, ListItemButton, ListItemText as ListItemText$1, Collapse, Fade as Fade$1, Slide, Zoom, Snackbar, alpha as alpha$1, lighten, createTheme as createTheme$1, responsiveFontSizes } from '@mui/material';
4
4
  import EditIcon from '@mui/icons-material/Edit';
5
5
  import * as React from 'react';
6
6
  import React__default, { useCallback, useEffect, isValidElement, cloneElement, Children, createContext, useContext, useState, useMemo, useRef, useImperativeHandle, useLayoutEffect, Suspense, forwardRef } from 'react';
@@ -97,6 +97,7 @@ import DrawIcon from '@mui/icons-material/Draw';
97
97
  import CloseIcon from '@mui/icons-material/Close';
98
98
  import ErrorOutlineIcon from '@mui/icons-material/ErrorOutline';
99
99
  import { skipToken } from '@reduxjs/toolkit/query';
100
+ import OpenInNewIcon from '@mui/icons-material/OpenInNew';
100
101
  import TabList from '@mui/lab/TabList';
101
102
  import TabPanel from '@mui/lab/TabPanel';
102
103
  import TabContext from '@mui/lab/TabContext';
@@ -26518,7 +26519,19 @@ const VisuallyHiddenInput = styled$1("input")({
26518
26519
  });
26519
26520
  const ControlledFileField = (props) => {
26520
26521
  return (jsx(Controller, { control: props.control, name: props.name, render: ({ field: { value, onChange, onBlur, ref }, fieldState: { error } }) => {
26521
- return (jsxs(FormGroup, { sx: { width: 1 }, color: "secondary", children: [value ? (jsxs(Stack, { direction: "row", spacing: 1, width: 1, alignItems: "center", children: [jsx(Typography$1, { children: value.name }), jsx(IconButton, { onClick: () => onChange(null), children: jsx(ClearIcon$1, { color: "error" }) })] })) : (jsxs(Button, { component: "label", variant: "contained", startIcon: jsx(UploadFileIcon, {}), sx: { maxWidth: 200 }, ...props.extraProps?.slotProps?.button, children: ["Cargar", jsx(VisuallyHiddenInput, { type: "file", accept: "image/*", ref: ref, onBlur: onBlur, onChange: (e) => onChange(e.target.files && e.target.files[0]), ...props.extraProps?.slotProps?.input })] })), jsx(FormHelperText$1, { error: !!error, children: error ? error.message : " " })] }));
26522
+ if (props.extraProps?.multiple) {
26523
+ const files = value ?? [];
26524
+ const handleAdd = (e) => {
26525
+ const incoming = e.target.files ? Array.from(e.target.files) : [];
26526
+ onChange([...files, ...incoming]);
26527
+ e.target.value = "";
26528
+ };
26529
+ const handleRemove = (index) => {
26530
+ onChange(files.filter((_, i) => i !== index));
26531
+ };
26532
+ return (jsxs(FormGroup, { sx: { width: 1 }, children: [jsxs(Stack, { spacing: 1, width: 1, children: [files.map((file, index) => (jsxs(Stack, { direction: "row", spacing: 1, alignItems: "center", sx: { minWidth: 0 }, children: [jsx(Typography$1, { noWrap: true, sx: { flex: 1 }, children: file.name }), jsx(IconButton, { onClick: () => handleRemove(index), children: jsx(ClearIcon$1, { color: "error" }) })] }, index))), jsxs(Button, { component: "label", variant: "contained", startIcon: jsx(UploadFileIcon, {}), sx: { maxWidth: 200 }, ...props.extraProps?.slotProps?.button, children: ["Cargar", jsx(VisuallyHiddenInput, { type: "file", multiple: true, accept: "image/*", ref: ref, onBlur: onBlur, onChange: handleAdd, ...props.extraProps?.slotProps?.input })] })] }), jsx(FormHelperText$1, { error: !!error, children: error ? error.message : " " })] }));
26533
+ }
26534
+ return (jsxs(FormGroup, { sx: { width: 1 }, color: "secondary", children: [value ? (jsxs(Stack, { direction: "row", spacing: 1, width: 1, alignItems: "center", sx: { minWidth: 0 }, children: [jsx(Typography$1, { noWrap: true, sx: { flex: 1 }, children: value.name }), jsx(IconButton, { onClick: () => onChange(null), children: jsx(ClearIcon$1, { color: "error" }) })] })) : (jsxs(Button, { component: "label", variant: "contained", startIcon: jsx(UploadFileIcon, {}), sx: { maxWidth: 200 }, ...props.extraProps?.slotProps?.button, children: ["Cargar", jsx(VisuallyHiddenInput, { type: "file", accept: "image/*", ref: ref, onBlur: onBlur, onChange: (e) => onChange(e.target.files && e.target.files[0]), ...props.extraProps?.slotProps?.input })] })), jsx(FormHelperText$1, { error: !!error, children: error ? error.message : " " })] }));
26522
26535
  } }));
26523
26536
  };
26524
26537
  ControlledFileField.displayName = "ControlledFileField";
@@ -28159,6 +28172,7 @@ const LinkField = ({ url, value, text }) => {
28159
28172
  return jsx(Link, { href: `${url}/${value}`, children: text });
28160
28173
  };
28161
28174
  const DetailField = (props) => {
28175
+ const [anchor, setAnchor] = useState(null);
28162
28176
  const hasLinkToViewPermission = useHasPermission(`${props.navigation?.permission}.view`);
28163
28177
  const value = useCallback(() => {
28164
28178
  const { fieldData, type, extraProps, detail_name } = props;
@@ -28178,7 +28192,7 @@ const DetailField = (props) => {
28178
28192
  ? dayjs(fieldData).format("YYYY-MM-DD HH:mm")
28179
28193
  : dayjs(fieldData).format("YYYY-MM-DD");
28180
28194
  case "ControlledFileField":
28181
- return fieldData ? "Archivo" : "N/A";
28195
+ return fieldData ? "Archivo(s)" : "N/A";
28182
28196
  default:
28183
28197
  if (!fieldData)
28184
28198
  return "N/A";
@@ -28196,7 +28210,13 @@ const DetailField = (props) => {
28196
28210
  return (jsx(LinkField, { url: props.navigation.url, value: get(props.fieldData, "value"), text: content }));
28197
28211
  }
28198
28212
  else if (props.type.displayName == "ControlledFileField" && content !== "N/A") {
28199
- return (jsx(Link, { href: props.fieldData, target: "_blank", rel: "noopener noreferrer", children: content }));
28213
+ const archivos = Array.isArray(props.fieldData)
28214
+ ? props.fieldData.filter(Boolean)
28215
+ : [props.fieldData];
28216
+ return (jsxs(Fragment, { children: [jsx(Badge, { badgeContent: archivos.length, color: "primary", sx: { "& .MuiBadge-badge": { fontSize: 10, minWidth: 16, height: 16 } }, children: jsx(Button, { size: "small", onClick: (e) => {
28217
+ e.stopPropagation();
28218
+ setAnchor(e.currentTarget);
28219
+ }, children: content }) }), jsx(Popover, { open: Boolean(anchor), anchorEl: anchor, onClose: () => setAnchor(null), anchorOrigin: { vertical: "bottom", horizontal: "center" }, transformOrigin: { vertical: "top", horizontal: "center" }, onClick: (e) => e.stopPropagation(), children: jsx(List$1, { dense: true, disablePadding: true, sx: { minWidth: 140 }, children: archivos.map((archivo, i) => (jsxs(ListItemButton, { component: "a", href: archivo.imagen ?? archivo, target: "_blank", rel: "noopener noreferrer", onClick: (e) => e.stopPropagation(), children: [jsx(ListItemText$1, { primary: `Archivo ${i + 1}` }), jsx(OpenInNewIcon, { fontSize: "small", sx: { ml: 1, opacity: 0.6 } })] }, i))) }) })] }));
28200
28220
  }
28201
28221
  else {
28202
28222
  if (Array.isArray(props.fieldData)) {
@@ -28244,6 +28264,8 @@ const Field = (props) => {
28244
28264
  const formData = props.form.watch();
28245
28265
  const show = useMemo(() => {
28246
28266
  if (props.dependantOn) {
28267
+ if (props.dependantOn.showOnDetail && props.pageType === "detail")
28268
+ return true;
28247
28269
  return props.dependantOn.method(get(props.data || formData, props.dependantOn.fieldName), props.dependantOn.value);
28248
28270
  }
28249
28271
  return true;
@@ -28272,6 +28294,7 @@ const FieldArrayField = (props) => {
28272
28294
  keyName: "_id",
28273
28295
  });
28274
28296
  const errors = props.form.formState.errors;
28297
+ const errorMessage = get(props.form.formState.errors, props.name + ".message");
28275
28298
  const getIndex = useCallback((id) => findIndex(fields, function (field) {
28276
28299
  return field._id == id;
28277
28300
  }), [fields]);
@@ -28352,31 +28375,27 @@ const FieldArrayField = (props) => {
28352
28375
  fieldProps: field.fieldProps,
28353
28376
  extraProps: field.extraProps,
28354
28377
  }) })] }, `grid-${index}`));
28355
- }) }) }), jsxs(Grid, { rowSpacing: 1, container: true, size: "grow", direction: "column", ...props.gridProps, children: [jsx(Grid, { size: 12, children: jsx(Typography$1, { variant: "body1", fontWeight: "bold", children: props.label }) }), jsx(Grid, { size: 12, children: jsx(DataGrid, { ...dataGridProps }) })] })] }));
28378
+ }) }) }), jsxs(Grid, { rowSpacing: 1, container: true, size: "grow", direction: "column", ...props.gridProps, children: [jsx(Grid, { size: 12, children: jsx(Typography$1, { variant: "body1", fontWeight: "bold", children: props.label }) }), errorMessage && (jsx(Grid, { size: 12, children: jsx(Typography$1, { variant: "body1", color: "error", children: errorMessage }) })), jsx(Grid, { size: 12, children: jsx(DataGrid, { ...dataGridProps }) })] })] }));
28356
28379
  };
28357
28380
 
28358
28381
  const Section = (props) => {
28359
28382
  const [expanded, setExpanded] = useState(true);
28360
28383
  const handleExpandChange = () => {
28361
- setExpanded(prevState => !prevState);
28384
+ setExpanded((prevState) => !prevState);
28362
28385
  };
28363
28386
  const renderField = (field, index) => {
28364
28387
  if (props.first && index == 0)
28365
- merge$2(get(field, 'fieldProps', {}), { autoFocus: true });
28388
+ merge$2(get(field, "fieldProps", {}), { autoFocus: true });
28366
28389
  return (jsx(Field, { fieldData: props.data && get(props.data, field.name), ...field, readOnly:
28367
28390
  // props.validation?.readOnlyFields.includes(field.name) ||
28368
- (props.edit?.readOnlyFields?.names.includes(field.name) && props.edit.readOnlyFields.validator.method(get(props.data, props.edit.readOnlyFields.validator.field), props.edit.readOnlyFields.validator.value)), form: props.form, pageType: props.pageType, data: props.data }, `F-${index}`));
28391
+ props.edit?.readOnlyFields?.names.includes(field.name) &&
28392
+ props.edit.readOnlyFields.validator.method(get(props.data, props.edit.readOnlyFields.validator.field), props.edit.readOnlyFields.validator.value), form: props.form, pageType: props.pageType, data: props.data }, `F-${index}`));
28369
28393
  };
28370
28394
  const renderArrayField = (field, index) => (jsx(FieldArrayField, { ...field, form: props.form, pageType: props.pageType }, `FA-${index}`));
28371
- return (jsxs(Grid, { size: 12, container: true, spacing: 2, bgcolor: props.bgColor, p: 2, borderRadius: 1, children: [(props.title || props.description) &&
28372
- jsxs(Grid, { size: 12, container: true, spacing: 0, children: [props.title &&
28373
- jsxs(Grid, { size: 12, container: true, onClick: handleExpandChange, sx: {
28374
- cursor: 'pointer'
28375
- }, children: [jsx(Grid, { children: expanded ? jsx(ExpandLessIcon, { fontSize: 'small' }) : jsx(ExpandMoreIcon, { fontSize: 'small' }) }), jsx(Grid, { children: jsx(Typography$1, { variant: 'h5', children: props.title }) })] }), props.description &&
28376
- jsx(Grid, { size: 12, children: jsx(Typography$1, { variant: 'caption', color: 'secondary.main', children: props.description }) })] }), expanded &&
28377
- jsxs(Grid, { size: 12, container: true, direction: 'row', children: [props.fields &&
28378
- props.fields.map((field, index) => renderField(field, index)), props.arrayFields &&
28379
- props.arrayFields.map((arrayField, index) => renderArrayField(arrayField, index)), props.content && props.content(props.data)] })] }));
28395
+ return (jsxs(Grid, { size: 12, container: true, spacing: 2, bgcolor: props.bgColor, p: 2, borderRadius: 1, children: [(props.title || props.description) && (jsxs(Grid, { size: 12, container: true, spacing: 0, children: [props.title && (jsxs(Grid, { size: 12, container: true, onClick: handleExpandChange, sx: {
28396
+ cursor: "pointer",
28397
+ }, children: [jsx(Grid, { children: expanded ? (jsx(ExpandLessIcon, { fontSize: "small" })) : (jsx(ExpandMoreIcon, { fontSize: "small" })) }), jsx(Grid, { children: jsx(Typography$1, { variant: "h5", children: props.title }) })] })), props.description && (jsx(Grid, { size: 12, children: jsx(Typography$1, { variant: "caption", color: "secondary.main", children: props.description }) }))] })), expanded && (jsxs(Grid, { size: 12, container: true, direction: "row", children: [props.fields && props.fields.map((field, index) => renderField(field, index)), props.arrayFields &&
28398
+ props.arrayFields.map((arrayField, index) => renderArrayField(arrayField, index)), props.content && props.content(props.data)] }))] }));
28380
28399
  };
28381
28400
 
28382
28401
  // ==============================|| VALIDATION ||============================== //
@@ -28585,7 +28604,7 @@ function DetailPage(props) {
28585
28604
  }
28586
28605
  }
28587
28606
  }, [data, dispatch, form, props.slots?.title]);
28588
- const [mutation, { isLoading: mutationIsLoading, isSuccess, data: mutationResponse },] = props.api.mutate.mutation();
28607
+ const [mutation, { isLoading: mutationIsLoading, isSuccess, data: mutationResponse }] = props.api.mutate.mutation();
28589
28608
  const handleCancel = () => {
28590
28609
  form.reset();
28591
28610
  navigate(-1);
@@ -28595,8 +28614,7 @@ function DetailPage(props) {
28595
28614
  // ==============================|| VALIDATION ||============================== //
28596
28615
  useValidateFieldData(props, form);
28597
28616
  // ==============================|| QUICK RETURN ||============================== //
28598
- if ((!canEdit && props.pageType == "edit") ||
28599
- (fetchError && fetchError.originalStatus == 403))
28617
+ if ((!canEdit && props.pageType == "edit") || (fetchError && fetchError.originalStatus == 403))
28600
28618
  return jsx(NotAllowed, {});
28601
28619
  if (fetchError && fetchError.originalStatus == 404)
28602
28620
  return jsx(NotFound, {});
@@ -28610,9 +28628,7 @@ function DetailPage(props) {
28610
28628
  props: props.slotProps?.parser,
28611
28629
  };
28612
28630
  const dataToSend = formParser(params);
28613
- mutation(props.edit.useFormData
28614
- ? dataToSend
28615
- : { ...dataToSend, ...props.api.mutate.args })
28631
+ mutation(props.edit.useFormData ? dataToSend : { ...dataToSend, ...props.api.mutate.args })
28616
28632
  .unwrap()
28617
28633
  .then(() => {
28618
28634
  if (!props.slotProps?.button?.save?.disableNavBack)
@@ -28638,17 +28654,26 @@ function DetailPage(props) {
28638
28654
  };
28639
28655
  const onError = (errors) => console.log("Validation Errors:", errors);
28640
28656
  // ==============================|| RENDER SECTIONS ||============================== //
28657
+ const validateDisplay = (field, method, value) => {
28658
+ const validateAgainst = form.watch(field)?.toString();
28659
+ return method(validateAgainst, value);
28660
+ };
28641
28661
  const renderContent = () => {
28642
28662
  let displayed_sections = -1;
28643
28663
  return (jsxs(Grid, { size: 12, container: true, direction: "column", position: "relative", pb: 2, children: [props.pageType == "detail" && data?.has_history && (jsx(HistorialDrawer, { ...props.slotProps?.historial })), props.sections.map((section, index) => {
28644
28664
  if (!section.display)
28645
28665
  return null;
28646
28666
  if (typeof section.display == "object") {
28647
- const validateAgainst = form
28648
- .watch(section.display.field)
28649
- ?.toString();
28650
- if (!section.display.method(validateAgainst, section.display.value))
28651
- return null;
28667
+ if (Array.isArray(section.display)) {
28668
+ if (!section.display
28669
+ .map((item) => validateDisplay(item.field, item.method, item.value))
28670
+ .every((item) => item == true))
28671
+ return null;
28672
+ }
28673
+ else {
28674
+ if (!validateDisplay(section.display.field, section.display.method, section.display.value))
28675
+ return null;
28676
+ }
28652
28677
  }
28653
28678
  displayed_sections += 1;
28654
28679
  return (jsx(Section, { data: data, form: form, bgColor: displayed_sections % 2 == 1 ? "white" : "#F7F7F7", pageType: props.pageType, ...section, first: displayed_sections == 0 }, index));
@@ -28658,8 +28683,7 @@ function DetailPage(props) {
28658
28683
  if (props.api.mutate.postAction &&
28659
28684
  isSuccess &&
28660
28685
  "post_action" in mutationResponse &&
28661
- mutationResponse["post_action"]["type"] ===
28662
- props.api.mutate.postAction.type) {
28686
+ mutationResponse["post_action"]["type"] === props.api.mutate.postAction.type) {
28663
28687
  switch (props.api.mutate.postAction.after) {
28664
28688
  // case 'create':
28665
28689
  // if (props.pageType === 'create') return addPropsToNode(props.api.mutate.postAction.node, mutationResponse);