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 #2399

Merged
merged 5 commits into from
Jan 23, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
13 changes: 6 additions & 7 deletions k8s/platform/values-stage.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ replicaCount: 1
image:
repository: eu.gcr.io/airqo-250220/airqo-stage-next-platform
pullPolicy: Always
tag: stage-33049363-1737029974
tag: stage-87a3d931-1737641477
imagePullSecrets: []
nameOverride: ''
fullnameOverride: ''
Expand All @@ -24,24 +24,23 @@ resources:
requests:
cpu: 20m
memory: 150Mi

autoscaling:
minReplicas: 1
maxReplicas: 3
targetCPUUtilizationPercentage: 80
nodeSelector:
nodeSelector:
role: control-plane
tolerations: []
affinity:
nodeAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- preference:
matchExpressions:
- preference:
matchExpressions:
- key: role
operator: In
values:
- control-plane
weight: 1
- control-plane
weight: 1
app:
name: airqo-stage-next-platform
label: sta-next-platform
Expand Down
8 changes: 6 additions & 2 deletions platform/src/common/components/AQNumberCard/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,9 @@ const SiteCard = React.memo(
<button
className="w-full h-auto"
onClick={() => onOpenModal('inSights', [], site)}
aria-label={`View detailed insights for ${site.name || 'this location'}`}
aria-label={`View detailed insights for ${
site.name || 'this location'
}`}
>
<div className="w-full flex flex-col justify-between bg-white border border-gray-200 rounded-xl px-6 py-5 h-[220px] shadow-sm hover:shadow-md transition-shadow duration-200 ease-in-out cursor-pointer">
{/* Header Section */}
Expand Down Expand Up @@ -271,7 +273,8 @@ const AQNumberCard = ({ className = '' }) => {
const { width: windowWidth } = useWindowSize();
const [loading, setLoading] = useState(true);

const { id: activeGroupId } = useGetActiveGroup();
const { id: activeGroupId, loading: isFetchingActiveGroup } =
useGetActiveGroup();

const pollutantType = useSelector((state) => state.chart.pollutionType);
const preferences = useSelector(
Expand All @@ -289,6 +292,7 @@ const AQNumberCard = ({ className = '' }) => {
);

useEffect(() => {
if (isFetchingActiveGroup) return;
const controller = new AbortController();

const fetchData = async () => {
Expand Down
18 changes: 13 additions & 5 deletions platform/src/common/components/Dropdowns/OrganizationDropdown.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { useGetActiveGroup } from '@/core/hooks/useGetActiveGroupId';

const cleanGroupName = (name) => {
if (!name) return '';
return name.replace(/-/g, ' ').toUpperCase();
return name.replace(/[-_]/g, ' ').toUpperCase();
};

const OrganizationDropdown = () => {
Expand All @@ -25,6 +25,7 @@ const OrganizationDropdown = () => {
title: activeGroupTitle,
groupList,
userID,
loading: isFetchingActiveGroup,
} = useGetActiveGroup();

const isCollapsed = useSelector((state) => state?.sidebar?.isCollapsed);
Expand All @@ -37,7 +38,12 @@ const OrganizationDropdown = () => {

// Initialize active group if missing
useEffect(() => {
if (!activeGroupId && activeGroups.length > 0) {
if (isFetchingActiveGroup) return;
const storedGroup = localStorage.getItem('activeGroup');
if (storedGroup) {
const defaultGroup = JSON.parse(storedGroup);
dispatch(setOrganizationName(defaultGroup.grp_title));
} else if (!activeGroupId && activeGroups.length > 0) {
const defaultGroup = activeGroups[0];
localStorage.setItem('activeGroup', JSON.stringify(defaultGroup));
dispatch(setOrganizationName(defaultGroup.grp_title));
Expand Down Expand Up @@ -111,7 +117,7 @@ const OrganizationDropdown = () => {
{!isCollapsed && (
<div
className="text-sm font-medium leading-tight truncate max-w-[200px]"
title={activeGroupTitle}
title={cleanGroupName(activeGroupTitle)}
>
{cleanGroupName(activeGroupTitle)}
</div>
Expand Down Expand Up @@ -141,9 +147,11 @@ const OrganizationDropdown = () => {
</div>
<div
className="text-sm font-medium truncate max-w-[150px]"
title={group.grp_title}
title={cleanGroupName(group.grp_title)}
>
{cleanGroupName(group.grp_title)}
{cleanGroupName(group.grp_title).length > 14
? `${cleanGroupName(group.grp_title).substring(0, 15)}...`
: cleanGroupName(group.grp_title)}
</div>
</div>
{loading && selectedGroupId === group._id ? (
Expand Down
54 changes: 40 additions & 14 deletions platform/src/core/hooks/useGetActiveGroupId.jsx
Original file line number Diff line number Diff line change
@@ -1,59 +1,85 @@
import { useEffect, useMemo, useState } from 'react';
import { useSelector } from 'react-redux';
import { useMemo } from 'react';

export function useGetActiveGroup() {
const [loading, setLoading] = useState(true);
const userInfo = useSelector((state) => state?.login?.userInfo);
const chartData = useSelector((state) => state.chart);

// Safely parse activeGroup from local storage
const activeGroup = useMemo(() => {
const activeGroupFromStorage = useMemo(() => {
try {
return JSON.parse(localStorage.getItem('activeGroup'));
return JSON.parse(localStorage.getItem('activeGroup') || 'null');
} catch (error) {
console.error('Error parsing activeGroup from local storage:', error);
return null;
}
}, []);

// Ensure userInfo and groups exist
useEffect(() => {
setLoading(false);
}, [userInfo, activeGroupFromStorage]);

// If no userInfo or groups, return stored or default values
if (!userInfo || !userInfo.groups || !chartData?.organizationName) {
return {
id: activeGroup?.id || null,
title: activeGroup?.grp_title || null,
loading,
id: activeGroupFromStorage?.id || null,
title: activeGroupFromStorage?.grp_title || null,
userID: userInfo?.id || null,
groupList: userInfo?.groups || [],
};
}

// Find the group that matches the chartData.organizationName
// Prioritize stored group if it exists in user's groups
if (activeGroupFromStorage) {
const storedGroupInUserGroups = userInfo.groups.find(
(group) => group._id === activeGroupFromStorage._id,
);

if (storedGroupInUserGroups) {
return {
loading,
id: storedGroupInUserGroups._id,
title: storedGroupInUserGroups.grp_title,
userID: userInfo._id,
groupList: userInfo.groups,
};
}
}

// Find group matching chart organization name
const matchingGroup = userInfo.groups.find(
(group) => group.grp_title === chartData.organizationName,
);

// Return the matching group, activeGroup, or fallback values
if (matchingGroup) {
return {
loading,
id: matchingGroup._id,
title: matchingGroup.grp_title,
userID: userInfo._id,
groupList: userInfo.groups,
};
}

if (activeGroup) {
// Fallback to first group if available
if (userInfo.groups.length > 0) {
const firstGroup = userInfo.groups[0];
return {
id: activeGroup._id,
title: activeGroup.grp_title,
loading,
id: firstGroup._id,
title: firstGroup.grp_title,
userID: userInfo._id,
groupList: userInfo.groups,
};
}

// Fallback when no matching group or activeGroup is found
// Final fallback
return {
loading,
id: null,
title: null,
userID: userInfo._id,
groupList: userInfo.groups,
groupList: [],
};
}
Loading