Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

move to production #2216

Merged
merged 22 commits into from
Nov 6, 2024
Merged
Changes from 1 commit
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
2879c84
location card functionality update
OchiengPaul442 Oct 29, 2024
989191e
updates to chart loading hook
OchiengPaul442 Oct 29, 2024
c4af9e8
Merge remote-tracking branch 'upstream/staging' into analytics-ui-imp…
OchiengPaul442 Oct 29, 2024
6868f16
Update netmanger staging image tag to stage-4beb5b3d-1730806044
github-actions[bot] Nov 5, 2024
706c81b
Update netmanger production image tag to prod-37dd191a-1730806155
github-actions[bot] Nov 5, 2024
ae005f7
use one source of chart data
OchiengPaul442 Nov 5, 2024
618977b
card checklist order fix
OchiengPaul442 Nov 5, 2024
efe51fb
updated url video link
OchiengPaul442 Nov 5, 2024
046aba0
optimize check list hook
OchiengPaul442 Nov 5, 2024
a784fe7
card design update
OchiengPaul442 Nov 5, 2024
ab52a53
fix calendar issue
OchiengPaul442 Nov 5, 2024
b69a13f
terms of service and policy links added
OchiengPaul442 Nov 5, 2024
0e5c26e
update url link
OchiengPaul442 Nov 5, 2024
5f92e7b
scroll on modal
OchiengPaul442 Nov 5, 2024
b66c1ae
chart optimizations
OchiengPaul442 Nov 6, 2024
7350a00
analytics card optimizations
OchiengPaul442 Nov 6, 2024
4adfadd
use of redux state to fetch and store chart data
OchiengPaul442 Nov 6, 2024
b928601
check list optimization (still work in progress)
OchiengPaul442 Nov 6, 2024
0c782cd
removed other pollutants
OchiengPaul442 Nov 6, 2024
22c2f81
Merge pull request #2208 from airqo-platform/analytics-ui-improvements
Baalmart Nov 6, 2024
597d754
Update next platform staging image tag to stage-22c2f81b-1730896329
github-actions[bot] Nov 6, 2024
4c9a91a
Update analytics platform production image tag to prod-37dd191a-17308…
github-actions[bot] Nov 6, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
location card functionality update
OchiengPaul442 committed Oct 29, 2024
commit 2879c844756d80c8d3254c016f8bfc4f6f329b28
Original file line number Diff line number Diff line change
@@ -50,7 +50,6 @@ const TableRowComponent = ({ item, isSelected, onToggleSite, index }) => (
</tr>
);

// Wrap the named function with React.memo and assign displayName
const TableRow = React.memo(TableRowComponent);
TableRow.displayName = 'TableRow';

@@ -216,7 +215,13 @@ const DataTable = ({

// Handle edge case if filteredData is empty
if (filteredData.length === 0) {
return <p>No data available</p>;
return (
<tr>
<td colSpan="5" className="p-4 text-center text-gray-500">
No data available
</td>
</tr>
);
}

return filteredData
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
import React from 'react';
import LocationIcon from '@/icons/Analytics/LocationIcon';

// Helper function to handle truncation logic
const truncateName = (name, maxLength = 25) => {
const truncateName = (name, maxLength = 13) => {
if (!name) return 'Unknown Location';
return name.length > maxLength ? `${name.substring(0, maxLength)}...` : name;
};

/**
* LocationCard Component
* Displays information about a location with a checkbox to toggle selection.
*/
const LocationCard = ({ site, onToggle, isSelected, isLoading }) => {
// Display loading skeleton while loading
if (isLoading) {
@@ -20,33 +25,42 @@ const LocationCard = ({ site, onToggle, isSelected, isLoading }) => {
);
}

// Determine display name (search_name or fallback to location_name)
const displayName = truncateName(
site?.name || site?.search_name?.split(',')[0],
);
// Destructure necessary properties from site
const { name, search_name, country } = site;

// Determine display name (search_name or fallback to name)
const displayName = truncateName(name || search_name?.split(',')[0] || '');

return (
<div
onClick={() => onToggle(site)}
className={`flex justify-between items-center p-3 bg-[#F6F6F7] cursor-pointer border ${
className={`flex justify-between items-center p-3 bg-[#F6F6F7] border ${
isSelected ? 'border-blue-300 ring-2 ring-blue-500' : 'border-gray-200'
} rounded-lg shadow-sm transition-all w-full`}
>
<div className="flex flex-col gap-2">
<h1 className="text-sm font-medium text-gray-900">{displayName}</h1>
<small className="text-xs text-gray-500">
{site.country || 'Unknown Country'}
</small>
<div className="flex items-center gap-2">
<LocationIcon
width={20}
height={20}
fill={isSelected ? '#3B82F6' : '#9EA3AA'}
/>
<div className="flex flex-col">
<h3 className="text-sm font-medium text-gray-900">{displayName}</h3>
<small className="text-xs text-gray-500">
{country || 'Unknown Country'}
</small>
</div>
</div>
<div>
<input
type="checkbox"
id={`checkbox-${site._id || 'unknown'}`}
checked={isSelected}
onChange={(e) => {
e.stopPropagation();
onToggle(site);
}}
className="w-4 h-4 text-blue-600 bg-white cursor-pointer border-blue-300 rounded focus:ring-blue-500"
aria-label={`Select ${displayName}`}
/>
</div>
</div>
Original file line number Diff line number Diff line change
@@ -37,6 +37,7 @@ const AddLocations = ({ onClose }) => {

// Local state management
const [selectedSites, setSelectedSites] = useState([]);
const [sidebarSites, setSidebarSites] = useState([]);
const [clearSelected, setClearSelected] = useState(false);
const [error, setError] = useState('');
const [submitLoading, setSubmitLoading] = useState(false);
@@ -62,13 +63,15 @@ const AddLocations = ({ onClose }) => {

/**
* Populate selectedSites based on selectedSiteIds and fetched sitesSummaryData.
* Also initializes sidebarSites with the initially selected sites.
*/
useEffect(() => {
if (sitesSummaryData && selectedSiteIds.length) {
const initialSelectedSites = sitesSummaryData.filter((site) =>
selectedSiteIds.includes(site._id),
);
setSelectedSites(initialSelectedSites);
setSidebarSites(initialSelectedSites);
}
}, [sitesSummaryData, selectedSiteIds]);

@@ -84,16 +87,32 @@ const AddLocations = ({ onClose }) => {

/**
* Toggles the selection of a site.
* @param {Object} site - The site to toggle.
* Adds to selectedSites and sidebarSites if selected.
* Removes from selectedSites but retains in sidebarSites if unselected.
*/
const handleToggleSite = useCallback((site) => {
setSelectedSites((prev) => {
const isSelected = prev.some((s) => s._id === site._id);
return isSelected
? prev.filter((s) => s._id !== site._id)
: [...prev, site];
});
}, []);
const handleToggleSite = useCallback(
(site) => {
setSelectedSites((prev) => {
const isSelected = prev.some((s) => s._id === site._id);
if (isSelected) {
// Remove from selectedSites
return prev.filter((s) => s._id !== site._id);
} else {
// Add to selectedSites
return [...prev, site];
}
});

setSidebarSites((prev) => {
const alreadyInSidebar = prev.some((s) => s._id === site._id);
if (!alreadyInSidebar) {
return [...prev, site];
}
return prev;
});
},
[setSelectedSites, setSidebarSites],
);

/**
* Handles the submission of selected sites.
@@ -149,9 +168,11 @@ const AddLocations = ({ onClose }) => {
}, [selectedSites, userID, dispatch, onClose]);

/**
* Generates the content for the selected sites panel.
* Generates the content for the sidebar.
* Displays only the sites that have been selected at least once.
* Each card reflects its current selection status.
*/
const selectedSitesContent = useMemo(() => {
const sidebarSitesContent = useMemo(() => {
if (loading) {
return (
<div className="space-y-4">
@@ -168,7 +189,7 @@ const AddLocations = ({ onClose }) => {
);
}

if (selectedSites.length === 0) {
if (sidebarSites.length === 0) {
return (
<div className="text-gray-500 w-full text-sm h-full flex flex-col justify-center items-center">
<span className="p-2 rounded-full bg-[#F6F6F7] mb-2">
@@ -179,22 +200,22 @@ const AddLocations = ({ onClose }) => {
);
}

return selectedSites.map((site) => (
return sidebarSites.map((site) => (
<LocationCard
key={site._id}
site={site}
onToggle={handleToggleSite}
isLoading={loading}
isSelected={true}
isSelected={selectedSites.some((s) => s._id === site._id)}
/>
));
}, [selectedSites, handleToggleSite, loading]);
}, [sidebarSites, selectedSites, handleToggleSite, loading]);

return (
<>
{/* Selected Sites Sidebar */}
<div className="w-[280px] h-[658px] overflow-y-auto border-r relative space-y-3 px-4 pt-5 pb-14">
{selectedSitesContent}
{sidebarSitesContent}
</div>

{/* Main Content Area */}