mirror of
https://github.com/Kingsrook/qqq-frontend-material-dashboard.git
synced 2025-07-18 13:20:43 +00:00
Add QBooleanFieldSwitch
This commit is contained in:
128
src/qqq/components/QDynamicFormField/QBooleanFieldSwitch.tsx
Normal file
128
src/qqq/components/QDynamicFormField/QBooleanFieldSwitch.tsx
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
/*
|
||||||
|
* QQQ - Low-code Application Framework for Engineers.
|
||||||
|
* Copyright (C) 2021-2022. Kingsrook, LLC
|
||||||
|
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
|
||||||
|
* contact@kingsrook.com
|
||||||
|
* https://github.com/Kingsrook/
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import {InputAdornment, InputLabel} from "@mui/material";
|
||||||
|
import Box from "@mui/material/Box";
|
||||||
|
import Grid from "@mui/material/Grid";
|
||||||
|
import Stack from "@mui/material/Stack";
|
||||||
|
import {styled} from "@mui/material/styles";
|
||||||
|
import Switch from "@mui/material/Switch";
|
||||||
|
import Typography from "@mui/material/Typography";
|
||||||
|
import {ErrorMessage, Field, useFormikContext} from "formik";
|
||||||
|
import React, {SyntheticEvent, useState} from "react";
|
||||||
|
import MDBox from "qqq/components/Temporary/MDBox";
|
||||||
|
import MDInput from "qqq/components/Temporary/MDInput";
|
||||||
|
import MDTypography from "qqq/components/Temporary/MDTypography";
|
||||||
|
|
||||||
|
const AntSwitch = styled(Switch)(({theme}) => ({
|
||||||
|
width: 28,
|
||||||
|
height: 16,
|
||||||
|
padding: 0,
|
||||||
|
display: "flex",
|
||||||
|
"&:active": {
|
||||||
|
"& .MuiSwitch-thumb": {
|
||||||
|
width: 15,
|
||||||
|
},
|
||||||
|
"& .MuiSwitch-switchBase.Mui-checked": {
|
||||||
|
transform: "translateX(9px)",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"& .MuiSwitch-switchBase": {
|
||||||
|
padding: 2,
|
||||||
|
"&.Mui-checked": {
|
||||||
|
transform: "translateX(12px)",
|
||||||
|
color: "#fff",
|
||||||
|
"& + .MuiSwitch-track": {
|
||||||
|
opacity: 1,
|
||||||
|
backgroundColor: theme.palette.mode === "dark" ? "#177ddc" : "#1890ff",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"& .MuiSwitch-thumb": {
|
||||||
|
boxShadow: "0 2px 4px 0 rgb(0 35 11 / 20%)",
|
||||||
|
width: 12,
|
||||||
|
height: 12,
|
||||||
|
borderRadius: 6,
|
||||||
|
transition: theme.transitions.create([ "width" ], {
|
||||||
|
duration: 200,
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
"& .MuiSwitch-track": {
|
||||||
|
borderRadius: 16 / 2,
|
||||||
|
opacity: 1,
|
||||||
|
backgroundColor:
|
||||||
|
theme.palette.mode === "dark" ? "rgba(255,255,255,.35)" : "rgba(0,0,0,.25)",
|
||||||
|
boxSizing: "border-box",
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
|
interface Props
|
||||||
|
{
|
||||||
|
name: string;
|
||||||
|
label: string;
|
||||||
|
value: boolean;
|
||||||
|
isDisabled: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function QBooleanFieldSwitch({name, label, value, isDisabled}: Props) : JSX.Element
|
||||||
|
{
|
||||||
|
const {setFieldValue} = useFormikContext();
|
||||||
|
|
||||||
|
const setSwitch = (event: SyntheticEvent, newValue: boolean) =>
|
||||||
|
{
|
||||||
|
if(!isDisabled)
|
||||||
|
{
|
||||||
|
setFieldValue(name, newValue);
|
||||||
|
event.stopPropagation();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const toggleSwitch = () =>
|
||||||
|
{
|
||||||
|
setFieldValue(name, !value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<InputLabel shrink={true}>{label}</InputLabel>
|
||||||
|
<Stack direction="row" spacing={1} alignItems="center">
|
||||||
|
<Typography
|
||||||
|
fontSize="0.875rem"
|
||||||
|
color={value === false ? "auto" : "#bfbfbf" }
|
||||||
|
onClick={(e) => setSwitch(e, false)}
|
||||||
|
sx={{cursor: value === false || isDisabled ? "inherit" : "pointer"}}>
|
||||||
|
No
|
||||||
|
</Typography>
|
||||||
|
<AntSwitch name={name} checked={value} onClick={toggleSwitch} disabled={isDisabled} />
|
||||||
|
<Typography
|
||||||
|
fontSize="0.875rem"
|
||||||
|
color={value === true ? "auto" : "#bfbfbf"}
|
||||||
|
onClick={(e) => setSwitch(e, true)}
|
||||||
|
sx={{cursor: value === true || isDisabled ? "inherit" : "pointer"}}>
|
||||||
|
Yes
|
||||||
|
</Typography>
|
||||||
|
</Stack>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default QBooleanFieldSwitch
|
@ -19,11 +19,12 @@
|
|||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {InputAdornment} from "@mui/material";
|
import {InputAdornment, InputLabel} from "@mui/material";
|
||||||
import Grid from "@mui/material/Grid";
|
import Box from "@mui/material/Box";
|
||||||
import Switch from "@mui/material/Switch";
|
import Switch from "@mui/material/Switch";
|
||||||
import {ErrorMessage, Field} from "formik";
|
import {ErrorMessage, Field, useFormikContext} from "formik";
|
||||||
import React, {useState} from "react";
|
import React, {SyntheticEvent, useState} from "react";
|
||||||
|
import QBooleanFieldSwitch from "qqq/components/QDynamicFormField/QBooleanFieldSwitch";
|
||||||
import MDBox from "qqq/components/Temporary/MDBox";
|
import MDBox from "qqq/components/Temporary/MDBox";
|
||||||
import MDInput from "qqq/components/Temporary/MDInput";
|
import MDInput from "qqq/components/Temporary/MDInput";
|
||||||
import MDTypography from "qqq/components/Temporary/MDTypography";
|
import MDTypography from "qqq/components/Temporary/MDTypography";
|
||||||
@ -34,6 +35,7 @@ interface Props
|
|||||||
label: string;
|
label: string;
|
||||||
name: string;
|
name: string;
|
||||||
displayFormat: string;
|
displayFormat: string;
|
||||||
|
value: any;
|
||||||
type: string;
|
type: string;
|
||||||
isEditable?: boolean;
|
isEditable?: boolean;
|
||||||
[key: string]: any;
|
[key: string]: any;
|
||||||
@ -42,11 +44,13 @@ interface Props
|
|||||||
}
|
}
|
||||||
|
|
||||||
function QDynamicFormField({
|
function QDynamicFormField({
|
||||||
label, name, displayFormat, bulkEditMode, bulkEditSwitchChangeHandler, type, isEditable, ...rest
|
label, name, displayFormat, value, bulkEditMode, bulkEditSwitchChangeHandler, type, isEditable, ...rest
|
||||||
}: Props): JSX.Element
|
}: Props): JSX.Element
|
||||||
{
|
{
|
||||||
const [switchChecked, setSwitchChecked] = useState(false);
|
const [ switchChecked, setSwitchChecked ] = useState(false);
|
||||||
const [isDisabled, setIsDisabled] = useState(!isEditable || bulkEditMode);
|
const [ isDisabled, setIsDisabled ] = useState(!isEditable || bulkEditMode);
|
||||||
|
|
||||||
|
const {setFieldValue} = useFormikContext();
|
||||||
|
|
||||||
const inputLabelProps = {};
|
const inputLabelProps = {};
|
||||||
if (type.toLowerCase().match("(date|time)"))
|
if (type.toLowerCase().match("(date|time)"))
|
||||||
@ -61,8 +65,15 @@ function QDynamicFormField({
|
|||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
inputProps.startAdornment = <InputAdornment position="start">$</InputAdornment>;
|
inputProps.startAdornment = <InputAdornment position="start">$</InputAdornment>;
|
||||||
}
|
}
|
||||||
|
if (displayFormat && displayFormat.endsWith("%%"))
|
||||||
|
{
|
||||||
|
// @ts-ignore
|
||||||
|
inputProps.endAdornment = <InputAdornment position="end">%</InputAdornment>;
|
||||||
|
}
|
||||||
|
|
||||||
const field = () => (
|
const field = () =>
|
||||||
|
(type == "checkbox" ?
|
||||||
|
<QBooleanFieldSwitch name={name} label={label} value={value} isDisabled={isDisabled} /> :
|
||||||
<>
|
<>
|
||||||
<Field {...rest} name={name} type={type} as={MDInput} variant="standard" label={label} InputLabelProps={inputLabelProps} InputProps={inputProps} fullWidth disabled={isDisabled} />
|
<Field {...rest} name={name} type={type} as={MDInput} variant="standard" label={label} InputLabelProps={inputLabelProps} InputProps={inputProps} fullWidth disabled={isDisabled} />
|
||||||
<MDBox mt={0.75}>
|
<MDBox mt={0.75}>
|
||||||
@ -84,22 +95,24 @@ function QDynamicFormField({
|
|||||||
if (bulkEditMode)
|
if (bulkEditMode)
|
||||||
{
|
{
|
||||||
return (
|
return (
|
||||||
<MDBox mb={1.5}>
|
<Box mb={1.5} display="flex" flexDirection="row">
|
||||||
<Grid container>
|
<Box alignItems="baseline" pt={1}>
|
||||||
<Grid item xs={1} alignItems="baseline" pt={1}>
|
|
||||||
<Switch
|
<Switch
|
||||||
id={`bulkEditSwitch-${name}`}
|
id={`bulkEditSwitch-${name}`}
|
||||||
checked={switchChecked}
|
checked={switchChecked}
|
||||||
onClick={bulkEditSwitchChanged}
|
onClick={bulkEditSwitchChanged}
|
||||||
/>
|
/>
|
||||||
</Grid>
|
</Box>
|
||||||
<Grid item xs={11}>
|
<Box width="100%">
|
||||||
|
{/* for checkboxes, if we put the whole thing in a label, we get bad overly aggressive toggling of the outer switch... */}
|
||||||
|
{(type == "checkbox" ?
|
||||||
|
field() :
|
||||||
<label htmlFor={`bulkEditSwitch-${name}`}>
|
<label htmlFor={`bulkEditSwitch-${name}`}>
|
||||||
{field()}
|
{field()}
|
||||||
</label>
|
</label>
|
||||||
</Grid>
|
)}
|
||||||
</Grid>
|
</Box>
|
||||||
</MDBox>
|
</Box>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -116,7 +129,8 @@ QDynamicFormField.defaultProps = {
|
|||||||
bulkEditMode: false,
|
bulkEditMode: false,
|
||||||
isEditable: true,
|
isEditable: true,
|
||||||
bulkEditSwitchChangeHandler: () =>
|
bulkEditSwitchChangeHandler: () =>
|
||||||
{},
|
{
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export default QDynamicFormField;
|
export default QDynamicFormField;
|
||||||
|
@ -78,7 +78,7 @@ class QFilterUtils
|
|||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
** Convert a qqq criteria operator to one expected by the grid.
|
** Convert a qqq criteria operator to one expected by the grid.
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
public static qqqCriteriaOperatorToGrid = (operator: QCriteriaOperator, fieldType: QFieldType = QFieldType.STRING): string =>
|
public static qqqCriteriaOperatorToGrid = (operator: QCriteriaOperator, fieldType: QFieldType = QFieldType.STRING, criteriaValues: any[]): string =>
|
||||||
{
|
{
|
||||||
switch (operator)
|
switch (operator)
|
||||||
{
|
{
|
||||||
@ -93,6 +93,15 @@ class QFilterUtils
|
|||||||
case QFieldType.DATE_TIME:
|
case QFieldType.DATE_TIME:
|
||||||
return ("equals");
|
return ("equals");
|
||||||
case QFieldType.BOOLEAN:
|
case QFieldType.BOOLEAN:
|
||||||
|
if (criteriaValues && criteriaValues[0] === true)
|
||||||
|
{
|
||||||
|
return "isTrue";
|
||||||
|
}
|
||||||
|
else if (criteriaValues && criteriaValues[0] === false)
|
||||||
|
{
|
||||||
|
return "isFalse";
|
||||||
|
}
|
||||||
|
return "is";
|
||||||
case QFieldType.STRING:
|
case QFieldType.STRING:
|
||||||
case QFieldType.TEXT:
|
case QFieldType.TEXT:
|
||||||
case QFieldType.HTML:
|
case QFieldType.HTML:
|
||||||
|
Reference in New Issue
Block a user