From e67301dc4b7cd4e08a169bb207106f5c00256b4f Mon Sep 17 00:00:00 2001 From: Darin Kelkhoff Date: Tue, 4 Oct 2022 11:36:11 -0500 Subject: [PATCH] Add QBooleanFieldSwitch --- .../QDynamicFormField/QBooleanFieldSwitch.tsx | 128 ++++++++++++++++++ .../components/QDynamicFormField/index.tsx | 76 ++++++----- src/qqq/utils/QFilterUtils.ts | 11 +- 3 files changed, 183 insertions(+), 32 deletions(-) create mode 100644 src/qqq/components/QDynamicFormField/QBooleanFieldSwitch.tsx diff --git a/src/qqq/components/QDynamicFormField/QBooleanFieldSwitch.tsx b/src/qqq/components/QDynamicFormField/QBooleanFieldSwitch.tsx new file mode 100644 index 0000000..3f72505 --- /dev/null +++ b/src/qqq/components/QDynamicFormField/QBooleanFieldSwitch.tsx @@ -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 . + */ + +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 ( + <> + {label} + + setSwitch(e, false)} + sx={{cursor: value === false || isDisabled ? "inherit" : "pointer"}}> + No + + + setSwitch(e, true)} + sx={{cursor: value === true || isDisabled ? "inherit" : "pointer"}}> + Yes + + + + ); +} + +export default QBooleanFieldSwitch \ No newline at end of file diff --git a/src/qqq/components/QDynamicFormField/index.tsx b/src/qqq/components/QDynamicFormField/index.tsx index 1240fc9..f1016e6 100644 --- a/src/qqq/components/QDynamicFormField/index.tsx +++ b/src/qqq/components/QDynamicFormField/index.tsx @@ -19,11 +19,12 @@ * along with this program. If not, see . */ -import {InputAdornment} from "@mui/material"; -import Grid from "@mui/material/Grid"; +import {InputAdornment, InputLabel} from "@mui/material"; +import Box from "@mui/material/Box"; import Switch from "@mui/material/Switch"; -import {ErrorMessage, Field} from "formik"; -import React, {useState} from "react"; +import {ErrorMessage, Field, useFormikContext} from "formik"; +import React, {SyntheticEvent, useState} from "react"; +import QBooleanFieldSwitch from "qqq/components/QDynamicFormField/QBooleanFieldSwitch"; import MDBox from "qqq/components/Temporary/MDBox"; import MDInput from "qqq/components/Temporary/MDInput"; import MDTypography from "qqq/components/Temporary/MDTypography"; @@ -34,6 +35,7 @@ interface Props label: string; name: string; displayFormat: string; + value: any; type: string; isEditable?: boolean; [key: string]: any; @@ -42,11 +44,13 @@ interface Props } function QDynamicFormField({ - label, name, displayFormat, bulkEditMode, bulkEditSwitchChangeHandler, type, isEditable, ...rest + label, name, displayFormat, value, bulkEditMode, bulkEditSwitchChangeHandler, type, isEditable, ...rest }: Props): JSX.Element { - const [switchChecked, setSwitchChecked] = useState(false); - const [isDisabled, setIsDisabled] = useState(!isEditable || bulkEditMode); + const [ switchChecked, setSwitchChecked ] = useState(false); + const [ isDisabled, setIsDisabled ] = useState(!isEditable || bulkEditMode); + + const {setFieldValue} = useFormikContext(); const inputLabelProps = {}; if (type.toLowerCase().match("(date|time)")) @@ -61,17 +65,24 @@ function QDynamicFormField({ // @ts-ignore inputProps.startAdornment = $; } + if (displayFormat && displayFormat.endsWith("%%")) + { + // @ts-ignore + inputProps.endAdornment = %; + } - const field = () => ( - <> - - - - {!isDisabled &&
} -
-
- - ); + const field = () => + (type == "checkbox" ? + : + <> + + + + {!isDisabled &&
} +
+
+ + ); const bulkEditSwitchChanged = () => { @@ -84,22 +95,24 @@ function QDynamicFormField({ if (bulkEditMode) { return ( - - - - - - + + + + + + {/* for checkboxes, if we put the whole thing in a label, we get bad overly aggressive toggling of the outer switch... */} + {(type == "checkbox" ? + field() : - - - + )} + + ); } else @@ -116,7 +129,8 @@ QDynamicFormField.defaultProps = { bulkEditMode: false, isEditable: true, bulkEditSwitchChangeHandler: () => - {}, + { + }, }; export default QDynamicFormField; diff --git a/src/qqq/utils/QFilterUtils.ts b/src/qqq/utils/QFilterUtils.ts index 01caccd..c51a8bc 100644 --- a/src/qqq/utils/QFilterUtils.ts +++ b/src/qqq/utils/QFilterUtils.ts @@ -78,7 +78,7 @@ class QFilterUtils /******************************************************************************* ** 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) { @@ -93,6 +93,15 @@ class QFilterUtils case QFieldType.DATE_TIME: return ("equals"); 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.TEXT: case QFieldType.HTML: