/*
* 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 {QTableMetaData} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QTableMetaData";
import Box from "@mui/material/Box";
import Button from "@mui/material/Button";
import Card from "@mui/material/Card";
import Icon from "@mui/material/Icon";
import Typography from "@mui/material/Typography";
import React, {useEffect, useState} from "react";
import {Link, useNavigate} from "react-router-dom";
import colors from "qqq/components/legacy/colors";
import DropdownMenu, {DropdownOption} from "qqq/components/widgets/components/DropdownMenu";
export interface WidgetData
{
dropdownLabelList?: string[];
dropdownNameList?: string[];
dropdownDataList?: {
id: string,
label: string
}[][];
dropdownNeedsSelectedText?: string;
}
interface Props
{
icon?: string;
label: string;
labelAdditionalComponentsLeft: LabelComponent[];
labelAdditionalComponentsRight: LabelComponent[];
widgetData?: WidgetData;
children: JSX.Element;
reloadWidgetCallback?: (params: string) => void;
isChild?: boolean;
isCard?: boolean;
}
Widget.defaultProps = {
isCard: true,
isChild: false,
label: null,
widgetData: {},
labelAdditionalComponentsLeft: [],
labelAdditionalComponentsRight: [],
};
export class LabelComponent
{
}
export class HeaderLink extends LabelComponent
{
label: string;
to: string
constructor(label: string, to: string)
{
super();
this.label = label;
this.to = to;
}
}
export class AddNewRecordButton extends LabelComponent
{
table: QTableMetaData;
label: string;
defaultValues: any;
disabledFields: any;
constructor(table: QTableMetaData, defaultValues: any, label: string = "Add new", disabledFields: any = defaultValues)
{
super();
this.table = table;
this.label = label;
this.defaultValues = defaultValues;
this.disabledFields = disabledFields;
}
}
export class Dropdown extends LabelComponent
{
label: string;
options: DropdownOption[];
onChangeCallback: any
constructor(label: string, options: DropdownOption[], onChangeCallback: any)
{
super();
this.label = label;
this.options = options;
this.onChangeCallback = onChangeCallback;
}
}
function Widget(props: React.PropsWithChildren): JSX.Element
{
const navigate = useNavigate();
const [dropdownData, setDropdownData] = useState([]);
const [counter, setCounter] = useState(0);
function openEditForm(table: QTableMetaData, id: any = null, defaultValues: any, disabledFields: any)
{
navigate(`#/createChild=${table.name}/defaultValues=${JSON.stringify(defaultValues)}/disabledFields=${JSON.stringify(disabledFields)}`)
}
function renderComponent(component: LabelComponent)
{
if(component instanceof HeaderLink)
{
const link = component as HeaderLink
return (
{link.to ? {link.label} : null}
);
}
if (component instanceof AddNewRecordButton)
{
const addNewRecordButton = component as AddNewRecordButton
return (
);
}
if (component instanceof Dropdown)
{
const dropdown = component as Dropdown
return (
);
}
return (
Unsupported component type.
)
}
///////////////////////////////////////////////////////////////////
// make dropdowns from the widgetData appear as label-components //
///////////////////////////////////////////////////////////////////
const effectiveLabelAdditionalComponentsRight: LabelComponent[] = [];
if(props.labelAdditionalComponentsRight)
{
props.labelAdditionalComponentsRight.map((component) => effectiveLabelAdditionalComponentsRight.push(component));
}
if(props.widgetData && props.widgetData.dropdownDataList)
{
props.widgetData.dropdownDataList?.map((dropdownData: any, index: number) =>
{
effectiveLabelAdditionalComponentsRight.push(new Dropdown(props.widgetData.dropdownLabelList[index], dropdownData, handleDataChange))
});
}
function handleDataChange(dropdownLabel: string, changedData: any)
{
if(dropdownData)
{
///////////////////////////////////////////
// find the index base on selected label //
///////////////////////////////////////////
const tableName = dropdownLabel.replace("Select ", "");
let index = -1;
for (let i = 0; i < props.widgetData.dropdownLabelList.length; i++)
{
if (tableName === props.widgetData.dropdownLabelList[i])
{
index = i;
break;
}
}
if (index < 0)
{
throw(`Could not find table name for label ${tableName}`);
}
dropdownData[index] = (changedData) ? changedData.id : null;
setDropdownData(dropdownData);
setCounter(counter + 1);
}
}
useEffect(() =>
{
if(dropdownData)
{
let params = "";
for (let i = 0; i < dropdownData.length; i++)
{
if (i > 0)
{
params += "&";
}
params += `${props.widgetData.dropdownNameList[i]}=`;
if(dropdownData[i])
{
params += `${dropdownData[i]}`;
}
}
if(props.reloadWidgetCallback)
{
props.reloadWidgetCallback(params);
}
else
{
console.log(`No reload widget callback in ${props.label}`)
}
}
}, [counter]);
const widgetContent =
{
(props.icon || props.label) && (
{
props.icon && (
{props.icon}
)
}
{props.label}
{
props.labelAdditionalComponentsLeft.map((component, i) =>
{
return ({renderComponent(component)});
})
}
{
effectiveLabelAdditionalComponentsRight.map((component, i) =>
{
return ({renderComponent(component)});
})
}
)
}
{
props.widgetData?.dropdownNeedsSelectedText ? (
{props.widgetData?.dropdownNeedsSelectedText}
) : (
props.children
)
}
;
return props.isCard ? {widgetContent} : widgetContent;
}
export default Widget;