Fix dropdown flickering

This commit is contained in:
2023-06-21 11:53:37 -05:00
parent dac2588ae2
commit 5016d76b15

View File

@ -30,8 +30,7 @@ import Tooltip from "@mui/material/Tooltip/Tooltip";
import Typography from "@mui/material/Typography";
import parse from "html-react-parser";
import React, {useEffect, useState} from "react";
import {Link, useNavigate, NavigateFunction} from "react-router-dom";
import {bool} from "yup";
import {Link, NavigateFunction, useNavigate} from "react-router-dom";
import colors from "qqq/components/legacy/colors";
import DropdownMenu, {DropdownOption} from "qqq/components/widgets/components/DropdownMenu";
@ -94,7 +93,9 @@ export class LabelComponent
}
/*******************************************************************************
**
*******************************************************************************/
export class HeaderLink extends LabelComponent
{
label: string;
@ -118,7 +119,9 @@ export class HeaderLink extends LabelComponent
}
/*******************************************************************************
**
*******************************************************************************/
export class AddNewRecordButton extends LabelComponent
{
table: QTableMetaData;
@ -152,6 +155,9 @@ export class AddNewRecordButton extends LabelComponent
}
/*******************************************************************************
**
*******************************************************************************/
export class ExportDataButton extends LabelComponent
{
callbackToExport: any;
@ -177,25 +183,29 @@ export class ExportDataButton extends LabelComponent
}
/*******************************************************************************
**
*******************************************************************************/
export class Dropdown extends LabelComponent
{
label: string;
options: DropdownOption[];
onChangeCallback: any
dropdownName: string;
onChangeCallback: any;
constructor(label: string, options: DropdownOption[], onChangeCallback: any)
constructor(label: string, options: DropdownOption[], dropdownName: string, onChangeCallback: any)
{
super();
this.label = label;
this.options = options;
this.dropdownName = dropdownName;
this.onChangeCallback = onChangeCallback;
}
render = (args: LabelComponentRenderArgs): JSX.Element =>
{
let defaultValue = null;
const dropdownName = args.widgetProps.widgetData.dropdownNameList[args.componentIndex];
const localStorageKey = `${WIDGET_DROPDOWN_SELECTION_LOCAL_STORAGE_KEY_ROOT}.${args.widgetProps.widgetMetaData.name}.${dropdownName}`;
const localStorageKey = `${WIDGET_DROPDOWN_SELECTION_LOCAL_STORAGE_KEY_ROOT}.${args.widgetProps.widgetMetaData.name}.${this.dropdownName}`;
if (args.widgetProps.storeDropdownSelections)
{
///////////////////////////////////////////////////////////////////////////////////////
@ -208,7 +218,7 @@ export class Dropdown extends LabelComponent
return (
<Box my={2} sx={{float: "right"}}>
<DropdownMenu
name={dropdownName}
name={this.dropdownName}
defaultValue={defaultValue}
sx={{width: 200, marginLeft: "15px"}}
label={`Select ${this.label}`}
@ -221,6 +231,9 @@ export class Dropdown extends LabelComponent
}
/*******************************************************************************
**
*******************************************************************************/
export class ReloadControl extends LabelComponent
{
callback: () => void;
@ -245,56 +258,98 @@ export class ReloadControl extends LabelComponent
export const WIDGET_DROPDOWN_SELECTION_LOCAL_STORAGE_KEY_ROOT = "qqq.widgets.dropdownData";
/*******************************************************************************
**
*******************************************************************************/
function Widget(props: React.PropsWithChildren<Props>): JSX.Element
{
const navigate = useNavigate();
const [dropdownData, setDropdownData] = useState([]);
const [fullScreenWidgetClassName, setFullScreenWidgetClassName] = useState("");
const [reloading, setReloading] = useState(false);
const [dropdownDataJSON, setDropdownDataJSON] = useState("");
const [labelComponentsLeft, setLabelComponentsLeft] = useState([] as LabelComponent[]);
const [labelComponentsRight, setLabelComponentsRight] = useState([] as LabelComponent[]);
function renderComponent(component: LabelComponent, componentIndex: number)
{
return component.render({navigate: navigate, widgetProps: props, dropdownData: dropdownData, componentIndex: componentIndex, reloadFunction: doReload})
return component.render({navigate: navigate, widgetProps: props, dropdownData: dropdownData, componentIndex: componentIndex, reloadFunction: doReload});
}
useEffect(() =>
{
////////////////////////////////////////////////////////////////////////////////
// for initial render, put left-components from props into the state variable //
// plus others we can infer from other props //
////////////////////////////////////////////////////////////////////////////////
const stateLabelComponentsLeft: LabelComponent[] = [];
if (props.reloadWidgetCallback && props.widgetData && props.showReloadControl && props.widgetMetaData.showReloadButton)
{
stateLabelComponentsLeft.push(new ReloadControl(doReload));
}
if (props.labelAdditionalComponentsLeft)
{
props.labelAdditionalComponentsLeft.map((component) => stateLabelComponentsLeft.push(component));
}
setLabelComponentsLeft(stateLabelComponentsLeft);
}, []);
///////////////////////////////////////////////////////////////////
// make dropdowns from the widgetData appear as label-components //
///////////////////////////////////////////////////////////////////
const effectiveLabelAdditionalComponentsRight: LabelComponent[] = [];
useEffect(() =>
{
/////////////////////////////////////////////////////////////////////////////////
// for initial render, put right-components from props into the state variable //
/////////////////////////////////////////////////////////////////////////////////
const stateLabelComponentsRight = [] as LabelComponent[];
// console.log(`${props.widgetMetaData.name} init'ing right-components`);
if (props.labelAdditionalComponentsRight)
{
props.labelAdditionalComponentsRight.map((component) => effectiveLabelAdditionalComponentsRight.push(component));
props.labelAdditionalComponentsRight.map((component) => stateLabelComponentsRight.push(component));
}
setLabelComponentsRight(stateLabelComponentsRight);
}, []);
//////////////////////////////////////////////////////////////////////////////////////////////////////////
// if we have widgetData, and it has a dropdown list, capture that in a state variable, if it's changed //
//////////////////////////////////////////////////////////////////////////////////////////////////////////
if (props.widgetData && props.widgetData.dropdownDataList)
{
const currentDropdownDataJSON = JSON.stringify(props.widgetData.dropdownDataList);
if (currentDropdownDataJSON !== dropdownDataJSON)
{
// console.log(`${props.widgetMetaData.name} we have (new) dropdown data!!: ${currentDropdownDataJSON}`);
setDropdownDataJSON(currentDropdownDataJSON);
}
}
useEffect(() =>
{
///////////////////////////////////////////////////////////////////////////////////
// if we've seen a change in the dropdown data, then update the right-components //
///////////////////////////////////////////////////////////////////////////////////
// console.log(`${props.widgetMetaData.name} in useEffect post dropdownData change`);
if (props.widgetData && props.widgetData.dropdownDataList)
{
const updatedStateLabelComponentsRight = JSON.parse(JSON.stringify(labelComponentsRight)) as LabelComponent[];
props.widgetData.dropdownDataList?.map((dropdownData: any, index: number) =>
{
effectiveLabelAdditionalComponentsRight.push(new Dropdown(props.widgetData.dropdownLabelList[index], dropdownData, handleDataChange))
// console.log(`${props.widgetMetaData.name} building a Dropdown, data is: ${dropdownData}`);
updatedStateLabelComponentsRight.push(new Dropdown(props.widgetData.dropdownLabelList[index], dropdownData, props.widgetData.dropdownNameList[index], handleDataChange));
});
setLabelComponentsRight(updatedStateLabelComponentsRight);
}
}, [dropdownDataJSON]);
const doReload = () =>
{
setReloading(true);
reloadWidget(dropdownData);
}
};
useEffect(() =>
{
setReloading(false);
}, [props.widgetData]);
const effectiveLabelAdditionalComponentsLeft: LabelComponent[] = [];
if(props.reloadWidgetCallback && props.widgetData && props.showReloadControl && props.widgetMetaData.showReloadButton)
{
effectiveLabelAdditionalComponentsLeft.push(new ReloadControl(doReload))
}
if(props.labelAdditionalComponentsLeft)
{
props.labelAdditionalComponentsLeft.map((component) => effectiveLabelAdditionalComponentsLeft.push(component));
}
function handleDataChange(dropdownLabel: string, changedData: any)
{
if (dropdownData)
@ -394,8 +449,8 @@ function Widget(props: React.PropsWithChildren<Props>): JSX.Element
let needLabelBox = false;
if (hasPermission)
{
needLabelBox ||= (effectiveLabelAdditionalComponentsLeft && effectiveLabelAdditionalComponentsLeft.length > 0);
needLabelBox ||= (effectiveLabelAdditionalComponentsRight && effectiveLabelAdditionalComponentsRight.length > 0);
needLabelBox ||= (labelComponentsLeft && labelComponentsLeft.length > 0);
needLabelBox ||= (labelComponentsRight && labelComponentsRight.length > 0);
needLabelBox ||= isSet(props.widgetMetaData?.icon);
needLabelBox ||= isSet(props.widgetData?.label);
needLabelBox ||= isSet(props.widgetMetaData?.label);
@ -430,8 +485,8 @@ function Widget(props: React.PropsWithChildren<Props>): JSX.Element
{props.widgetMetaData.icon}
</Icon>
</Box>
) : (
) :
(
<Box
ml={3}
mt={-4}
@ -469,7 +524,7 @@ function Widget(props: React.PropsWithChildren<Props>): JSX.Element
}
{
hasPermission && (
effectiveLabelAdditionalComponentsLeft.map((component, i) =>
labelComponentsLeft.map((component, i) =>
{
return (<span key={i}>{renderComponent(component, i)}</span>);
})
@ -479,7 +534,7 @@ function Widget(props: React.PropsWithChildren<Props>): JSX.Element
<Box>
{
hasPermission && (
effectiveLabelAdditionalComponentsRight.map((component, i) =>
labelComponentsRight.map((component, i) =>
{
return (<span key={i}>{renderComponent(component, i)}</span>);
})