Skip to content

Commit

Permalink
Moved weather widget to separate component
Browse files Browse the repository at this point in the history
  • Loading branch information
eshwinrio committed Mar 11, 2024
1 parent 84d1143 commit d04235b
Show file tree
Hide file tree
Showing 3 changed files with 207 additions and 102 deletions.
166 changes: 64 additions & 102 deletions hr-panel/src/Home.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,130 +11,92 @@ import Grid2 from '@mui/material/Unstable_Grid2/Grid2';
import { Link, LoaderFunction, useLoaderData } from 'react-router-dom';
import DashCard from './components/DashCard';
import ListEmployee from './components/ListEmployee';
import WeatherWidget from './components/WeatherWidget';
import { apolloClient } from './lib/apollo';
import { LoadAllUsersQuery } from './lib/gql-codegen/graphql';
import { LOAD_USERS } from './lib/gql-queries';
import { useWhoAmI } from './lib/whoami-provider';
import { useEffect, useMemo, useState } from 'react';
import { fetchWeather } from './lib/fetch-requests';

export default function Home() {
const whoAmI = useWhoAmI();
const data = useLoaderData() as LoadAllUsersQuery;
const [geolocationCoords, setGeoLocationCoords] = useState<GeolocationCoordinates | null>(null);
const [weatherData, setWeatherData] = useState<any>();

useEffect(() => {
navigator.geolocation.getCurrentPosition(
position => {
setGeoLocationCoords(position.coords);
},
error => {
if (error.PERMISSION_DENIED) {
alert("Bro said NO:(")
}
if (error.POSITION_UNAVAILABLE) {
alert("Bro ignored me :(");
}
},
{ enableHighAccuracy: true }
);
}, []);

useEffect(() => {
if (geolocationCoords) {
fetchWeather(geolocationCoords.latitude, geolocationCoords.longitude)
.then(response => response.json())
.then(json => setWeatherData(json))
.catch(error => console.log(error));
}
}, [geolocationCoords]);

return (
<Container>

{/* Greeting text */}
<Typography variant="body1">
Hello {whoAmI?.currentUser?.firstName}!👋
</Typography>
<Toolbar disableGutters>
<Typography variant="body1">
Hello {whoAmI?.currentUser?.firstName}!👋
</Typography>
</Toolbar>

<Grid2 container spacing={2} alignItems="stretch">
<Grid2 container spacing={3} alignItems="stretch">

{/* Section 1 - Greeting 2 and overview */}
<Grid2 container xs={12} sm={6} xl={4}>

<Grid2 container xs={12} sm={6} xl={4} spacing={1}>
<Grid2 xs={12}>
<DashCard elevation={0} sx={{ backgroundColor: '#E9DACFD7', color: '#482880' }}>
<img src={`${process.env['REACT_APP_OPENWEATHERMAP_ICON_API']}/${weatherData ? weatherData.weather[0].icon : '04d'}.png`} alt='weather' />
<Typography variant="h5" fontWeight={600}>{weatherData?.weather[0]?.main}</Typography>
</DashCard>
<WeatherWidget />
</Grid2>
<Grid2 container xs={12}>
{[
{
title: 'Total employees',
icon: <AssignmentIndIcon />,
value: data.users.length,
backgroundColor: "#CAB7EBD7",
color: "#482880"
},
{
title: 'On leave',
icon: <AssignmentIndIcon />,
value: 0,
backgroundColor: "#E9DACFD7",
color: "#482880"
},
{
title: 'New recruits',
icon: <AssignmentIndIcon />,
value: 0,
backgroundColor: "#D0E3CCD7",
color: "#482880"
},
{
title: 'On notice',
icon: <AssignmentIndIcon />,
value: 0,
backgroundColor: "#E9DACF",
color: "#482880"
}
].map((data, index) => (
<Grid2 xs={6} key={index}>
<DashCard elevation={0} sx={{ backgroundColor: data.backgroundColor, color: data.color }}>
<Box sx={{ display: 'flex', flexDirection: 'column', alignItems: 'flex-start' }}>
<IconButton size="small" edge="start" color='inherit'>
{data.icon}
</IconButton>
<Typography variant="caption">{data.title}</Typography>
<Typography variant="h5">{data.value}</Typography>
</Box>
</DashCard>
</Grid2>
))}
</Grid2>

<Grid2 container spacing={1}>

{[
{
title: 'Total employees',
icon: <AssignmentIndIcon />,
value: data.users.length,
backgroundColor: "#CAB7EBD7",
color: "#482880"
},
{
title: 'On leave',
icon: <AssignmentIndIcon />,
value: 0,
backgroundColor: "#E9DACFD7",
color: "#482880"
},
{
title: 'New recruits',
icon: <AssignmentIndIcon />,
value: 0,
backgroundColor: "#D0E3CCD7",
color: "#482880"
},
{
title: 'On notice',
icon: <AssignmentIndIcon />,
value: 0,
backgroundColor: "#E9DACF",
color: "#482880"
}
].map((data, index) => (
<Grid2 xs={6} key={index}>
<DashCard elevation={0} sx={{ backgroundColor: data.backgroundColor, color: data.color }}>
<Box sx={{ display: 'flex', flexDirection: 'column', alignItems: 'flex-start' }}>
<IconButton size="small" edge="start" color='inherit'>
{data.icon}
</IconButton>
<Typography variant="caption">{data.title}</Typography>
<Typography variant="h5">{data.value}</Typography>
</Box>
</DashCard>
</Grid2>
))}
</Grid2>
</Grid2>

<Grid2 container direction='column' alignItems='stretch' spacing={0} xs={12} sm={6} xl={4}>
<Grid2>
<Toolbar disableGutters sx={{ justifyContent: 'space-between' }}>
<Typography variant="h6" fontWeight={600}>Active employees</Typography>
<Grid2 flex={1} xs={12} sm={6} xl={4}>
<Paper variant='outlined' elevation={0} sx={{ height: '100%', overflowY: 'auto' }}>
<Toolbar sx={{ justifyContent: 'space-between' }}>
<Typography>Active</Typography>
<Button size='small' startIcon={<LaunchIcon fontSize='inherit' />} component={Link} to='/employees/list'>View all</Button>
</Toolbar>
</Grid2>

<Grid2 flex={1}>
<Paper variant='outlined' elevation={0} sx={{ height: '100%', overflowY: 'auto' }}>
<ListEmployee
disablePadding dense
listItemProps={{ disableGutters: true, disablePadding: true, divider: true }}
data={data}
sx={{ height: 212, overflowY: 'auto' }}
/>
</Paper>
</Grid2>
<ListEmployee
disablePadding dense
listItemProps={{ disableGutters: true, disablePadding: true, divider: true }}
data={data}
sx={{ height: 273, overflowY: 'auto' }}
/>
</Paper>
</Grid2>
</Grid2 >
</Container>
Expand Down
6 changes: 6 additions & 0 deletions hr-panel/src/components/DashCard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,15 @@ import { Paper, styled } from "@mui/material";

export default styled(Paper)(({ theme }) => ({
backgroundColor: theme.palette.mode === 'dark' ? '#1A2027' : '#fff',
backgroundRepeat: 'no-repeat',
backgroundAttachment: 'fixed',
backgroundSize: 'cover',
backgroundPosition: 'center',
padding: theme.spacing(1),
color: theme.palette.text.secondary,
width: '100%',
maxHeight: theme.spacing(16),
height: '100%',
overflow: 'hidden',
textOverflow: 'ellipsis',
whiteSpace: 'nowrap',
Expand Down
137 changes: 137 additions & 0 deletions hr-panel/src/components/WeatherWidget.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
import { PaperProps } from "@mui/material/Paper";
import Skeleton from "@mui/material/Skeleton";
import Typography from "@mui/material/Typography";
import Grid2 from "@mui/material/Unstable_Grid2/Grid2";
import { alpha } from "@mui/material/styles";
import { FC, useEffect, useState } from "react";
import { fetchWeather } from "../lib/fetch-requests";
import DashCard from "./DashCard";

interface OpenWeatherMapResponse {
coord: {
lon: number;
lat: number;
};
weather: [
{
id: number;
main: string;
description: string;
icon: string;
}
];
base: string;
main: {
temp: number;
feels_like: number;
temp_min: number;
temp_max: number;
pressure: number;
humidity: number;
}
visibility: number;
wind: {
speed: number;
deg: number;
};
clouds: {
all: number;
};
dt: number;
sys: {
type: number;
id: number;
country: string;
sunrise: number;
sunset: number;
};
timezone: number;
id: number;
name: string;
cod: number;
}

interface WeatherWidgetProps extends PaperProps {

}

const WeatherWidget: FC<WeatherWidgetProps> = function ({ children, ...props }) {
const [geolocationPos, setGeoLocationPos] = useState<GeolocationPosition>();
const [weatherData, setWeatherData] = useState<OpenWeatherMapResponse>();
const [loading, setLoading] = useState(true);
const [error, setError] = useState<GeolocationPositionError>();
const [fetchError, setFetchError] = useState<string>();

useEffect(() => {
navigator.geolocation.getCurrentPosition(
position => setGeoLocationPos(position),
error => setError(error),
{ enableHighAccuracy: true }
);
}, []);

useEffect(() => {
if (!geolocationPos) {
setLoading(false);
return;
}
if (geolocationPos) {
fetchWeather(geolocationPos.coords.latitude, geolocationPos.coords.longitude)
.then(response => response.json())
.then(json => setWeatherData(json))
.catch(error => setFetchError(error.message))
.finally(() => setLoading(false));
}
}, [geolocationPos]);

if (!navigator.geolocation || error || fetchError) {
return <></>;
}

if (loading) {
return <Skeleton variant="rectangular" width="100%" height={200} />;
}

if (weatherData) {
return (
<DashCard sx={({ palette }) => ({
backgroundImage: `url(https://source.unsplash.com/random/1600x900?${palette.mode === 'dark' ? 'night' : 'day'},${weatherData.weather[0].description.split(' ').join(',')})`,
backgroundPosition: 'bottom',
color: palette.common.white,
position: 'relative',
'&:before': {
content: '""',
position: 'absolute',
top: 0,
bottom: 0,
right: 0,
left: 0,
backgroundImage: `linear-gradient(45deg, ${alpha(palette.grey[900], 0.7)}, ${alpha(palette.grey[700], 0.1)})`,
},
})}>
<Grid2 container justifyContent='flex-start' alignItems='center' position='inherit'>
<Grid2>
<img
src={`https://openweathermap.org/img/wn/${weatherData.weather[0].icon}@2x.png`}
alt="weather"
width={64} height={64}
/>
</Grid2>
<Grid2>
<Typography variant="h3" fontWeight={600}>
{Math.round(Math.floor((weatherData.main.temp - 273.15) * 100) / 100)}°
</Typography>
</Grid2>
<Grid2 xs={12} sx={{ pl: 8 }}>
<Typography variant="body2" fontWeight={600}>{weatherData.weather[0].main}</Typography>
</Grid2>
</Grid2>
<Typography align="right" fontStyle='italic' fontSize='0.5rem'>Image fetched from <a href="https://unsplash.com/">Unsplash</a></Typography>
</DashCard >
)
} else {
return <></>;
}
}

export default WeatherWidget;

0 comments on commit d04235b

Please sign in to comment.