Page Menu
Home
c4science
Search
Configure Global Search
Log In
Files
F100159301
ConceptBoxes.js
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Subscribers
None
File Metadata
Details
File Info
Storage
Attached
Created
Tue, Jan 28, 15:37
Size
13 KB
Mime Type
text/x-java
Expires
Thu, Jan 30, 15:37 (2 d)
Engine
blob
Format
Raw Data
Handle
23912653
Attached To
R13029 webapp_nextjs
ConceptBoxes.js
View Options
import React, {useEffect, useRef, useState} from 'react';
import {FontAwesomeIcon} from '@fortawesome/react-fontawesome';
import {faTimes, faArrowUp, faArrowDown, faArrowRight} from '@fortawesome/free-solid-svg-icons';
import {callbackAddConceptsToBoxes} from "@/app/utils/utils";
function ConceptBox({
concept,
onRemove,
handleMagicClick,
setToolTipVisible,
setToolTipContent,
setSearchData,
searchData,
}) {
const [showPopup, setShowPopup] = useState(false);
const [popupContent, setPopupContent] = useState(null);
const [conceptClicked, setConceptClicked] = useState(false);
const popupRef = useRef(null);
const buttonRefs = useRef([]);
const handleMouseEnter = (title, event, setToolTipContent, setToolTipVisible) => {
setToolTipContent(title);
setToolTipVisible(true);
};
const handleMouseLeave = (setToolTipVisible) => {
setShowPopup(false);
setToolTipVisible(false);
};
const handleMouseClickConcept = (concept, event) => {
event.stopPropagation();
console.log('concept', concept)
if (JSON.stringify(concept) === JSON.stringify(conceptClicked)) {
setConceptClicked(false);
setShowPopup(false);
return;
}
setConceptClicked(concept);
setPopupContent(concept);
setShowPopup(true);
}
useEffect(() => {
const handleClickOutside = (event) => {
if (
showPopup &&
popupRef.current &&
!popupRef.current.contains(event.target) &&
// Check all the button refs
!buttonRefs.current.some(ref => ref.contains(event.target))
) {
setShowPopup(false);
setConceptClicked(null);
}
}
document.addEventListener("mousedown", handleClickOutside);
return () => {
document.removeEventListener("mousedown", handleClickOutside);
}
}, [showPopup]);
let boxWidth = 140
if (!concept.siblings) {
boxWidth += 30
}
if (!concept.parent) {
boxWidth += 30
}
if (!concept.children || concept.children.length === 0) {
boxWidth += 30
}
return (
<div className="block concept" style={{position: 'relative'}}>
<div className="input-group input-group-sm" style={{width: '260px'}}>
<span
id={`text${concept.id}`}
data-pageid={concept.title}
className="input-group-text"
style={{overflow: 'hidden', width: boxWidth + 'px'}}
onMouseEnter={(e) => handleMouseEnter(
concept.title || concept,
e,
setToolTipContent,
setToolTipVisible,
)}
onMouseLeave={e => handleMouseLeave(setToolTipVisible)}
>
{concept.title || concept}
</span>
{concept.parent && (
<button
ref={(el) => buttonRefs.current[0] = el}
className="btn btn-primary form-control"
style={{flex: '0 1 30px'}}
onClick={(e) => {
e.stopPropagation();
handleMouseClickConcept([concept.parent], e)
}}
>
<FontAwesomeIcon icon={faArrowUp}/>
</button>
)}
{concept.children && concept.children.length > 0 && (
<button
ref={(el) => buttonRefs.current[1] = el}
className="btn btn-primary form-control"
style={{flex: '0 1 30px'}}
onClick={(e) => {
e.stopPropagation();
handleMouseClickConcept(concept.children, e)
}
}
>
<FontAwesomeIcon icon={faArrowDown}/>
</button>
)}
{concept.siblings && concept.siblings.length > 0 && (
<button
ref={(el) => buttonRefs.current[2] = el}
className="btn btn-primary form-control"
style={{flex: '0 1 30px'}}
onClick={(e) => {
e.stopPropagation();
handleMouseClickConcept(concept.siblings, e)
}
}>
<FontAwesomeIcon icon={faArrowRight}/>
</button>
)}
<button
ref={(el) => buttonRefs.current[3] = el}
className="btn btn-danger form-control"
style={{flex: '0 1 30px', backgroundColor: 'red'}}
onClick={() => onRemove(concept)}
>
<FontAwesomeIcon icon={faTimes}/>
</button>
</div>
{showPopup && (
<div
ref={popupRef}
style={{
position: 'absolute',
top: '-70px',
left: '260px',
background: '#fff',
border: '1px solid #ccc',
padding: '10px',
borderRadius: '5px', // Added rounded corners
boxShadow: '0px 0px 10px rgba(0,0,0,0.1)', // Added a shadow for a "lifted" effect
zIndex: 1000
}}>
{popupContent.map((sibling, index) => (
<div key={index} className="d-flex justify-content-between align-items-right mb-2" style={{
padding: '5px',
borderRadius: '3px',
width: '100%'
}}>
<div style={{flexGrow: 1, padding: '5px'}}>{sibling.title}</div>
<button className="btn btn-primary" style={{
flex: '0 0 30px',
backgroundColor: 'green',
marginLeft: '10px',
borderRadius: '3px'
}} onClick={() => handleMagicClick(sibling, searchData, setSearchData)}>+
</button>
</div>
))}
</div>
)}
</div>
);
}
function ConceptBoxes({
setToolTipContent,
setToolTipVisible,
freeTextSearch,
searchData,
setSearchData,
searchEntity,
setRenderForceGraph,
removeNodeInGraph,
}) {
console.log('render ConceptBoxes');
// console.log('conceptsToAddBoxes', conceptsToAddBoxes)
useEffect(() => {
console.log("searchData", searchData)
}, [searchData])
const handleRemoveClick = (conceptToRemove) => {
setRenderForceGraph(false)
console.log('conceptToRemove', conceptToRemove)
// setTableColumnsInRightOrder(tableColumnsInRightOrder.filter((concept) => concept !== conceptToRemove.title));
// setConceptsToAddBoxes(conceptsToAddBoxes.filter((concept) => concept !== conceptToRemove));
let conceptsToAddBoxes = searchData['conceptsToAddBoxes']
conceptsToAddBoxes = conceptsToAddBoxes.filter((concept) => concept !== conceptToRemove);
let tableColumnsInRightOrder = searchData['tableColumnsInRightOrder']
tableColumnsInRightOrder = tableColumnsInRightOrder.filter((concept) => concept !== conceptToRemove.title);
console.log('conceptsToAddBoxes', conceptsToAddBoxes)
console.log('concepttoRemove', conceptToRemove)
// remove rows from searchData['table'] if they have only zeros left
let table = searchData['table']
let tableWithoutConceptToRemove = table.filter(
// check if any or row[column] is not 0 for column in tableColumnsInRightOrder
(row) => tableColumnsInRightOrder.some((column) => row[column] !== 0)
)
console.log('tableWithoutConceptToRemove', tableWithoutConceptToRemove)
setSearchData({
...searchData,
'conceptsToAddBoxes': conceptsToAddBoxes,
'tableColumnsInRightOrder': tableColumnsInRightOrder,
'table': tableWithoutConceptToRemove
})
removeNodeInGraph(conceptToRemove.title)
};
const handleMagicClick = (concept, searchData, setSearchData) => {
console.log('concept', concept)
console.log('handleMagicClick searchdata', searchData)
if (concept.id[0] === 'p') {
console.log('concept is a page')
} else if (concept.id[0] === 'c') {
console.log('concept is a category')
}
let callback = (data) => {
console.log('received data', data)
if(data['table'].length === 0){
console.log('received data is empty')
return
}
let myNewConceptsToAddBoxes_with_duplicates = [
...searchData['conceptsToAddBoxes'],
...data['conceptsToAddBoxes']
]
let myNewConceptsToAddBoxes = []
const seen = new Set();
for (const item of myNewConceptsToAddBoxes_with_duplicates) {
if (!seen.has(item.id)) {
seen.add(item.id);
myNewConceptsToAddBoxes.push(item);
}
}
let myNewConceptsOfPeople = {
...searchData['conceptsOfPeople'],
...data['conceptsOfPeople']
}
let myNewTableColumnsInRightOrder = [
...new Set([
...searchData['tableColumnsInRightOrder'],
...data['tableColumnsInRightOrder']
])
]
// create new table with all rows from both tables
// Create lookup objects.
let lookupData = {};
let lookupSearchData = {};
data['table'].forEach(item => lookupData[item.ID] = item);
searchData['table'].forEach(item => lookupSearchData[item.ID] = item);
// Get the unique keys from both data sets
let setOfKeys1 = new Set(data['table'].flatMap(item => Object.keys(item)));
let setOfKeys2 = new Set(searchData['table'].flatMap(item => Object.keys(item)));
// Create a merged array
let mergedArray = [];
// Get the union of keys from both datasets
let allKeys = [...new Set([...setOfKeys1, ...setOfKeys2])];
// Iterate through the IDs in both datasets
let allIDs = [...new Set([...data['table'].map(item => item.ID), ...searchData['table'].map(item => item.ID)])];
allIDs.forEach(id => {
let baseData = lookupData[id] || {};
let searchItem = lookupSearchData[id] || {};
let mergedItem = {ID: id}; // Initialize with ID
allKeys.forEach(key => {
mergedItem[key] = baseData[key] || searchItem[key] || 0;
});
mergedArray.push(mergedItem);
});
// Now mergedArray will have your required data
let myNewData = {
...searchData,
'conceptsToAddBoxes': myNewConceptsToAddBoxes,
'conceptsOfPeople': myNewConceptsOfPeople,
'tableColumnsInRightOrder': myNewTableColumnsInRightOrder,
'table': mergedArray
}
setSearchData(myNewData)
}
if (concept.id[0] === 'p') {
freeTextSearch('#' + concept.title,
30,
searchEntity,
callbackAddConceptsToBoxes,
'concepts',
searchData,
setSearchData);
}
if (concept.id[0] === 'c') {
freeTextSearch('+' + concept.title,
30,
searchEntity,
callbackAddConceptsToBoxes,
'concepts',
searchData,
setSearchData);
}
};
return (
<div id="selected-id">
{(searchData['conceptsToAddBoxes'] || searchData['tableColumnsInRightOrder']).map((concept, index) => (
<ConceptBox key={index} concept={concept} onRemove={handleRemoveClick}
handleMagicClick={handleMagicClick}
setToolTipVisible={setToolTipVisible}
setToolTipContent={setToolTipContent}
searchData={searchData}
setSearchData={setSearchData}
/>
))}
</div>
);
}
export default React.memo(ConceptBoxes);
Event Timeline
Log In to Comment