Skip to content

Commit

Permalink
feat: Add info panel item panel to load and display data on demand (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
vardhan0604 authored Jan 30, 2025
1 parent aa73757 commit 8e5741d
Show file tree
Hide file tree
Showing 2 changed files with 207 additions and 42 deletions.
174 changes: 138 additions & 36 deletions src/components/AggregationPanel/AggregationPanel.js
Original file line number Diff line number Diff line change
@@ -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,
Expand All @@ -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) {
Expand All @@ -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) => (
<div key={index} className={styles.segmentContainer}>
<h2 className={styles.heading}>{segment.title}</h2>
<div className={styles.segmentItems}>
{segment.items.map((item, idx) => {
switch (item.type) {
case 'text':
return <TextElement key={idx} text={item.text} />;
case 'keyValue':
return <KeyValueElement key={idx} item={item} />;
case 'table':
return <TableElement key={idx} columns={item.columns} rows={item.rows} />;
case 'image':
return <ImageElement key={idx} url={item.url} />;
case 'video':
return <VideoElement key={idx} url={item.url} />;
case 'audio':
return <AudioElement key={idx} url={item.url} />;
case 'button':
return <ButtonElement key={idx} item={item} showNote={showNote} />;
case 'panel':
return (
<div key={idx} className={styles.nestedPanelContainer}>
<AggregationPanel
data={{}}
isLoadingCloudFunction={false}
showAggregatedData={true}
setErrorAggregatedData={setErrorAggregatedData}
errorAggregatedData={errorAggregatedData}
showNote={showNote}
setSelectedObjectId={setSelectedObjectId}
selectedObjectId={selectedObjectId}
depth={depth + 1}
cloudCodeFunction={item.cloudCodeFunction}
panelTitle={item.title}
/>
</div>
);
default:
return null;
}
})}
</div>
</div>
);

if (depth > 0) {
return (
<div className={styles.nestedPanel}>
<div className={`${styles.nestedPanelHeader} ${isExpanded ? styles.expanded : ''}`} onClick={handleToggle}>
<span className={`${styles.expandButton} ${isExpanded ? styles.expanded : ''}`}>{panelTitle}</span>
<div>
{isExpanded && (
<button
onClick={handleRefresh}
className={styles.refreshButton}
disabled={isLoadingNested}
>
<span></span>
</button>

)}
<span >{isExpanded ? '▼' : '▲'}</span>
</div>
</div>
{isExpanded && (
<div className={styles.nestedPanelContent}>
{isLoadingNested ? (
<div className={styles.loader}>
<LoaderDots />
</div>
) : (
nestedData && nestedData.panel.segments.map((segment, index) =>
renderSegmentContent(segment, index)
)
)}
</div>
)}
</div>
);
}

return (
<>
<div className={styles.aggregationPanel}>
{isLoading ? (
<div className={styles.center}>
<LoaderDots />
</div>
) : shouldShowAggregatedData ? (
data.panel.segments.map((segment, index) => (
<div key={index}>
<h2 className={styles.heading}>{segment.title}</h2>
<div className={styles.segmentItems}>
{segment.items.map((item, idx) => {
switch (item.type) {
case 'text':
return <TextElement key={idx} text={item.text} />;
case 'keyValue':
return <KeyValueElement key={idx} item={item} />;
case 'table':
return <TableElement key={idx} columns={item.columns} rows={item.rows} />;
case 'image':
return <ImageElement key={idx} url={item.url} />;
case 'video':
return <VideoElement key={idx} url={item.url} />;
case 'audio':
return <AudioElement key={idx} url={item.url} />;
case 'button':
return <ButtonElement key={idx} item={item} showNote={showNote} />;
default:
return null;
}
})}
</div>
</div>
))
<div className={styles.mainContent}>
{data.panel.segments.map((segment, index) =>
renderSegmentContent(segment, index)
)}
</div>
) : (
<div className={styles.loading}>
No object selected.
<div className={styles.center}>
No object selected.
</div>
)}
</>
</div>
);
};

Expand Down
75 changes: 69 additions & 6 deletions src/components/AggregationPanel/AggregationPanel.scss
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand All @@ -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;
}

0 comments on commit 8e5741d

Please sign in to comment.