mirror of
https://github.com/Kingsrook/qqq-frontend-material-dashboard.git
synced 2025-07-18 13:20:43 +00:00
Fix dropdown flickering
This commit is contained in:
@ -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>);
|
||||
})
|
||||
|
Reference in New Issue
Block a user