@acvl/frontend-components 0.0.35 → 0.0.36

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.
@@ -6,7 +6,13 @@ export interface CSVMenuOptionProps {
6
6
  custom?: string;
7
7
  icon?: any;
8
8
  }
9
+ export interface ExtraCreateOptionProps {
10
+ title: string;
11
+ icon: any;
12
+ onClick: () => void;
13
+ }
9
14
  export interface CreateGridAPIProps {
15
+ extraOptions?: ExtraCreateOptionProps[];
10
16
  csv_upload?: {
11
17
  enable: boolean;
12
18
  extraOptions?: CSVMenuOptionProps[];
@@ -0,0 +1,18 @@
1
+ import React from "react";
2
+ import type { AutocompleteProps } from "@mui/material";
3
+ import { ComoOpcionesProps } from "../../../types";
4
+ export interface CrudDropdownProps {
5
+ name: string;
6
+ label?: string;
7
+ control: any;
8
+ fieldProps?: Partial<AutocompleteProps<any, any, any, any>>;
9
+ extraProps: {
10
+ queryArgs: ComoOpcionesProps;
11
+ crudExtraArgs?: Record<string, any>;
12
+ /** API field name for the display label. Default: "nombre" */
13
+ labelField?: string;
14
+ disableHT?: boolean;
15
+ };
16
+ }
17
+ declare const CrudDropdown: React.FC<CrudDropdownProps>;
18
+ export default CrudDropdown;
@@ -11,3 +11,4 @@ export { default as ControlledToggleButtons } from "./ControlledToggleButtons";
11
11
  export { default as ControlledTimePicker } from "./ControlledTimePicker";
12
12
  export { default as ControlledFileField } from "./ControlledFileField";
13
13
  export { default as ControlledSimpleSlider } from "./ControlledSimpleSlider";
14
+ export { default as CrudDropdown } from "./CrudDropdown";
@@ -1,4 +1,4 @@
1
- import { ReactNode } from 'react';
1
+ import { ReactNode } from "react";
2
2
  export interface APIcontextProps {
3
3
  useLazyGetComoOpcionesQuery: any;
4
4
  useLazyGetHistorialQuery: any;
@@ -6,9 +6,10 @@ export interface APIcontextProps {
6
6
  useValidarCSVMutation: any;
7
7
  useSubirCSVMutation: any;
8
8
  useRemoverCSVMutation: any;
9
+ useGenericCrudMutation: any;
9
10
  }
10
11
  declare const APIContext: import("react").Context<APIcontextProps | null>;
11
- export declare const APIProvider: ({ children, hooks }: {
12
+ export declare const APIProvider: ({ children, hooks, }: {
12
13
  children: ReactNode;
13
14
  hooks: APIcontextProps;
14
15
  }) => import("react/jsx-runtime").JSX.Element;
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, Dialog, DialogTitle, DialogContent as DialogContent$1, DialogContentText, DialogActions as DialogActions$1, 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, 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';
@@ -41,7 +41,7 @@ import BaseFocusTrap from '@mui/material/Unstable_TrapFocus';
41
41
  import DialogContent from '@mui/material/DialogContent';
42
42
  import MuiDialog, { dialogClasses } from '@mui/material/Dialog';
43
43
  import debounce from 'lodash/debounce';
44
- import { get, map, find, groupBy, forEach, findIndex, mergeWith, isArray, omit, set as set$1, every, includes, merge as merge$2, countBy, isNumber, isEmpty as isEmpty$1, isBoolean, isEqual as isEqual$1, debounce as debounce$1, some } from 'lodash';
44
+ import { get, map, find, groupBy, forEach, findIndex, mergeWith, isArray, omit, set as set$1, debounce as debounce$1, every, includes, merge as merge$2, countBy, isNumber, isEmpty as isEmpty$1, isBoolean, isEqual as isEqual$1, some } from 'lodash';
45
45
  import { produce } from 'immer';
46
46
  import set from 'lodash/set';
47
47
  import get$1 from 'lodash/get';
@@ -68,8 +68,8 @@ import { Visibility, VisibilityOff } from '@mui/icons-material';
68
68
  import merge$1 from 'lodash/merge';
69
69
  import UploadFileIcon from '@mui/icons-material/UploadFile';
70
70
  import ClearIcon$1 from '@mui/icons-material/Clear';
71
- import SaveIcon from '@mui/icons-material/Save';
72
71
  import AddIcon from '@mui/icons-material/Add';
72
+ import SaveIcon from '@mui/icons-material/Save';
73
73
  import KeyboardArrowDownIcon from '@mui/icons-material/KeyboardArrowDown';
74
74
  import LinearProgress$1 from '@mui/material/LinearProgress';
75
75
  import AttachFileIcon from '@mui/icons-material/AttachFile';
@@ -25494,8 +25494,8 @@ const useHasPermission = (path) => {
25494
25494
  };
25495
25495
 
25496
25496
  const APIContext = createContext(null);
25497
- const APIProvider = ({ children, hooks }) => {
25498
- return (jsx(APIContext.Provider, { value: hooks, children: children }));
25497
+ const APIProvider = ({ children, hooks, }) => {
25498
+ return jsx(APIContext.Provider, { value: hooks, children: children });
25499
25499
  };
25500
25500
 
25501
25501
  const useAPI = () => {
@@ -26532,6 +26532,161 @@ const ControlledSlider = (props) => {
26532
26532
  } }));
26533
26533
  };
26534
26534
 
26535
+ const CREATE_OPTION = { value: "__create__", label: "" };
26536
+ const CrudDropdown = (props) => {
26537
+ const { name, label, control, fieldProps, extraProps: { queryArgs, crudExtraArgs = {}, labelField = "nombre", disableHT }, } = props;
26538
+ const [inputValue, setInputValue] = useState("");
26539
+ const [options, setOptions] = useState([]);
26540
+ const [open, setOpen] = useState(false);
26541
+ const [createOpen, setCreateOpen] = useState(false);
26542
+ const [editOpen, setEditOpen] = useState(false);
26543
+ const [deleteOpen, setDeleteOpen] = useState(false);
26544
+ const [activeOption, setActiveOption] = useState(null);
26545
+ const [dialogInput, setDialogInput] = useState("");
26546
+ const formValueRef = useRef(null);
26547
+ const formOnChangeRef = useRef(() => { });
26548
+ const api = useAPI();
26549
+ const [getOpciones, { isLoading, isFetching, isError }] = api.useLazyGetComoOpcionesQuery();
26550
+ const [genericCrud, { isLoading: isMutating }] = api.useGenericCrudMutation();
26551
+ const notifications = useNotifications();
26552
+ const args = useMemo(() => ({
26553
+ ...queryArgs,
26554
+ filters: { ...queryArgs.filters, nombre__icontains: inputValue },
26555
+ }), [inputValue, queryArgs]);
26556
+ const fetchOptions = useCallback(debounce$1((fetchArgs, cb) => {
26557
+ setOptions([]);
26558
+ getOpciones(fetchArgs)
26559
+ .unwrap()
26560
+ .then(cb)
26561
+ .catch(() => { });
26562
+ }, 500), []);
26563
+ const refreshOptions = () => {
26564
+ getOpciones(args, false)
26565
+ .unwrap()
26566
+ .then((fresh) => setOptions(fresh))
26567
+ .catch(() => { });
26568
+ };
26569
+ React__default.useEffect(() => {
26570
+ if (open)
26571
+ fetchOptions(args, setOptions);
26572
+ }, [args, fetchOptions, open]);
26573
+ const handleCreate = () => {
26574
+ genericCrud({
26575
+ endpoint: props.extraProps.queryArgs.endpoint,
26576
+ method: "POST",
26577
+ body: { [labelField]: dialogInput, ...crudExtraArgs },
26578
+ })
26579
+ .unwrap()
26580
+ .then(() => {
26581
+ notifications.show("Opción creada.", { severity: "success" });
26582
+ setCreateOpen(false);
26583
+ setDialogInput("");
26584
+ refreshOptions();
26585
+ })
26586
+ .catch(() => notifications.show("Error al crear.", { severity: "error" }));
26587
+ };
26588
+ const handleEdit = () => {
26589
+ if (!activeOption)
26590
+ return;
26591
+ genericCrud({
26592
+ endpoint: props.extraProps.queryArgs.endpoint,
26593
+ method: "PATCH",
26594
+ id: activeOption.value,
26595
+ body: { [labelField]: dialogInput, ...crudExtraArgs },
26596
+ })
26597
+ .unwrap()
26598
+ .then(() => {
26599
+ if (formValueRef.current?.value === activeOption.value) {
26600
+ formOnChangeRef.current({ value: activeOption.value, label: dialogInput });
26601
+ }
26602
+ notifications.show("Opción actualizada.", { severity: "success" });
26603
+ setEditOpen(false);
26604
+ setDialogInput("");
26605
+ setActiveOption(null);
26606
+ refreshOptions();
26607
+ })
26608
+ .catch(() => notifications.show("Error al actualizar.", { severity: "error" }));
26609
+ };
26610
+ const handleDelete = () => {
26611
+ if (!activeOption)
26612
+ return;
26613
+ genericCrud({
26614
+ endpoint: props.extraProps.queryArgs.endpoint,
26615
+ method: "DELETE",
26616
+ id: activeOption.value,
26617
+ })
26618
+ .unwrap()
26619
+ .then(() => {
26620
+ if (formValueRef.current?.value === activeOption.value) {
26621
+ formOnChangeRef.current(null);
26622
+ }
26623
+ notifications.show("Opción eliminada.", { severity: "success" });
26624
+ setDeleteOpen(false);
26625
+ setActiveOption(null);
26626
+ refreshOptions();
26627
+ })
26628
+ .catch(() => notifications.show("Error al eliminar.", { severity: "error" }));
26629
+ };
26630
+ return (jsxs(Fragment, { children: [jsx(Controller, { name: name, control: control, render: ({ field: { value, onChange }, fieldState: { error } }) => {
26631
+ formValueRef.current = value;
26632
+ formOnChangeRef.current = onChange;
26633
+ const handleChange = (_event, newValue) => {
26634
+ if (newValue?.value === "__create__") {
26635
+ setDialogInput("");
26636
+ setCreateOpen(true);
26637
+ return;
26638
+ }
26639
+ onChange(newValue);
26640
+ };
26641
+ return (jsx(Autocomplete, { id: name, open: open, onOpen: () => setOpen(true), onClose: () => setOpen(false), options: options, loading: isLoading || isFetching, value: value, onChange: handleChange, inputValue: inputValue, onInputChange: (_event, newInputValue) => setInputValue(newInputValue), isOptionEqualToValue: (option, val) => option.value === val.value, filterOptions: (x) => [CREATE_OPTION, ...x], getOptionLabel: (option) => option.value === "__create__" ? "" : option.label || "", fullWidth: true, size: "small", disabled: isError, renderOption: (optionProps, option) => {
26642
+ const { key, ...rest } = optionProps;
26643
+ if (option.value === "__create__") {
26644
+ return (jsxs(Box, { component: "li", ...rest, onClick: () => {
26645
+ setDialogInput("");
26646
+ setCreateOpen(true);
26647
+ }, sx: {
26648
+ justifyContent: "center !important",
26649
+ color: "primary.main",
26650
+ borderBottom: "1px solid",
26651
+ borderColor: "divider",
26652
+ py: "6px !important",
26653
+ gap: 0.5,
26654
+ }, children: [jsx(AddIcon, { fontSize: "small" }), jsx(Typography$1, { variant: "body2", children: "Agregar nuevo" })] }, key));
26655
+ }
26656
+ return (jsxs(Box, { component: "li", ...rest, sx: {
26657
+ display: "flex",
26658
+ alignItems: "center",
26659
+ pr: "4px !important",
26660
+ }, children: [jsx(Box, { sx: {
26661
+ flex: 1,
26662
+ overflow: "hidden",
26663
+ textOverflow: "ellipsis",
26664
+ }, children: option.label }), jsx(IconButton, { size: "small", tabIndex: -1, onMouseDown: (e) => {
26665
+ e.stopPropagation();
26666
+ e.preventDefault();
26667
+ }, onClick: (e) => {
26668
+ e.stopPropagation();
26669
+ setActiveOption(option);
26670
+ setDialogInput(option.label);
26671
+ setEditOpen(true);
26672
+ }, children: jsx(EditIcon, { fontSize: "inherit" }) }), jsx(IconButton, { size: "small", tabIndex: -1, onMouseDown: (e) => {
26673
+ e.stopPropagation();
26674
+ e.preventDefault();
26675
+ }, onClick: (e) => {
26676
+ e.stopPropagation();
26677
+ setActiveOption(option);
26678
+ setDeleteOpen(true);
26679
+ }, children: jsx(DeleteIcon, { fontSize: "inherit" }) })] }, key));
26680
+ }, renderInput: (params) => (jsx(TextField$1, { ...params, label: label, error: !!error, helperText: error ? error.message : disableHT ? "" : " ", slotProps: {
26681
+ input: {
26682
+ ...params.InputProps,
26683
+ endAdornment: (jsxs(Fragment, { children: [isLoading || isFetching ? (jsx(CircularProgress, { color: "inherit", size: 20 })) : null, params.InputProps.endAdornment] })),
26684
+ },
26685
+ } })), ...fieldProps }));
26686
+ } }), jsxs(Dialog, { open: createOpen, onClose: () => setCreateOpen(false), maxWidth: "xs", fullWidth: true, children: [jsx(DialogTitle, { children: "Agregar opci\u00F3n" }), jsx(DialogContent$1, { children: jsx(TextField$1, { autoFocus: true, fullWidth: true, size: "small", label: label, value: dialogInput, onChange: (e) => setDialogInput(e.target.value), onKeyDown: (e) => e.key === "Enter" && !!dialogInput && handleCreate(), sx: { mt: 1 } }) }), jsxs(DialogActions$1, { children: [jsx(Button, { color: "error", onClick: () => setCreateOpen(false), children: "Cancelar" }), jsx(Button, { color: "secondary", disabled: !dialogInput, loading: isMutating, onClick: handleCreate, children: "Guardar" })] })] }), jsxs(Dialog, { open: editOpen, onClose: () => setEditOpen(false), maxWidth: "xs", fullWidth: true, children: [jsx(DialogTitle, { children: "Editar opci\u00F3n" }), jsx(DialogContent$1, { children: jsx(TextField$1, { autoFocus: true, fullWidth: true, size: "small", label: label, value: dialogInput, onChange: (e) => setDialogInput(e.target.value), onKeyDown: (e) => e.key === "Enter" && !!dialogInput && handleEdit(), sx: { mt: 1 } }) }), jsxs(DialogActions$1, { children: [jsx(Button, { color: "error", onClick: () => setEditOpen(false), children: "Cancelar" }), jsx(Button, { color: "secondary", disabled: !dialogInput, loading: isMutating, onClick: handleEdit, children: "Guardar" })] })] }), jsxs(Dialog, { open: deleteOpen, onClose: () => setDeleteOpen(false), maxWidth: "xs", fullWidth: true, children: [jsx(DialogTitle, { children: "Eliminar opci\u00F3n" }), jsx(DialogContent$1, { children: jsxs(Typography$1, { children: ["\u00BFEliminar ", jsx("strong", { children: activeOption?.label }), "?"] }) }), jsxs(DialogActions$1, { children: [jsx(Button, { onClick: () => setDeleteOpen(false), children: "Cancelar" }), jsx(Button, { color: "error", loading: isMutating, onClick: handleDelete, children: "Eliminar" })] })] })] }));
26687
+ };
26688
+ CrudDropdown.displayName = "CrudDropdown";
26689
+
26535
26690
  const DeleteConfirmationDialog = (props) => {
26536
26691
  const notifications = useNotifications();
26537
26692
  const { pathname } = useLocation();
@@ -27655,7 +27810,12 @@ const CreateGridWrapper = (props) => {
27655
27810
  }), jsxs(MenuItem, { onClick: () => {
27656
27811
  navigate(props.navigation ? `${props.navigation}crear` : `crear`);
27657
27812
  handleClose();
27658
- }, disableRipple: true, children: [jsx(ListItemIcon, { children: jsx(DrawIcon, {}) }), "Manual"] })] }), props.csv_upload?.enable && (jsx(CSVUpload, { open: csv.open, drawerToggle: handleToggleClose, data: csv.data })), props.renderFunction({ dataGridProps: createGridProps })] }));
27813
+ }, disableRipple: true, children: [jsx(ListItemIcon, { children: jsx(DrawIcon, {}) }), "Manual"] }), props.extraOptions?.map((option, index) => {
27814
+ return (jsxs(MenuItem, { onClick: () => {
27815
+ option.onClick();
27816
+ handleClose();
27817
+ }, disableRipple: true, children: [jsx(ListItemIcon, { children: option.icon }), option.title] }, index));
27818
+ })] }), props.csv_upload?.enable && (jsx(CSVUpload, { open: csv.open, drawerToggle: handleToggleClose, data: csv.data })), props.renderFunction({ dataGridProps: createGridProps })] }));
27659
27819
  };
27660
27820
 
27661
27821
  const Base = (props) => {
@@ -28841,5 +29001,5 @@ const theme = () => {
28841
29001
  return themes;
28842
29002
  };
28843
29003
 
28844
- export { APIContext, APIProvider, ActiveCell, Base, ButtonWithDrawer, CSVUpload, ContentLayout, ControlledDate, ControlledDropdown, ControlledFileField, FileUploadBox as ControlledFileUploadBox, ControlledNumber, ControlledPhoneNumber, ControlledSelect, ControlledSlider as ControlledSimpleSlider, ControlledSlider$1 as ControlledSlider, ControlledSwitch, ControlledText, ControlledTimePicker, ControlledToggleButtons, CoverPage, CreateButtonBase, CreateButtonWithMenuOptions, DeleteButton, DeleteConfirmationDialog, DetailPage, EditButton, ExportCSV, HistorialDrawer, ListPage, Loadable, LoadingComponent, Logo, MainDrawer, MenuItemWithLoading, ModuleCard, MoreOptions, MyGridEditSingleSelect, NavigationContext, NavigationProvider, NormalOrIcon, NotAllowed, NotFound, ObjectProgressStack, SaveCancelButton, StatusBadge, StyledMenu, Tabs, Transitions, UncontrolledText, changeTitle, closeProgressSnack, dayjs, deleteColumn, editColumn, filterQuery, formParser, header as headerReducer, manualCacheRefresh, mergeSettings, openProgressSnack, query, renderEditCellWithErrorTooltip, setErrors, snackProgress_default as snackProgressReducer, tags, theme, updateProgressSnackData, useAPI, useHasPermission, useNavigation, valueLabel };
29004
+ export { APIContext, APIProvider, ActiveCell, Base, ButtonWithDrawer, CSVUpload, ContentLayout, ControlledDate, ControlledDropdown, ControlledFileField, FileUploadBox as ControlledFileUploadBox, ControlledNumber, ControlledPhoneNumber, ControlledSelect, ControlledSlider as ControlledSimpleSlider, ControlledSlider$1 as ControlledSlider, ControlledSwitch, ControlledText, ControlledTimePicker, ControlledToggleButtons, CoverPage, CreateButtonBase, CreateButtonWithMenuOptions, CrudDropdown, DeleteButton, DeleteConfirmationDialog, DetailPage, EditButton, ExportCSV, HistorialDrawer, ListPage, Loadable, LoadingComponent, Logo, MainDrawer, MenuItemWithLoading, ModuleCard, MoreOptions, MyGridEditSingleSelect, NavigationContext, NavigationProvider, NormalOrIcon, NotAllowed, NotFound, ObjectProgressStack, SaveCancelButton, StatusBadge, StyledMenu, Tabs, Transitions, UncontrolledText, changeTitle, closeProgressSnack, dayjs, deleteColumn, editColumn, filterQuery, formParser, header as headerReducer, manualCacheRefresh, mergeSettings, openProgressSnack, query, renderEditCellWithErrorTooltip, setErrors, snackProgress_default as snackProgressReducer, tags, theme, updateProgressSnackData, useAPI, useHasPermission, useNavigation, valueLabel };
28845
29005
  //# sourceMappingURL=index.js.map