overall updates
This commit is contained in:
@@ -5,11 +5,13 @@ import { Box, Card, CardContent, Grid, Typography } from '@mui/material';
|
||||
|
||||
// ===========================|| HOVER SOCIAL CARD ||=========================== //
|
||||
|
||||
const HoverSocialCard = ({ primary, secondary,
|
||||
percentage,
|
||||
const HoverSocialCard = ({
|
||||
primary,
|
||||
secondary,
|
||||
percentage,
|
||||
// iconPrimary,
|
||||
color
|
||||
}) => {
|
||||
color
|
||||
}) => {
|
||||
// const IconPrimary = iconPrimary;
|
||||
// const primaryIcon = iconPrimary ? <IconPrimary /> : null;
|
||||
|
||||
@@ -20,10 +22,10 @@ const HoverSocialCard = ({ primary, secondary,
|
||||
background: color,
|
||||
position: 'relative',
|
||||
color: '#fff',
|
||||
// '&:hover svg': {
|
||||
// opacity: 1,
|
||||
// transform: 'scale(1.1)'
|
||||
// }
|
||||
'&:hover svg': {
|
||||
opacity: 1,
|
||||
transform: 'scale(1.1)'
|
||||
}
|
||||
}}
|
||||
>
|
||||
<CardContent>
|
||||
@@ -33,19 +35,18 @@ const HoverSocialCard = ({ primary, secondary,
|
||||
right: 15,
|
||||
top: 25,
|
||||
color: '#fff',
|
||||
// '& svg': {
|
||||
// width: 36,
|
||||
// height: 36,
|
||||
// opacity: 0.5,
|
||||
// transition: 'all .3s ease-in-out'
|
||||
// }
|
||||
'& svg': {
|
||||
width: 36,
|
||||
height: 36,
|
||||
opacity: 0.5,
|
||||
transition: 'all .3s ease-in-out'
|
||||
}
|
||||
}}
|
||||
>
|
||||
<Typography variant="h2" color="inherit">
|
||||
{/* {percentage.toString()} % */}
|
||||
{(percentage)? `${percentage.toString()} %`:''}
|
||||
|
||||
</Typography>
|
||||
{/* {percentage.toString()} % */}
|
||||
{percentage ? `${percentage.toString()} %` : ''}
|
||||
</Typography>
|
||||
{/* {primaryIcon} */}
|
||||
</Box>
|
||||
<Grid container spacing={0}>
|
||||
@@ -69,7 +70,7 @@ HoverSocialCard.propTypes = {
|
||||
primary: PropTypes.string,
|
||||
secondary: PropTypes.string,
|
||||
// iconPrimary: PropTypes.object,
|
||||
percentage:PropTypes.string,
|
||||
percentage: PropTypes.string,
|
||||
color: PropTypes.string
|
||||
};
|
||||
|
||||
|
||||
55
src/components/nearle_components/DateFilterDialog.js
Normal file
55
src/components/nearle_components/DateFilterDialog.js
Normal file
@@ -0,0 +1,55 @@
|
||||
import { Dialog, DialogTitle, DialogContent, Typography, Stack, Button, DialogActions, Paper } from '@mui/material';
|
||||
|
||||
import { DateRangePicker } from 'mui-daterange-picker';
|
||||
import dayjs from 'dayjs';
|
||||
|
||||
import { addDays, addWeeks, addMonths, startOfWeek, endOfWeek, startOfMonth, endOfMonth } from 'date-fns';
|
||||
|
||||
export default function DateFilterDialog({ open, onClose, onApply }) {
|
||||
const definedRanges = [
|
||||
{ label: 'Today', startDate: new Date(), endDate: new Date() },
|
||||
{ label: 'Yesterday', startDate: addDays(new Date(), -1), endDate: addDays(new Date(), -1) },
|
||||
{ label: 'Tomorrow', startDate: addDays(new Date(), 1), endDate: addDays(new Date(), 1) },
|
||||
{ label: 'This Week', startDate: startOfWeek(new Date()), endDate: endOfWeek(new Date()) },
|
||||
{ label: 'Last Week', startDate: startOfWeek(addWeeks(new Date(), -1)), endDate: endOfWeek(addWeeks(new Date(), -1)) },
|
||||
{ label: 'Last 7 Days', startDate: addDays(new Date(), -7), endDate: new Date() },
|
||||
{ label: 'This Month', startDate: startOfMonth(new Date()), endDate: endOfMonth(new Date()) },
|
||||
{ label: 'Last Month', startDate: startOfMonth(addMonths(new Date(), -1)), endDate: endOfMonth(addMonths(new Date(), -1)) }
|
||||
];
|
||||
|
||||
const handleSelect = (range) => {
|
||||
if (!range?.startDate || !range?.endDate) return;
|
||||
|
||||
onApply({
|
||||
startDate: dayjs(range.startDate).format('YYYY-MM-DD'),
|
||||
endDate: dayjs(range.endDate).format('YYYY-MM-DD'),
|
||||
label: range.label || ''
|
||||
});
|
||||
|
||||
onClose();
|
||||
};
|
||||
|
||||
return (
|
||||
<Dialog open={open} onClose={onClose} fullWidth maxWidth="sm">
|
||||
<DialogTitle disableTypography>
|
||||
<Stack display="flex" flexDirection="row" justifyContent="space-between" alignItems="center" sx={{ width: '100%' }}>
|
||||
<Typography variant="h4">Select Date Range</Typography>
|
||||
</Stack>
|
||||
</DialogTitle>
|
||||
<DialogContent
|
||||
sx={{
|
||||
'& .MuiPaper-root': {
|
||||
boxShadow: 'none !important'
|
||||
}
|
||||
}}
|
||||
>
|
||||
<DateRangePicker open={open} toggle={onClose} definedRanges={definedRanges} onChange={handleSelect} closeOnClickOutside={false} />
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button variant="contained" onClick={onClose} sx={{ cursor: 'pointer' }}>
|
||||
Close
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
);
|
||||
}
|
||||
58
src/components/nearle_components/SearchBar.js
Normal file
58
src/components/nearle_components/SearchBar.js
Normal file
@@ -0,0 +1,58 @@
|
||||
// SearchBar.jsx
|
||||
import React, { useEffect, useRef } from 'react';
|
||||
import { FormControl, OutlinedInput, InputAdornment, IconButton, useTheme } from '@mui/material';
|
||||
import SearchOutlined from '@mui/icons-material/SearchOutlined';
|
||||
import ClearIcon from '@mui/icons-material/Clear';
|
||||
|
||||
const SearchBar = ({ value, onChange, sx, placeholder = 'Search (Ctrl + K)' }) => {
|
||||
const theme = useTheme();
|
||||
const inputRef = useRef(null);
|
||||
|
||||
/* ============================================= || handleKeyPress (CTRL + K) and ESC ||============================================= */
|
||||
useEffect(() => {
|
||||
const handleKeyPress = (event) => {
|
||||
// Focus input with CTRL + K / CMD + K
|
||||
if (event.key === 'k' && (event.metaKey || event.ctrlKey)) {
|
||||
event.preventDefault();
|
||||
inputRef.current?.focus();
|
||||
}
|
||||
|
||||
// ESC removes focus
|
||||
if (event.key === 'Escape' && document.activeElement === inputRef.current) {
|
||||
inputRef.current.blur();
|
||||
}
|
||||
};
|
||||
|
||||
document.addEventListener('keydown', handleKeyPress);
|
||||
return () => document.removeEventListener('keydown', handleKeyPress);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<FormControl fullWidth sx={{}}>
|
||||
<OutlinedInput
|
||||
inputRef={inputRef}
|
||||
placeholder={placeholder}
|
||||
sx={{
|
||||
borderRadius: 0,
|
||||
...sx
|
||||
}}
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
autoComplete="off"
|
||||
size="large"
|
||||
startAdornment={
|
||||
<InputAdornment position="start" sx={{ mr: -0.5, color: theme.palette.primary.main }}>
|
||||
<SearchOutlined />
|
||||
</InputAdornment>
|
||||
}
|
||||
endAdornment={
|
||||
<IconButton sx={{ visibility: value ? 'visible' : 'hidden' }} onClick={() => onChange({ target: { value: '' } })}>
|
||||
<ClearIcon style={{ fontSize: 'large', color: theme.palette.primary.main }} />
|
||||
</IconButton>
|
||||
}
|
||||
/>
|
||||
</FormControl>
|
||||
);
|
||||
};
|
||||
|
||||
export default SearchBar;
|
||||
96
src/components/nearle_components/updateNetworkStatus.js
Normal file
96
src/components/nearle_components/updateNetworkStatus.js
Normal file
@@ -0,0 +1,96 @@
|
||||
import { useEffect, useState, useRef } from 'react';
|
||||
import { useTheme } from '@mui/material/styles';
|
||||
import WifiOffIcon from '@mui/icons-material/WifiOff';
|
||||
import WifiIcon from '@mui/icons-material/Wifi';
|
||||
|
||||
const NOTIFICATION_STYLE = {
|
||||
position: 'fixed',
|
||||
top: '10px', // Keep top spacing
|
||||
left: '50%', // Center horizontally
|
||||
transform: 'translateX(-50%)', // Offset to truly center
|
||||
padding: '12px 40px',
|
||||
borderRadius: '8px',
|
||||
color: 'white',
|
||||
fontWeight: '500',
|
||||
fontSize: '14px',
|
||||
boxShadow: '0 4px 12px rgba(0, 0, 0, 0.15)',
|
||||
zIndex: 9999,
|
||||
maxWidth: '90%',
|
||||
minWidth: 'auto',
|
||||
textAlign: 'center'
|
||||
};
|
||||
|
||||
const InternetStatus = () => {
|
||||
const theme = useTheme();
|
||||
const [isOnline, setIsOnline] = useState(navigator.onLine);
|
||||
const [showBackOnline, setShowBackOnline] = useState(false);
|
||||
const wasOffline = useRef(!navigator.onLine);
|
||||
|
||||
useEffect(() => {
|
||||
const handleNetworkChange = () => {
|
||||
const online = navigator.onLine;
|
||||
setIsOnline(online);
|
||||
|
||||
if (online && wasOffline.current) {
|
||||
console.log('✅ Back online');
|
||||
setShowBackOnline(true);
|
||||
wasOffline.current = false;
|
||||
// window.location.reload();
|
||||
|
||||
setTimeout(() => {
|
||||
setShowBackOnline(false);
|
||||
}, 2000);
|
||||
}
|
||||
|
||||
if (!online) {
|
||||
console.log('❌ No internet connection');
|
||||
wasOffline.current = true;
|
||||
setShowBackOnline(false);
|
||||
}
|
||||
};
|
||||
|
||||
window.addEventListener('online', handleNetworkChange);
|
||||
window.addEventListener('offline', handleNetworkChange);
|
||||
|
||||
return () => {
|
||||
window.removeEventListener('online', handleNetworkChange);
|
||||
window.removeEventListener('offline', handleNetworkChange);
|
||||
};
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<>
|
||||
{!isOnline && (
|
||||
<div
|
||||
style={{
|
||||
...NOTIFICATION_STYLE,
|
||||
backgroundColor: theme.palette.error.main,
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
gap: '10px'
|
||||
}}
|
||||
>
|
||||
<WifiOffIcon style={{ color: '#fff' }} />
|
||||
No Internet Connection
|
||||
</div>
|
||||
)}
|
||||
|
||||
{showBackOnline && (
|
||||
<div
|
||||
style={{
|
||||
...NOTIFICATION_STYLE,
|
||||
backgroundColor: theme.palette.success.main,
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
gap: '10px'
|
||||
}}
|
||||
>
|
||||
<WifiIcon style={{ color: '#fff' }} />
|
||||
Back Online
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default InternetStatus;
|
||||
15
src/components/nearle_components/useDebounce.js
Normal file
15
src/components/nearle_components/useDebounce.js
Normal file
@@ -0,0 +1,15 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
|
||||
export const useDebounce = (value, delay = 500) => {
|
||||
const [debouncedValue, setDebouncedValue] = useState(value);
|
||||
|
||||
useEffect(() => {
|
||||
const handler = setTimeout(() => {
|
||||
setDebouncedValue(value);
|
||||
}, delay);
|
||||
|
||||
return () => clearTimeout(handler); // cleanup on every value change
|
||||
}, [value, delay]);
|
||||
|
||||
return debouncedValue;
|
||||
};
|
||||
26
src/components/nearle_components/useHotkeyFocus.js
Normal file
26
src/components/nearle_components/useHotkeyFocus.js
Normal file
@@ -0,0 +1,26 @@
|
||||
import { useEffect } from 'react';
|
||||
|
||||
export const useHotkeyFocus = (ref, hotkey = 'k') => {
|
||||
useEffect(() => {
|
||||
if (!ref?.current) return;
|
||||
|
||||
const handleKeyPress = (event) => {
|
||||
const isHotkey = event.key.toLowerCase() === hotkey.toLowerCase();
|
||||
|
||||
// CTRL + Hotkey
|
||||
if (isHotkey && (event.metaKey || event.ctrlKey)) {
|
||||
event.preventDefault();
|
||||
ref.current?.focus();
|
||||
}
|
||||
|
||||
// ESC to blur
|
||||
if (event.key === 'Escape' && document.activeElement === ref.current) {
|
||||
ref.current.blur();
|
||||
}
|
||||
};
|
||||
|
||||
document.addEventListener('keydown', handleKeyPress);
|
||||
|
||||
return () => document.removeEventListener('keydown', handleKeyPress);
|
||||
}, [ref, hotkey]);
|
||||
};
|
||||
Reference in New Issue
Block a user