diff --git a/src/components/AggregationPanel/AggregationPanel.js b/src/components/AggregationPanel/AggregationPanel.js
index 5cd5a0440..3fbca8882 100644
--- a/src/components/AggregationPanel/AggregationPanel.js
+++ b/src/components/AggregationPanel/AggregationPanel.js
@@ -1,6 +1,7 @@
import LoaderDots from 'components/LoaderDots/LoaderDots.react';
-import React, { useEffect, useMemo } from 'react';
+import React, { useCallback, useEffect, useMemo, useState } from 'react';
import styles from './AggregationPanel.scss';
+import Parse from 'parse';
import {
AudioElement,
ButtonElement,
@@ -19,8 +20,14 @@ const AggregationPanel = ({
errorAggregatedData,
showNote,
setSelectedObjectId,
- selectedObjectId
+ selectedObjectId,
+ depth = 0,
+ cloudCodeFunction = null,
+ panelTitle = null,
}) => {
+ const [isExpanded, setIsExpanded] = useState(false);
+ const [nestedData, setNestedData] = useState(null);
+ const [isLoadingNested, setIsLoadingNested] = useState(false);
useEffect(() => {
if (Object.keys(errorAggregatedData).length !== 0) {
@@ -30,54 +37,149 @@ const AggregationPanel = ({
}, [errorAggregatedData, setSelectedObjectId, setErrorAggregatedData]);
const isLoading = useMemo(() =>
- selectedObjectId && isLoadingCloudFunction && showAggregatedData,
- [selectedObjectId, isLoadingCloudFunction, showAggregatedData]
+ depth === 0 && selectedObjectId && isLoadingCloudFunction && showAggregatedData,
+ [depth, selectedObjectId, isLoadingCloudFunction, showAggregatedData]
);
const shouldShowAggregatedData = useMemo(() =>
- selectedObjectId && showAggregatedData && Object.keys(data).length !== 0 && Object.keys(errorAggregatedData).length === 0, [selectedObjectId, showAggregatedData, data, errorAggregatedData]
+ depth === 0
+ ? (selectedObjectId && showAggregatedData && Object.keys(data).length !== 0 && Object.keys(errorAggregatedData).length === 0)
+ : true,
+ [depth, selectedObjectId, showAggregatedData, data, errorAggregatedData]
);
+ const fetchNestedData = useCallback(async () => {
+ setIsLoadingNested(true);
+ try {
+ const params = { objectId: selectedObjectId };
+ const result = await Parse.Cloud.run(cloudCodeFunction, params);
+ if (result?.panel?.segments) {
+ setNestedData(result);
+ } else {
+ const errorMsg = 'Improper JSON format';
+ showNote(errorMsg, true);
+ }
+ } catch (error) {
+ const errorMsg = error.message;
+ showNote(errorMsg, true);
+ } finally {
+ setIsLoadingNested(false);
+ }
+ }, [cloudCodeFunction, selectedObjectId, showNote]);
+
+ const handleToggle = useCallback(async () => {
+ if (!isExpanded && !nestedData && cloudCodeFunction) {
+ fetchNestedData();
+ }
+ setIsExpanded(prev => !prev);
+ }, [isExpanded, nestedData, cloudCodeFunction, fetchNestedData]);
+
+ const handleRefresh = useCallback(() => {
+ setNestedData(null);
+ setIsExpanded(false);
+ fetchNestedData();
+ }, [fetchNestedData]);
+
+ const renderSegmentContent = (segment, index) => (
+
+
{segment.title}
+
+ {segment.items.map((item, idx) => {
+ switch (item.type) {
+ case 'text':
+ return
;
+ case 'keyValue':
+ return
;
+ case 'table':
+ return
;
+ case 'image':
+ return
;
+ case 'video':
+ return
;
+ case 'audio':
+ return
;
+ case 'button':
+ return
;
+ case 'panel':
+ return (
+
+ );
+ default:
+ return null;
+ }
+ })}
+
+
+ );
+
+ if (depth > 0) {
+ return (
+
+
+
{panelTitle}
+
+ {isExpanded && (
+
+
+ )}
+ {isExpanded ? '▼' : '▲'}
+
+
+ {isExpanded && (
+
+ {isLoadingNested ? (
+
+
+
+ ) : (
+ nestedData && nestedData.panel.segments.map((segment, index) =>
+ renderSegmentContent(segment, index)
+ )
+ )}
+
+ )}
+
+ );
+ }
+
return (
- <>
+
{isLoading ? (
) : shouldShowAggregatedData ? (
- data.panel.segments.map((segment, index) => (
-
-
{segment.title}
-
- {segment.items.map((item, idx) => {
- switch (item.type) {
- case 'text':
- return
;
- case 'keyValue':
- return
;
- case 'table':
- return
;
- case 'image':
- return
;
- case 'video':
- return
;
- case 'audio':
- return
;
- case 'button':
- return
;
- default:
- return null;
- }
- })}
-
-
- ))
+
+ {data.panel.segments.map((segment, index) =>
+ renderSegmentContent(segment, index)
+ )}
+
) : (
-
- No object selected.
+
+ No object selected.
)}
- >
+
);
};
diff --git a/src/components/AggregationPanel/AggregationPanel.scss b/src/components/AggregationPanel/AggregationPanel.scss
index 2bfda1414..58edd2a41 100644
--- a/src/components/AggregationPanel/AggregationPanel.scss
+++ b/src/components/AggregationPanel/AggregationPanel.scss
@@ -11,14 +11,11 @@
.segmentItems {
font-size: 14px;
- padding-left: 10px;
- padding-right: 10px;
- padding-top: 6px;
+ padding: 10px;
display: flex;
flex-direction: column;
- border-left: 1px solid #e3e3ea;
gap: 10px;
-}
+ }
.keyValue {
font-size: 14px;
@@ -76,13 +73,14 @@
text-align: center;
border-radius: 5px;
font-size: 14px;
+
&:hover,
&:focus {
background-color: $darkBlue;
}
}
-.loading{
+.loading {
height: 100%;
display: flex;
flex-direction: column;
@@ -96,4 +94,69 @@
top: 50%;
left: 50%;
@include transform(translate(-50%, -50%));
+}
+
+.nestedPanel {
+ margin-right: -10px;
+ transition: all 0.3s ease;
+}
+
+.nestedPanelHeader {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ gap: 8px;
+ border-left: 1px solid transparent;
+ background-color: $blue;
+ color: $white;
+ cursor: pointer;
+ padding-right: 4px;
+
+ &.expanded {
+ border-left-color: #e3e3ea;
+ }
+ }
+
+.expandButton {
+ display: inline;
+ padding: 8px;
+ font-weight: 500;
+
+ &.expanded {
+ font-weight: 600;
+ }
+}
+
+.refreshButton {
+ background: none;
+ border: none;
+ padding: 4px;
+ cursor: pointer;
+ color: #666;
+ font-size: 16px;
+
+ &:hover {
+ color: #333;
+ }
+
+ &:disabled {
+ color: #ccc;
+ cursor: not-allowed;
+ }
+}
+
+.nestedPanelContent {
+ padding: 0 0 8px 0;
+}
+
+.loader {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+}
+
+.segmentContainer {
+ border-left: 1px solid #e3e3ea;
+ border-bottom: 1px solid #e3e3ea;
+ margin-bottom: 16px;
}
\ No newline at end of file