From f61081b21dc3fc423d81396e997566c8806eb1e7 Mon Sep 17 00:00:00 2001
From: Mohammad Torkashvand <mohammad.torkashvand@geant.org>
Date: Tue, 4 Jun 2024 16:23:45 +0200
Subject: [PATCH] Refactor data fetching and state management in MapsPage

- Move data fetching logic from NetworkMap to MapsPage
- Handle loading and error states in MapsPage
- Remove loading and error handling from NetworkMap
- Ensure separation of concerns between data fetching and presentation

This refactor simplifies NetworkMap by focusing it solely on rendering the network map, while MapsPage handles data fetching, session management, and error handling.
---
 components/NetworkMap/NetworkMap.tsx | 16 +-----
 contexts/GsoConfigContext.tsx        |  1 +
 pages/api/runtime-config.ts          |  2 +
 pages/maps/index.tsx                 | 84 ++++++++++++++++++----------
 4 files changed, 58 insertions(+), 45 deletions(-)

diff --git a/components/NetworkMap/NetworkMap.tsx b/components/NetworkMap/NetworkMap.tsx
index 842f978..bd48188 100644
--- a/components/NetworkMap/NetworkMap.tsx
+++ b/components/NetworkMap/NetworkMap.tsx
@@ -1,11 +1,5 @@
 import { NetworkTopologyData } from '@/types/types';
-import {
-  EuiToolTip,
-  EuiSelect,
-  EuiLoadingSpinner,
-  EuiPanel,
-  EuiFormRow,
-} from '@elastic/eui';
+import { EuiToolTip, EuiSelect, EuiPanel, EuiFormRow } from '@elastic/eui';
 import cytoscape, { ElementDefinition, Core } from 'cytoscape';
 import fcose from 'cytoscape-fcose';
 import React, { useEffect, useState, useRef } from 'react';
@@ -26,7 +20,6 @@ interface FcoseLayoutOptions {
 const NetworkMap: React.FC<NetworkMapProps> = ({ data }) => {
   const [elements, setElements] = useState<ElementDefinition[]>([]);
   const [labelType, setLabelType] = useState('iptrunkIsisMetric');
-  const [loading, setLoading] = useState(true);
   const [tooltipContent, setTooltipContent] = useState<JSX.Element | null>(
     null,
   );
@@ -40,7 +33,6 @@ const NetworkMap: React.FC<NetworkMapProps> = ({ data }) => {
     if (data) {
       const transformedElements = transformDataToElements(data);
       setElements(transformedElements);
-      setLoading(false);
     }
   }, [data]);
 
@@ -295,11 +287,7 @@ const NetworkMap: React.FC<NetworkMapProps> = ({ data }) => {
 
   return (
     <EuiPanel>
-      {loading ? (
-        <EuiLoadingSpinner size="xl" />
-      ) : (
-        <div id="container" style={{ height: '80vh', marginTop: '20px' }}></div>
-      )}
+      <div id="container" style={{ height: '80vh', marginTop: '20px' }}></div>
       {tooltipContent && tooltipPosition && (
         <div
           style={{
diff --git a/contexts/GsoConfigContext.tsx b/contexts/GsoConfigContext.tsx
index c2dee34..0196a72 100644
--- a/contexts/GsoConfigContext.tsx
+++ b/contexts/GsoConfigContext.tsx
@@ -3,6 +3,7 @@ import React, { createContext, useContext, ReactNode } from 'react';
 export interface GsoConfig {
   opaPublicBundleUrl: string;
   oidcClientId: string;
+  networkTopologyApiUrl: string;
 }
 
 const GsoConfigContext = createContext<GsoConfig | undefined>(undefined);
diff --git a/pages/api/runtime-config.ts b/pages/api/runtime-config.ts
index ca8e6c9..00df944 100644
--- a/pages/api/runtime-config.ts
+++ b/pages/api/runtime-config.ts
@@ -3,6 +3,7 @@ import { NextApiRequest, NextApiResponse } from 'next';
 interface RuntimeConfig {
   opaPublicBundleUrl: string;
   oidcClientId: string;
+  networkTopologyApiUrl: string;
 }
 
 export default async function handler(
@@ -12,6 +13,7 @@ export default async function handler(
   const config: RuntimeConfig = {
     opaPublicBundleUrl: process.env.OPA_PUBLIC_BUNDLE_URL || '',
     oidcClientId: process.env.NEXTAUTH_CLIENT_ID || '',
+    networkTopologyApiUrl: process.env.NETWORK_TOPOLOGY_API_URL || '',
   };
 
   res.status(200).json(config);
diff --git a/pages/maps/index.tsx b/pages/maps/index.tsx
index 958b212..e51b74a 100644
--- a/pages/maps/index.tsx
+++ b/pages/maps/index.tsx
@@ -1,45 +1,67 @@
 import NetworkMap from '@/components/NetworkMap/NetworkMap';
+import { useGsoConfig } from '@/contexts/GsoConfigContext';
 import { GSOPolicyResource } from '@/types/policyResources';
 import { NetworkTopologyData } from '@/types/types';
-import { WfoPolicyRenderPageFallback } from '@orchestrator-ui/orchestrator-ui-components';
+import { EuiLoadingSpinner, EuiText } from '@elastic/eui';
+import {
+  useWfoSession,
+  WfoPolicyRenderPageFallback,
+} from '@orchestrator-ui/orchestrator-ui-components';
 import axios from 'axios';
-import { NextPage, GetServerSideProps } from 'next';
-import React from 'react';
+import React, { useEffect, useState } from 'react';
 
-interface MapsProps {
-  networkTopologyData: NetworkTopologyData;
-}
+const MapsPage: React.FC = () => {
+  const [networkTopologyData, setNetworkTopologyData] =
+    useState<NetworkTopologyData | null>(null);
+  const [loading, setLoading] = useState<boolean>(true);
+  const [error, setError] = useState<boolean>(false);
+  const TIMEOUT = 5000;
+  const config = useGsoConfig();
+  const { session } = useWfoSession(); // Use the hook here
 
-const AXIOS_TIMEOUT = 10000; // 10 seconds
+  useEffect(() => {
+    const fetchData = async () => {
+      try {
+        const requestHeaders = {
+          Authorization: session ? `Bearer ${session.accessToken}` : '',
+        };
+        const response = await axios.get<NetworkTopologyData>(
+          config.networkTopologyApiUrl!,
+          {
+            timeout: TIMEOUT,
+            headers: requestHeaders,
+          },
+        );
+        setNetworkTopologyData(response.data);
+        setLoading(false);
+      } catch (error) {
+        console.error('Failed to fetch data', error);
+        setError(true);
+        setLoading(false);
+      }
+    };
+
+    if (session) {
+      fetchData();
+    } else {
+      setLoading(false);
+      setError(true);
+    }
+  }, [session]);
 
-const MapsPage: NextPage<MapsProps> = ({ networkTopologyData }) => {
   return (
     <WfoPolicyRenderPageFallback resource={GSOPolicyResource.NAVIGATION_MAPS}>
-      <NetworkMap data={networkTopologyData} />
+      {loading ? (
+        <EuiLoadingSpinner size="xl" />
+      ) : error ? (
+        <EuiText color="danger">
+          Failed to load data. Please try again later.
+        </EuiText>
+      ) : (
+        <NetworkMap data={networkTopologyData} />
+      )}
     </WfoPolicyRenderPageFallback>
   );
 };
 
-export const getServerSideProps: GetServerSideProps = async () => {
-  try {
-    const response = await axios.get(process.env.NETWORK_TOPOLOGY_API_URL!, {
-      timeout: AXIOS_TIMEOUT,
-    });
-    const networkTopologyData: NetworkTopologyData = response.data;
-
-    return {
-      props: {
-        networkTopologyData,
-      },
-    };
-  } catch (error) {
-    console.error('Failed to fetch data', error);
-    return {
-      props: {
-        networkTopologyData: null,
-      },
-    };
-  }
-};
-
 export default MapsPage;
-- 
GitLab