Add iot data and custom input card for floting cards
This commit is contained in:
@@ -59,9 +59,11 @@ const ProgressBarWidget = ({
|
||||
id,
|
||||
title,
|
||||
data,
|
||||
type
|
||||
}: {
|
||||
id: string;
|
||||
title: string;
|
||||
type: string;
|
||||
data: any;
|
||||
}) => {
|
||||
const { setDraggedAsset } = useWidgetStore((state) => state);
|
||||
@@ -72,7 +74,7 @@ const ProgressBarWidget = ({
|
||||
draggable
|
||||
onDragStart={() => {
|
||||
setDraggedAsset({
|
||||
type: "progress",
|
||||
type: type,
|
||||
id,
|
||||
title,
|
||||
panel: "top",
|
||||
@@ -99,7 +101,7 @@ const ProgressBarWidget = ({
|
||||
</div>
|
||||
);
|
||||
};
|
||||
console.log(chartTypes,"chartTypes");
|
||||
console.log(chartTypes, "chartTypes");
|
||||
|
||||
const Widgets2D = () => {
|
||||
return (
|
||||
@@ -124,6 +126,7 @@ const Widgets2D = () => {
|
||||
{ key: "units", value: 1000, description: "Initial stock" },
|
||||
],
|
||||
}}
|
||||
type={"progress 1"}
|
||||
/>
|
||||
<ProgressBarWidget
|
||||
id="widget-8"
|
||||
@@ -134,6 +137,7 @@ const Widgets2D = () => {
|
||||
{ key: "units", value: 500, description: "Additional stock" },
|
||||
],
|
||||
}}
|
||||
type={"progress 2"}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,178 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
import MultiLevelDropdown from "../../../../ui/inputs/MultiLevelDropDown";
|
||||
import { AddIcon } from "../../../../icons/ExportCommonIcons";
|
||||
import RegularDropDown from "../../../../ui/inputs/RegularDropDown";
|
||||
import useChartStore from "../../../../../store/useChartStore";
|
||||
import { useSelectedZoneStore } from "../../../../../store/useZoneStore";
|
||||
import { useWidgetStore } from "../../../../../store/useWidgetStore";
|
||||
import axios from "axios";
|
||||
import RenameInput from "../../../../ui/inputs/RenameInput";
|
||||
|
||||
type Props = {};
|
||||
|
||||
const FleetEfficiencyInputComponent = (props: Props) => {
|
||||
const [widgetName, setWidgetName] = useState('Widget');
|
||||
const { setFlotingMeasurements, updateFlotingDuration, updateHeader } = useChartStore();
|
||||
const [duration, setDuration] = useState('1h')
|
||||
const [dropDowndata, setDropDownData] = useState({});
|
||||
const [selections, setSelections] = useState<Record<string, { name: string; fields: string }>>({});
|
||||
const { selectedZone } = useSelectedZoneStore();
|
||||
const { selectedChartId } = useWidgetStore();
|
||||
const iotApiUrl = process.env.REACT_APP_IOT_SOCKET_SERVER_URL;
|
||||
const email = localStorage.getItem("email") || "";
|
||||
const organization = email?.split("@")[1]?.split(".")[0]
|
||||
|
||||
useEffect(() => {
|
||||
const fetchZoneData = async () => {
|
||||
try {
|
||||
const response = await axios.get(`http://${iotApiUrl}/getinput`);
|
||||
if (response.status === 200) {
|
||||
// console.log("dropdown data:", response.data);
|
||||
setDropDownData(response.data);
|
||||
} else {
|
||||
console.log("Unexpected response:", response);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("There was an error!", error);
|
||||
}
|
||||
};
|
||||
fetchZoneData();
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
const fetchSavedInputes = async () => {
|
||||
if (selectedChartId.id !== "") {
|
||||
try {
|
||||
const response = await axios.get(`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/A_floatWidget/${selectedChartId.id}/${organization}`);
|
||||
if (response.status === 200) {
|
||||
console.log(response.data);
|
||||
|
||||
setSelections(response.data.Data.measurements)
|
||||
setDuration(response.data.Data.duration)
|
||||
setWidgetName(response.data.header)
|
||||
} else {
|
||||
console.log("Unexpected response:", response);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("There was an error!", error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fetchSavedInputes();
|
||||
|
||||
}, [selectedChartId.id]);
|
||||
|
||||
// Sync Zustand state when component mounts
|
||||
useEffect(() => {
|
||||
setFlotingMeasurements(selections);
|
||||
updateFlotingDuration(duration);
|
||||
updateHeader(widgetName);
|
||||
}, [selections, duration, widgetName]);
|
||||
|
||||
|
||||
const sendInputes = async (inputMeasurement: any, inputDuration: any, inputName: any) => {
|
||||
try {
|
||||
const response = await axios.post(`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/floatwidget/save`, {
|
||||
organization: organization,
|
||||
zoneId: selectedZone.zoneId,
|
||||
widget: {
|
||||
id: selectedChartId.id,
|
||||
header: inputName,
|
||||
Data: {
|
||||
measurements: inputMeasurement,
|
||||
duration: inputDuration
|
||||
}
|
||||
}
|
||||
} as any);
|
||||
if (response.status === 200) {
|
||||
return true
|
||||
} else {
|
||||
console.log("Unexpected response:", response);
|
||||
return false
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("There was an error!", error);
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
const handleSelect = async (inputKey: string, selectedData: { name: string; fields: string } | null) => {
|
||||
|
||||
// async() => {
|
||||
const newSelections = { ...selections };
|
||||
if (selectedData === null) {
|
||||
delete newSelections[inputKey];
|
||||
} else {
|
||||
newSelections[inputKey] = selectedData;
|
||||
}
|
||||
// setMeasurements(newSelections); // Update Zustand store
|
||||
console.log(newSelections);
|
||||
if (await sendInputes(newSelections, duration, widgetName)) {
|
||||
setSelections(newSelections);
|
||||
}
|
||||
// sendInputes(newSelections, duration); // Send data to server
|
||||
// return newSelections;
|
||||
// };
|
||||
};
|
||||
|
||||
const handleSelectDuration = async (option: string) => {
|
||||
if (await sendInputes(selections, option, widgetName)) {
|
||||
setDuration(option);
|
||||
}
|
||||
// setDuration(option);
|
||||
};
|
||||
|
||||
const handleNameChange = async (name:any) => {
|
||||
console.log('name change requested',name);
|
||||
|
||||
if (await sendInputes(selections, duration, name)) {
|
||||
setWidgetName(name);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="inputs-wrapper">
|
||||
<div className="datas">
|
||||
<div className="datas__label">Title</div>
|
||||
<RenameInput value={selectedChartId?.header || "untited"} onRename={handleNameChange}/>
|
||||
</div>
|
||||
{[...Array(1)].map((_, index) => {
|
||||
const inputKey = `input${index + 1}`;
|
||||
return (
|
||||
<div key={index} className="datas">
|
||||
<div className="datas__label">Input {index + 1}</div>
|
||||
<div className="datas__class">
|
||||
<MultiLevelDropdown
|
||||
data={dropDowndata}
|
||||
onSelect={(selectedData) => handleSelect(inputKey, selectedData)}
|
||||
onUnselect={() => handleSelect(inputKey, null)}
|
||||
selectedValue={selections[inputKey]} // Load from Zustand
|
||||
/>
|
||||
<div className="icon">
|
||||
<AddIcon />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
<div>
|
||||
{/* <div className="datas">
|
||||
<div className="datas__label">Duration</div>
|
||||
<div className="datas__class">
|
||||
<RegularDropDown
|
||||
header={duration}
|
||||
options={["1h", "2h", "12h"]}
|
||||
onSelect={handleSelectDuration}
|
||||
search={false}
|
||||
/>
|
||||
</div>
|
||||
</div> */}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default FleetEfficiencyInputComponent;
|
||||
@@ -3,6 +3,9 @@ import LineGrapInput from './LineGrapInput'
|
||||
import BarChartInput from './BarChartInput'
|
||||
import PieChartInput from './PieChartInput'
|
||||
import FlotingWidgetInput from './FlotingWidgetInput'
|
||||
import FleetEfficiencyInputComponent from './FleetEfficiencyInputComponent'
|
||||
import Progress1Input from './Progress1Input'
|
||||
import Progress2Input from './Progress2Input'
|
||||
import WarehouseThroughputInputComponent from './WarehouseThroughputInputComponent'
|
||||
import { useWidgetStore } from '../../../../../store/useWidgetStore'
|
||||
|
||||
@@ -56,6 +59,24 @@ const InputSelecterComponent = () => {
|
||||
)
|
||||
}
|
||||
|
||||
else if (selectedChartId && selectedChartId.type && selectedChartId.type === 'progress 1' ) {
|
||||
return (
|
||||
<>
|
||||
<div className="sideBarHeader">2D Widget Input</div>
|
||||
<Progress1Input />
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
else if (selectedChartId && selectedChartId.type && selectedChartId.type === 'progress 2' ) {
|
||||
return (
|
||||
<>
|
||||
<div className="sideBarHeader">2D Widget Input</div>
|
||||
<Progress2Input />
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
else if (selectedChartId && selectedChartId.className && selectedChartId.className === 'warehouseThroughput floating' ) {
|
||||
return (
|
||||
<>
|
||||
@@ -65,6 +86,24 @@ const InputSelecterComponent = () => {
|
||||
)
|
||||
}
|
||||
|
||||
else if (selectedChartId && selectedChartId.className && selectedChartId.className === 'fleetEfficiency floating' ) {
|
||||
return (
|
||||
<>
|
||||
<div className="sideBarHeader">Floting Widget Input</div>
|
||||
<FleetEfficiencyInputComponent />
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
else if (selectedChartId && selectedChartId.className && selectedChartId.className === 'floating total-card' ) {
|
||||
return (
|
||||
<>
|
||||
<div className="sideBarHeader">Floting Widget Input</div>
|
||||
<FleetEfficiencyInputComponent />
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
else {
|
||||
return (
|
||||
<div>No chart selected</div>
|
||||
|
||||
@@ -0,0 +1,171 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
import MultiLevelDropdown from "../../../../ui/inputs/MultiLevelDropDown";
|
||||
import { AddIcon } from "../../../../icons/ExportCommonIcons";
|
||||
import RegularDropDown from "../../../../ui/inputs/RegularDropDown";
|
||||
import useChartStore from "../../../../../store/useChartStore";
|
||||
import { useSelectedZoneStore } from "../../../../../store/useZoneStore";
|
||||
import { useWidgetStore } from "../../../../../store/useWidgetStore";
|
||||
import axios from "axios";
|
||||
import RenameInput from "../../../../ui/inputs/RenameInput";
|
||||
|
||||
type Props = {};
|
||||
|
||||
const Progress1Input = (props: Props) => {
|
||||
const [widgetName, setWidgetName] = useState('Widget');
|
||||
const { setMeasurements, updateDuration, updateName } = useChartStore();
|
||||
const [duration, setDuration] = useState('1h')
|
||||
const [dropDowndata, setDropDownData] = useState({});
|
||||
const [selections, setSelections] = useState<Record<string, { name: string; fields: string }>>({});
|
||||
const { selectedZone } = useSelectedZoneStore();
|
||||
const { selectedChartId } = useWidgetStore();
|
||||
const iotApiUrl = process.env.REACT_APP_IOT_SOCKET_SERVER_URL;
|
||||
const email = localStorage.getItem("email") || "";
|
||||
const organization = email?.split("@")[1]?.split(".")[0]
|
||||
|
||||
useEffect(() => {
|
||||
const fetchZoneData = async () => {
|
||||
try {
|
||||
const response = await axios.get(`http://${iotApiUrl}/getinput`);
|
||||
if (response.status === 200) {
|
||||
// console.log("dropdown data:", response.data);
|
||||
setDropDownData(response.data);
|
||||
} else {
|
||||
console.log("Unexpected response:", response);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("There was an error!", error);
|
||||
}
|
||||
};
|
||||
fetchZoneData();
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
const fetchSavedInputes = async () => {
|
||||
if (selectedChartId.id !== "") {
|
||||
try {
|
||||
const response = await axios.get(`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/WidgetData/${selectedChartId.id}/${organization}`);
|
||||
if (response.status === 200) {
|
||||
setSelections(response.data.Data.measurements)
|
||||
setDuration(response.data.Data.duration)
|
||||
setWidgetName(response.data.widgetName)
|
||||
} else {
|
||||
console.log("Unexpected response:", response);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("There was an error!", error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fetchSavedInputes();
|
||||
|
||||
}, [selectedChartId.id]);
|
||||
|
||||
// Sync Zustand state when component mounts
|
||||
useEffect(() => {
|
||||
setMeasurements(selections);
|
||||
updateDuration(duration);
|
||||
updateName(widgetName);
|
||||
}, [selections, duration, widgetName]);
|
||||
|
||||
|
||||
const sendInputes = async (inputMeasurement: any, inputDuration: any, inputName: any) => {
|
||||
try {
|
||||
const response = await axios.post(`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/widget/save`, {
|
||||
organization: organization,
|
||||
zoneId: selectedZone.zoneId,
|
||||
widget: {
|
||||
id: selectedChartId.id,
|
||||
panel: selectedChartId.panel,
|
||||
widgetName: inputName,
|
||||
Data: {
|
||||
measurements: inputMeasurement,
|
||||
duration: inputDuration
|
||||
}
|
||||
}
|
||||
} as any);
|
||||
if (response.status === 200) {
|
||||
return true
|
||||
} else {
|
||||
console.log("Unexpected response:", response);
|
||||
return false
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("There was an error!", error);
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
const handleSelect = async (inputKey: string, selectedData: { name: string; fields: string } | null) => {
|
||||
|
||||
// async() => {
|
||||
const newSelections = { ...selections };
|
||||
if (selectedData === null) {
|
||||
delete newSelections[inputKey];
|
||||
} else {
|
||||
newSelections[inputKey] = selectedData;
|
||||
}
|
||||
// setMeasurements(newSelections); // Update Zustand store
|
||||
console.log(newSelections);
|
||||
if (await sendInputes(newSelections, duration, widgetName)) {
|
||||
setSelections(newSelections);
|
||||
}
|
||||
};
|
||||
|
||||
const handleSelectDuration = async (option: string) => {
|
||||
if (await sendInputes(selections, option, widgetName)) {
|
||||
setDuration(option);
|
||||
}
|
||||
};
|
||||
|
||||
const handleNameChange = async (name:any) => {
|
||||
if (await sendInputes(selections, duration, name)) {
|
||||
setWidgetName(name);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="inputs-wrapper">
|
||||
<div className="datas">
|
||||
<div className="datas__label">Title</div>
|
||||
<RenameInput value={selectedChartId?.title || "untited"} onRename={handleNameChange}/>
|
||||
</div>
|
||||
{[...Array(1)].map((_, index) => {
|
||||
const inputKey = `input${index + 1}`;
|
||||
return (
|
||||
<div key={index} className="datas">
|
||||
<div className="datas__label">Input {index + 1}</div>
|
||||
<div className="datas__class">
|
||||
<MultiLevelDropdown
|
||||
data={dropDowndata}
|
||||
onSelect={(selectedData) => handleSelect(inputKey, selectedData)}
|
||||
onUnselect={() => handleSelect(inputKey, null)}
|
||||
selectedValue={selections[inputKey]} // Load from Zustand
|
||||
/>
|
||||
<div className="icon">
|
||||
<AddIcon />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
{/* <div>
|
||||
<div className="datas">
|
||||
<div className="datas__label">Duration</div>
|
||||
<div className="datas__class">
|
||||
<RegularDropDown
|
||||
header={duration}
|
||||
options={["1h", "2h", "12h"]}
|
||||
onSelect={handleSelectDuration}
|
||||
search={false}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div> */}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default Progress1Input;
|
||||
@@ -0,0 +1,171 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
import MultiLevelDropdown from "../../../../ui/inputs/MultiLevelDropDown";
|
||||
import { AddIcon } from "../../../../icons/ExportCommonIcons";
|
||||
import RegularDropDown from "../../../../ui/inputs/RegularDropDown";
|
||||
import useChartStore from "../../../../../store/useChartStore";
|
||||
import { useSelectedZoneStore } from "../../../../../store/useZoneStore";
|
||||
import { useWidgetStore } from "../../../../../store/useWidgetStore";
|
||||
import axios from "axios";
|
||||
import RenameInput from "../../../../ui/inputs/RenameInput";
|
||||
|
||||
type Props = {};
|
||||
|
||||
const Progress2Input = (props: Props) => {
|
||||
const [widgetName, setWidgetName] = useState('Widget');
|
||||
const { setMeasurements, updateDuration, updateName } = useChartStore();
|
||||
const [duration, setDuration] = useState('1h')
|
||||
const [dropDowndata, setDropDownData] = useState({});
|
||||
const [selections, setSelections] = useState<Record<string, { name: string; fields: string }>>({});
|
||||
const { selectedZone } = useSelectedZoneStore();
|
||||
const { selectedChartId } = useWidgetStore();
|
||||
const iotApiUrl = process.env.REACT_APP_IOT_SOCKET_SERVER_URL;
|
||||
const email = localStorage.getItem("email") || "";
|
||||
const organization = email?.split("@")[1]?.split(".")[0]
|
||||
|
||||
useEffect(() => {
|
||||
const fetchZoneData = async () => {
|
||||
try {
|
||||
const response = await axios.get(`http://${iotApiUrl}/getinput`);
|
||||
if (response.status === 200) {
|
||||
// console.log("dropdown data:", response.data);
|
||||
setDropDownData(response.data);
|
||||
} else {
|
||||
console.log("Unexpected response:", response);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("There was an error!", error);
|
||||
}
|
||||
};
|
||||
fetchZoneData();
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
const fetchSavedInputes = async () => {
|
||||
if (selectedChartId.id !== "") {
|
||||
try {
|
||||
const response = await axios.get(`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/WidgetData/${selectedChartId.id}/${organization}`);
|
||||
if (response.status === 200) {
|
||||
setSelections(response.data.Data.measurements)
|
||||
setDuration(response.data.Data.duration)
|
||||
setWidgetName(response.data.widgetName)
|
||||
} else {
|
||||
console.log("Unexpected response:", response);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("There was an error!", error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fetchSavedInputes();
|
||||
|
||||
}, [selectedChartId.id]);
|
||||
|
||||
// Sync Zustand state when component mounts
|
||||
useEffect(() => {
|
||||
setMeasurements(selections);
|
||||
updateDuration(duration);
|
||||
updateName(widgetName);
|
||||
}, [selections, duration, widgetName]);
|
||||
|
||||
|
||||
const sendInputes = async (inputMeasurement: any, inputDuration: any, inputName: any) => {
|
||||
try {
|
||||
const response = await axios.post(`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/widget/save`, {
|
||||
organization: organization,
|
||||
zoneId: selectedZone.zoneId,
|
||||
widget: {
|
||||
id: selectedChartId.id,
|
||||
panel: selectedChartId.panel,
|
||||
widgetName: inputName,
|
||||
Data: {
|
||||
measurements: inputMeasurement,
|
||||
duration: inputDuration
|
||||
}
|
||||
}
|
||||
} as any);
|
||||
if (response.status === 200) {
|
||||
return true
|
||||
} else {
|
||||
console.log("Unexpected response:", response);
|
||||
return false
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("There was an error!", error);
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
const handleSelect = async (inputKey: string, selectedData: { name: string; fields: string } | null) => {
|
||||
|
||||
// async() => {
|
||||
const newSelections = { ...selections };
|
||||
if (selectedData === null) {
|
||||
delete newSelections[inputKey];
|
||||
} else {
|
||||
newSelections[inputKey] = selectedData;
|
||||
}
|
||||
// setMeasurements(newSelections); // Update Zustand store
|
||||
console.log(newSelections);
|
||||
if (await sendInputes(newSelections, duration, widgetName)) {
|
||||
setSelections(newSelections);
|
||||
}
|
||||
};
|
||||
|
||||
const handleSelectDuration = async (option: string) => {
|
||||
if (await sendInputes(selections, option, widgetName)) {
|
||||
setDuration(option);
|
||||
}
|
||||
};
|
||||
|
||||
const handleNameChange = async (name:any) => {
|
||||
if (await sendInputes(selections, duration, name)) {
|
||||
setWidgetName(name);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="inputs-wrapper">
|
||||
<div className="datas">
|
||||
<div className="datas__label">Title</div>
|
||||
<RenameInput value={selectedChartId?.title || "untited"} onRename={handleNameChange}/>
|
||||
</div>
|
||||
{[...Array(2)].map((_, index) => {
|
||||
const inputKey = `input${index + 1}`;
|
||||
return (
|
||||
<div key={index} className="datas">
|
||||
<div className="datas__label">Input {index + 1}</div>
|
||||
<div className="datas__class">
|
||||
<MultiLevelDropdown
|
||||
data={dropDowndata}
|
||||
onSelect={(selectedData) => handleSelect(inputKey, selectedData)}
|
||||
onUnselect={() => handleSelect(inputKey, null)}
|
||||
selectedValue={selections[inputKey]} // Load from Zustand
|
||||
/>
|
||||
<div className="icon">
|
||||
<AddIcon />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
{/* <div>
|
||||
<div className="datas">
|
||||
<div className="datas__label">Duration</div>
|
||||
<div className="datas__class">
|
||||
<RegularDropDown
|
||||
header={duration}
|
||||
options={["1h", "2h", "12h"]}
|
||||
onSelect={handleSelectDuration}
|
||||
search={false}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div> */}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default Progress2Input;
|
||||
Reference in New Issue
Block a user