Skip to content

Commit

Permalink
Merge pull request #96 from BU-Spark/bugFixes
Browse files Browse the repository at this point in the history
Bug fixes
  • Loading branch information
nmr2701 authored Sep 19, 2024
2 parents ad6e12d + 5809b4c commit 0dd7d45
Show file tree
Hide file tree
Showing 6 changed files with 221 additions and 48 deletions.
38 changes: 38 additions & 0 deletions frontend/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,12 @@
"@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^13.5.0",
"@types/jest": "^29.5.4",
"@types/lodash": "^4.17.7",
"@types/node": "^20.6.0",
"@types/react": "^18.2.25",
"@types/react-dom": "^18.2.7",
"@types/react-redux": "^7.1.26",
"@types/react-window": "^1.8.8",
"@types/redux-logger": "^3.0.9",
"antd": "^5.4.2",
"axios": "^1.6.1",
Expand All @@ -40,6 +42,7 @@
"google-map-react": "^2.2.0",
"graphql": "^16.6.0",
"konva": "^9.2.0",
"lodash": "^4.17.21",
"moment": "^2.29.4",
"pigeon-maps": "^0.21.3",
"pigeon-maps-cluster": "^1.0.8",
Expand All @@ -54,6 +57,7 @@
"react-tabs": "^6.0.2",
"react-toastify": "^10.0.5",
"react-tooltip": "^5.10.0",
"react-window": "^1.8.10",
"redux-logger": "^3.0.6",
"serve": "^14.2.1",
"supercluster": "^8.0.1",
Expand Down
73 changes: 45 additions & 28 deletions frontend/src/components/LocationsDropDown/LocationsDropDown.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
import React, { useContext } from "react";
import React, { useContext, useMemo } from "react";
import { MenuProps } from "antd";
import { Menu } from "antd";
import { LocationContext } from "../../contexts/location_context";
import { Locations } from "../../__generated__/graphql";
import { Card, CardContent } from "@mui/material";
import { Input } from "antd"; // Import Input for search bar



import { Input } from "antd";
import { debounce } from "lodash"; // Import lodash debounce
import { FixedSizeList as List, ListChildComponentProps } from 'react-window'; // Import react-window for virtualization

type MenuItem = Required<MenuProps>["items"][number];

Expand All @@ -18,39 +17,57 @@ interface LocationsDropDownProps {

const LocationsDropDown: React.FC<LocationsDropDownProps> = ({ selectedLocation, setSelectedLocation }) => {
const { locationsData } = useContext(LocationContext)!;
const [searchTerm, setSearchTerm] = React.useState(""); // State for search term
const [searchTerm, setSearchTerm] = React.useState<string>(""); // Add explicit string type

// Debounced search term update
const debouncedSetSearchTerm = debounce((value: string) => setSearchTerm(value), 300);

// Memoized filtered locations
const filteredItems: Locations[] = useMemo(() => {
return locationsData?.filter(location =>
location.value.toLowerCase().includes(searchTerm.toLowerCase())
)
.sort((a, b) => b.articles.length - a.articles.length) || []; // Sort by article count descending
}, [locationsData, searchTerm]);

const filteredItems: MenuItem[] = locationsData?.filter(location =>
location.value.toLowerCase().includes(searchTerm.toLowerCase())
).map(location => ({
key: location.value,
label: `${location.value} - ${location.articles.length} articles`,
onClick: () => {
setSelectedLocation(location);
},
})) || [];
// Virtualized List Row Component
const Row = ({ index, style }: ListChildComponentProps) => {
const location = filteredItems[index];
const isSelected = selectedLocation?.value === location.value;
return (
<div
style={{
...style,
backgroundColor: isSelected ? '#e6f7ff' : 'transparent', // Highlight selected item
padding: '10px',
color: isSelected ? '#1890ff' : 'black', // Change text color of selected item
}}
onClick={() => setSelectedLocation(location)}
>
{location.value} - {location.articles.length} articles
</div>
);
};

return (
<Card sx={{ width: "100%", height: "62vh" }}>
<CardContent sx={{ width: "100%", height: "62vh" }}>
<Input
placeholder="Search locations..." // Search bar placeholder
value={searchTerm}
onChange={e => setSearchTerm(e.target.value)} // Update search term
style={{ marginBottom: '10px' }} // Spacing for search bar
/>
<Menu
items={filteredItems}
style={{ width: "100%", height: "100%", overflow: "auto" }} // Added overflow: 'auto'
selectedKeys={selectedLocation?.value ? [selectedLocation.value] : []}


placeholder="Search locations..."
onChange={e => debouncedSetSearchTerm(e.target.value)}
style={{ marginBottom: '10px' }}
/>
<List
height={450} // Set the height of the virtualized list
itemCount={filteredItems.length} // Total items
itemSize={45} // Height of each row
width={"100%"} // Set width of the list
>
{Row}
</List>
</CardContent>
</Card>
);
);
};

export default LocationsDropDown;
export default LocationsDropDown;
86 changes: 86 additions & 0 deletions frontend/src/components/TopicCount/TopicCount.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import React, { useState } from "react";
import { Article } from "../../__generated__/graphql";
import { Button, Modal, Box, Typography, Card, CardContent } from "@mui/material";
import { useNavigate } from "react-router-dom";
import { List, ListItem, ListItemText } from "@mui/material"; // Add List imports



interface TopicCountProps {
articles: Article[];
}

const TopicCount: React.FC<TopicCountProps> = ({ articles }) => {
const [open, setOpen] = useState(false);
const topicCounts: Record<string, number> = {};
const navigate = useNavigate();

// Count occurrences of each topic
articles.forEach((article) => {
const topic = article.openai_labels;
if (topic) {
topicCounts[topic] = (topicCounts[topic] || 0) + 1;
}
});

// Get top 5 topics
const topTopics = Object.entries(topicCounts)
.sort(([, countA], [, countB]) => countB - countA)
.slice(0, 5);

// Handle modal open/close
const handleOpen = () => setOpen(true);
const handleClose = () => setOpen(false);

// Navigate to topic page
const handleTopicClick = (topic: string) => {
navigate(`/Topics?topic=${encodeURIComponent(topic)}`);
};

return (
<Card sx={{ height: "62vh" }}>
<CardContent sx={{ height: "100%" }}>
<List> {/* Use List component */}
{topTopics.map(([topic, count]) => (
<ListItem key={topic} onClick={() => handleTopicClick(topic)} style={{ cursor: 'pointer', color:'#1E90FF' }}>
<ListItemText primary={`${topic}: ${count}`} />
</ListItem>
))}
</List>
<Button variant="outlined" onClick={handleOpen}>
View All Topics Count
</Button>

<Modal open={open} onClose={handleClose}>
<Box sx={{
position: 'absolute',
top: '50%',
left: '50%',
transform: 'translate(-50%, -50%)',
bgcolor: 'background.paper',
boxShadow: 24,
p: 4,
maxHeight: '80vh',
overflowY: 'auto',
width: '80%', // Make modal wider
}}>
<Typography variant="h6" component="h2">
All Topic Counts
</Typography>
<List sx={{ display: 'flex', flexWrap: 'wrap', justifyContent: 'space-between' }}> {/* Use flexbox for layout */}
{Object.entries(topicCounts)
.sort(([, countA], [, countB]) => countB - countA) // Sort by count in descending order
.map(([topic, count]) => (
<ListItem key={topic} onClick={() => handleTopicClick(topic)} style={{ cursor: 'pointer', width: '23%', color:'#1E90FF' }}>
<ListItemText primary={`${topic}: ${count}`} />
</ListItem>
))}
</List>
<Button onClick={handleClose}>Close</Button>
</Box>
</Modal>
</CardContent>
</Card>
);
}
export default TopicCount;
Loading

0 comments on commit 0dd7d45

Please sign in to comment.