-
Notifications
You must be signed in to change notification settings - Fork 31
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
[Analytics] Added maintenance banner #2296
Changes from all commits
1e9b10f
d97584a
b84c5de
bdda6b6
5202804
d27cd8e
5b332d0
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
import React from 'react'; | ||
import { IoWarningOutline } from 'react-icons/io5'; | ||
import dayjs from 'dayjs'; | ||
|
||
const MaintenanceBanner = ({ maintenance }) => { | ||
if (!maintenance?.isActive) return null; | ||
|
||
return ( | ||
<div className="bg-yellow-50 border-b border-yellow-200 mb-2"> | ||
<div className="py-3 px-3 sm:px-6 lg:px-8"> | ||
<div className="flex items-center justify-center"> | ||
<div className="flex items-center"> | ||
<span className="flex"> | ||
<IoWarningOutline | ||
className="h-6 w-6 text-yellow-600" | ||
aria-hidden="true" | ||
/> | ||
</span> | ||
<p className="ml-3 font-medium text-yellow-700"> | ||
{maintenance.message} | ||
<span className="ml-2 text-yellow-600"> | ||
(Estimated downtime:{' '} | ||
{dayjs(maintenance.startDate).format('D MMM, YYYY hh:mm A')} -{' '} | ||
{dayjs(maintenance.endDate).format('D MMM, YYYY hh:mm A')}) | ||
</span> | ||
</p> | ||
</div> | ||
</div> | ||
</div> | ||
</div> | ||
); | ||
}; | ||
|
||
export default MaintenanceBanner; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 💡 Codebase verification Add test coverage for MaintenanceBanner component The component is currently used in the Layout component and serves a clear purpose, but lacks test coverage. A test file should be added to ensure the component's reliability, especially since it handles maintenance state display.
🔗 Analysis chainVerify component usage and add tests Let's ensure the component is properly integrated and tested:
🏁 Scripts executedThe following scripts were executed for the analysis: Script: #!/bin/bash
# Search for MaintenanceBanner usage
echo "Searching for MaintenanceBanner usage..."
rg "MaintenanceBanner" --type jsx --type tsx
# Check for existing test file
echo "Checking for test file..."
fd "MaintenanceBanner.test" --type file
Length of output: 264 Script: #!/bin/bash
# Search for MaintenanceBanner usage with correct file extensions
echo "Searching for MaintenanceBanner usage..."
rg "MaintenanceBanner" -g "*.js" -g "*.jsx" -g "*.ts" -g "*.tsx"
# Check for test files in a more comprehensive way
echo "Checking for test files..."
fd -e test.js -e test.jsx -e spec.js -e spec.jsx "MaintenanceBanner"
# Look for the component definition to understand its location
echo "Finding component definition..."
rg "class MaintenanceBanner|function MaintenanceBanner|const MaintenanceBanner" -g "*.js" -g "*.jsx" -g "*.ts" -g "*.tsx"
Length of output: 1001 |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -12,6 +12,7 @@ import { | |
USER_CHECKLISTS_URL, | ||
FORGOT_PWD_URL, | ||
RESET_PWD_URL, | ||
MAINTENANCE_STATUS_URL, | ||
} from '../urls/authentication'; | ||
import axios from 'axios'; | ||
import createAxiosInstance from './axiosConfig'; | ||
|
@@ -221,3 +222,13 @@ export const updateGroupDetailsApi = async (groupID, data) => { | |
.put(`${GROUPS_URL}/${groupID}`, data) | ||
.then((response) => response.data); | ||
}; | ||
|
||
export const getMaintenanceStatus = async () => { | ||
try { | ||
const response = await createAxiosInstance().get(MAINTENANCE_STATUS_URL); | ||
return response.data; | ||
} catch (error) { | ||
console.error('Error fetching maintenance status:', error); | ||
throw error; | ||
} | ||
}; | ||
Comment on lines
+226
to
+234
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Enhance error handling and reliability While the basic implementation is functional, consider these improvements:
export const getMaintenanceStatus = async () => {
try {
- const response = await createAxiosInstance().get(MAINTENANCE_STATUS_URL);
+ const response = await createAxiosInstance().get<MaintenanceStatusResponse>(
+ MAINTENANCE_STATUS_URL,
+ {
+ retry: 3,
+ retryDelay: 1000,
+ }
+ );
return response.data;
} catch (error) {
- console.error('Error fetching maintenance status:', error);
+ if (axios.isAxiosError(error)) {
+ if (error.response?.status === 404) {
+ console.error('Maintenance status endpoint not found');
+ } else if (error.response?.status >= 500) {
+ console.error('Server error while fetching maintenance status');
+ } else {
+ console.error('Network error:', error.message);
+ }
+ }
throw error;
}
}; Also, consider defining a type for the maintenance status response: interface MaintenanceStatusResponse {
active: boolean;
message?: string;
startTime?: string;
endTime?: string;
} |
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,38 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import { useState, useEffect } from 'react'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import { getMaintenanceStatus } from '../apis/Account'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const POLLING_INTERVAL = 5 * 60 * 1000; // 5 minutes | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const useMaintenanceStatus = () => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const [maintenance, setMaintenance] = useState(null); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const [loading, setLoading] = useState(true); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const [error, setError] = useState(null); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const fetchMaintenanceStatus = async () => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
try { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const response = await getMaintenanceStatus(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if (response.success && response.maintenance?.length > 0) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
setMaintenance(response.maintenance[0]); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} else { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
setMaintenance(null); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
setError(null); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} catch (err) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
setError(err); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
console.error('Error fetching maintenance status:', err); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} finally { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
setLoading(false); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+11
to
+26
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Enhance error handling and add type validation The error handling could be more robust:
Consider this enhanced implementation: const fetchMaintenanceStatus = async () => {
try {
const response = await getMaintenanceStatus();
+ // Validate response structure
+ if (!response || typeof response.success !== 'boolean') {
+ throw new Error('Invalid response format');
+ }
if (response.success && response.maintenance?.length > 0) {
+ // Validate maintenance object structure
+ const maintenance = response.maintenance[0];
+ if (!maintenance.startDate || !maintenance.endDate || typeof maintenance.isActive !== 'boolean') {
+ throw new Error('Invalid maintenance data format');
+ }
setMaintenance(response.maintenance[0]);
} else {
setMaintenance(null);
}
setError(null);
} catch (err) {
setError(err);
- console.error('Error fetching maintenance status:', err);
+ // Use a proper logging service in production
+ if (process.env.NODE_ENV === 'development') {
+ console.error('Error fetching maintenance status:', err);
+ }
} finally {
setLoading(false);
}
}; 📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
useEffect(() => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
fetchMaintenanceStatus(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const interval = setInterval(fetchMaintenanceStatus, POLLING_INTERVAL); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return () => clearInterval(interval); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}, []); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+28
to
+33
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Add cleanup for in-flight requests Use AbortController to clean up pending requests when the component unmounts. useEffect(() => {
+ const abortController = new AbortController();
+
- fetchMaintenanceStatus();
+ const fetchWithAbort = async () => {
+ try {
+ await fetchMaintenanceStatus({ signal: abortController.signal });
+ } catch (error) {
+ if (!error.name === 'AbortError') {
+ throw error;
+ }
+ }
+ };
+
+ fetchWithAbort();
const interval = setInterval(fetchMaintenanceStatus, POLLING_INTERVAL);
- return () => clearInterval(interval);
+ return () => {
+ clearInterval(interval);
+ abortController.abort();
+ };
}, []);
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return { maintenance, loading, error }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
export default useMaintenanceStatus; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Add PropTypes and handle invalid maintenance object
The component lacks prop type validation and could crash with invalid date values.
📝 Committable suggestion