@toolpad/core
Version:
Dashboard framework powered by Material UI.
310 lines (309 loc) • 10.2 kB
JavaScript
'use client';
var _CircularProgress, _EditIcon, _DeleteIcon;
import * as React from 'react';
import PropTypes from 'prop-types';
import Alert from '@mui/material/Alert';
import Box from '@mui/material/Box';
import Button from '@mui/material/Button';
import CircularProgress from '@mui/material/CircularProgress';
import Divider from '@mui/material/Divider';
import Grid from '@mui/material/Grid';
import Paper from '@mui/material/Paper';
import Stack from '@mui/material/Stack';
import Typography from '@mui/material/Typography';
import EditIcon from '@mui/icons-material/Edit';
import DeleteIcon from '@mui/icons-material/Delete';
import invariant from 'invariant';
import dayjs from 'dayjs';
import { useDialogs } from "../useDialogs/index.js";
import { useNotifications } from "../useNotifications/index.js";
import { useLocaleText } from "../AppProvider/LocalizationProvider.js";
import { CrudContext } from "../shared/context.js";
import { DataSourceCache } from "./cache.js";
import { useCachedDataSource } from "./useCachedDataSource.js";
import { CRUD_DEFAULT_LOCALE_TEXT } from "./localeText.js";
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
/**
*
* Demos:
*
* - [CRUD](https://mui.com/toolpad/core/react-crud/)
*
* API:
*
* - [Show API](https://mui.com/toolpad/core/api/show)
*/
function Show(props) {
const {
id,
onEditClick,
onDelete,
dataSourceCache,
localeText: propsLocaleText
} = props;
const globalLocaleText = useLocaleText();
const localeText = {
...CRUD_DEFAULT_LOCALE_TEXT,
...globalLocaleText,
...propsLocaleText
};
const crudContext = React.useContext(CrudContext);
const dataSource = props.dataSource ?? crudContext.dataSource;
invariant(dataSource, 'No data source found.');
const cache = React.useMemo(() => {
const manualCache = dataSourceCache ?? crudContext.dataSourceCache;
return typeof manualCache !== 'undefined' ? manualCache : new DataSourceCache();
}, [crudContext.dataSourceCache, dataSourceCache]);
const cachedDataSource = useCachedDataSource(dataSource, cache);
const {
fields,
validate,
...methods
} = cachedDataSource;
const {
getOne,
deleteOne
} = methods;
const dialogs = useDialogs();
const notifications = useNotifications();
const [data, setData] = React.useState(null);
const [isLoading, setIsLoading] = React.useState(false);
const [error, setError] = React.useState(null);
const [hasDeleted, setHasDeleted] = React.useState(false);
const loadData = React.useCallback(async () => {
setError(null);
setIsLoading(true);
try {
const showData = await getOne(id);
setData(showData);
} catch (showDataError) {
setError(showDataError);
}
setIsLoading(false);
}, [getOne, id]);
React.useEffect(() => {
loadData();
}, [loadData]);
const handleItemEdit = React.useCallback(() => {
if (onEditClick) {
onEditClick(id);
}
}, [id, onEditClick]);
const handleItemDelete = React.useCallback(async () => {
const confirmed = await dialogs.confirm(localeText.deleteConfirmMessage, {
title: localeText.deleteConfirmTitle,
severity: 'error',
okText: localeText.deleteConfirmLabel,
cancelText: localeText.deleteCancelLabel
});
if (confirmed) {
setIsLoading(true);
try {
await deleteOne?.(id);
if (onDelete) {
onDelete(id);
}
notifications.show(localeText.deleteSuccessMessage, {
severity: 'success',
autoHideDuration: 3000
});
setHasDeleted(true);
} catch (deleteError) {
notifications.show(`${localeText.deleteErrorMessage} ${deleteError.message}`, {
severity: 'error',
autoHideDuration: 3000
});
}
setIsLoading(false);
}
}, [deleteOne, dialogs, id, localeText.deleteCancelLabel, localeText.deleteConfirmLabel, localeText.deleteConfirmMessage, localeText.deleteConfirmTitle, localeText.deleteErrorMessage, localeText.deleteSuccessMessage, notifications, onDelete]);
const renderField = React.useCallback(showField => {
if (!data) {
return '…';
}
const {
field,
type
} = showField;
const fieldValue = data[field];
if (type === 'boolean') {
return fieldValue ? 'Yes' : 'No';
}
if (type === 'date') {
return fieldValue ? dayjs(fieldValue).format('MMMM D, YYYY') : '-';
}
if (type === 'dateTime') {
return fieldValue ? dayjs(fieldValue).format('MMMM D, YYYY h:mm A') : '-';
}
if (type === 'singleSelect') {
const {
getOptionValue,
getOptionLabel,
valueOptions
} = showField;
if (valueOptions && Array.isArray(valueOptions)) {
const selectedOption = valueOptions.find(option => {
let optionValue = option;
if (typeof option !== 'string' && typeof option !== 'number') {
optionValue = getOptionValue ? getOptionValue(option) : option.value;
}
return optionValue === fieldValue;
});
if (selectedOption) {
let selectedOptionLabel = selectedOption;
if (typeof selectedOption !== 'string' && typeof selectedOption !== 'number') {
selectedOptionLabel = getOptionLabel ? getOptionLabel(selectedOption) : selectedOption.label;
}
return selectedOptionLabel ? String(selectedOptionLabel) : '-';
}
}
}
return fieldValue ? String(fieldValue) : '-';
}, [data]);
const renderShow = React.useMemo(() => {
if (isLoading) {
return /*#__PURE__*/_jsx(Box, {
sx: {
flex: 1,
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
justifyContent: 'center',
width: '100%',
m: 1
},
children: _CircularProgress || (_CircularProgress = /*#__PURE__*/_jsx(CircularProgress, {}))
});
}
if (error) {
return /*#__PURE__*/_jsx(Box, {
sx: {
flexGrow: 1
},
children: /*#__PURE__*/_jsx(Alert, {
severity: "error",
children: error.message
})
});
}
if (hasDeleted) {
return /*#__PURE__*/_jsx(Box, {
sx: {
flexGrow: 1
},
children: /*#__PURE__*/_jsx(Alert, {
severity: "error",
children: localeText.deletedItemMessage
})
});
}
return data ? /*#__PURE__*/_jsxs(Box, {
sx: {
flexGrow: 1,
width: '100%'
},
children: [/*#__PURE__*/_jsx(Grid, {
container: true,
spacing: 2,
sx: {
width: '100%'
},
children: fields.filter(({
type
}) => type !== 'actions' && type !== 'custom').map(showField => {
const {
field,
headerName
} = showField;
return /*#__PURE__*/_jsx(Grid, {
size: {
xs: 12,
sm: 6
},
children: /*#__PURE__*/_jsxs(Paper, {
sx: {
px: 2,
py: 1
},
children: [/*#__PURE__*/_jsx(Typography, {
variant: "overline",
children: headerName
}), /*#__PURE__*/_jsx(Typography, {
variant: "body1",
sx: {
mb: 1
},
children: renderField(showField)
})]
})
}, field);
})
}), /*#__PURE__*/_jsx(Divider, {
sx: {
my: 3
}
}), /*#__PURE__*/_jsxs(Stack, {
direction: "row",
spacing: 2,
justifyContent: "flex-end",
children: [onEditClick ? /*#__PURE__*/_jsx(Button, {
variant: "contained",
startIcon: _EditIcon || (_EditIcon = /*#__PURE__*/_jsx(EditIcon, {})),
onClick: handleItemEdit,
children: localeText.editLabel
}) : null, deleteOne ? /*#__PURE__*/_jsx(Button, {
variant: "contained",
color: "error",
startIcon: _DeleteIcon || (_DeleteIcon = /*#__PURE__*/_jsx(DeleteIcon, {})),
onClick: handleItemDelete,
children: localeText.deleteLabel
}) : null]
})]
}) : null;
}, [data, deleteOne, error, fields, handleItemDelete, handleItemEdit, hasDeleted, isLoading, localeText.deleteLabel, localeText.deletedItemMessage, localeText.editLabel, onEditClick, renderField]);
return /*#__PURE__*/_jsx(Box, {
sx: {
display: 'flex',
flex: 1,
width: '100%'
},
children: renderShow
});
}
process.env.NODE_ENV !== "production" ? Show.propTypes /* remove-proptypes */ = {
// ┌────────────────────────────── Warning ──────────────────────────────┐
// │ These PropTypes are generated from the TypeScript type definitions. │
// │ To update them, edit the TypeScript types and run `pnpm proptypes`. │
// └─────────────────────────────────────────────────────────────────────┘
/**
* Server-side [data source](https://mui.com/toolpad/core/react-crud/#data-sources).
*/
dataSource: PropTypes.object,
/**
* [Cache](https://mui.com/toolpad/core/react-crud/#data-caching) for the data source.
*/
dataSourceCache: PropTypes.shape({
cache: PropTypes.object.isRequired,
clear: PropTypes.func.isRequired,
get: PropTypes.func.isRequired,
set: PropTypes.func.isRequired,
ttl: PropTypes.number.isRequired
}),
/**
* @ignore
*/
id: PropTypes.oneOfType([PropTypes.number, PropTypes.string]).isRequired,
/**
* Locale text for the component.
*/
localeText: PropTypes.object,
/**
* Callback fired when the item is successfully deleted.
*/
onDelete: PropTypes.func,
/**
* Callback fired when the "Edit" button is clicked.
*/
onEditClick: PropTypes.func
} : void 0;
export { Show };