Started on shifts page
parent
0c8f33c486
commit
1890d022ff
@ -0,0 +1,29 @@
|
|||||||
|
{
|
||||||
|
"updated": "2021-07-15T22:29:19.164Z",
|
||||||
|
"parsed": [
|
||||||
|
{
|
||||||
|
"start": "2021-07-07T17:00:00.000Z",
|
||||||
|
"end": "2021-07-07T19:00:00.000Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"start": "2021-07-08T17:00:00.000Z",
|
||||||
|
"end": "2021-07-08T20:00:00.000Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"start": "2021-07-10T17:00:00.000Z",
|
||||||
|
"end": "2021-07-10T20:30:00.000Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"start": "2021-07-14T17:30:00.000Z",
|
||||||
|
"end": "2021-07-14T19:30:00.000Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"start": "2021-07-17T17:00:00.000Z",
|
||||||
|
"end": "2021-07-17T20:30:00.000Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"start": "2021-07-18T10:00:00.000Z",
|
||||||
|
"end": "2021-07-18T13:30:00.000Z"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
@ -0,0 +1,40 @@
|
|||||||
|
.lds {
|
||||||
|
display: inline-block;
|
||||||
|
position: relative;
|
||||||
|
width: 80px;
|
||||||
|
height: 80px;
|
||||||
|
|
||||||
|
div {
|
||||||
|
box-sizing: border-box;
|
||||||
|
display: block;
|
||||||
|
position: absolute;
|
||||||
|
width: 64px;
|
||||||
|
height: 64px;
|
||||||
|
margin: 8px;
|
||||||
|
border: 8px solid var(--foreground);
|
||||||
|
border-radius: 50%;
|
||||||
|
animation: lds-ring 1.2s cubic-bezier(0.5, 0, 0.5, 1) infinite;
|
||||||
|
border-color: var(--foreground) transparent transparent transparent;
|
||||||
|
|
||||||
|
&:nth-child(1) {
|
||||||
|
animation-delay: -0.45s;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:nth-child(2) {
|
||||||
|
animation-delay: -0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:nth-child(3) {
|
||||||
|
animation-delay: -0.15s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes lds-ring {
|
||||||
|
0% {
|
||||||
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
transform: rotate(360deg);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,14 @@
|
|||||||
|
import { FC } from 'react';
|
||||||
|
|
||||||
|
import styles from './Spinner.module.scss';
|
||||||
|
|
||||||
|
const Spinner: FC = () => (
|
||||||
|
<div className={styles.lds}>
|
||||||
|
<div></div>
|
||||||
|
<div></div>
|
||||||
|
<div></div>
|
||||||
|
<div></div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
export default Spinner;
|
@ -0,0 +1,4 @@
|
|||||||
|
export default interface Shift {
|
||||||
|
start: string;
|
||||||
|
end: string;
|
||||||
|
}
|
@ -0,0 +1,40 @@
|
|||||||
|
.body {
|
||||||
|
padding-top: 6rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content {
|
||||||
|
height: calc(100vh - 6rem);
|
||||||
|
padding-top: 5rem;
|
||||||
|
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table {
|
||||||
|
background-color: var(--secondary);
|
||||||
|
padding: 3rem;
|
||||||
|
|
||||||
|
font-family: 'Roboto';
|
||||||
|
|
||||||
|
border-radius: 7.5px;
|
||||||
|
border: var(--borders) 1px solid;
|
||||||
|
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tableHeader {
|
||||||
|
font-family: 'Raleway';
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.weekDays {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.error {
|
||||||
|
button {
|
||||||
|
margin-right: 2rem;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,110 @@
|
|||||||
|
import { NextPage } from 'next';
|
||||||
|
import { Info, DateTime } from 'luxon';
|
||||||
|
import useSWR from 'swr';
|
||||||
|
|
||||||
|
import { FC } from 'react';
|
||||||
|
|
||||||
|
import { stringToTime } from '@utils/date';
|
||||||
|
|
||||||
|
import Spinner from '@components/Spinner';
|
||||||
|
import Layout from '@components/Layout';
|
||||||
|
import Page from '@components/Page';
|
||||||
|
|
||||||
|
import Shift from '@models/shifts';
|
||||||
|
|
||||||
|
import styles from './Shifts.module.scss';
|
||||||
|
|
||||||
|
interface APIResponse {
|
||||||
|
updated: Date;
|
||||||
|
parsed: Shift[];
|
||||||
|
}
|
||||||
|
|
||||||
|
const Error: FC = () => (
|
||||||
|
<>
|
||||||
|
<div className={styles.error}>
|
||||||
|
<h1>Error retrieving shift information</h1>
|
||||||
|
<button className="button">Retry</button>
|
||||||
|
<a href="/">
|
||||||
|
<button className="button">Go back</button>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
|
||||||
|
const Table: FC = () => {
|
||||||
|
const { data, error } = useSWR<APIResponse>('https://api.g-vm.nl/appie');
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
return <Error />;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!data) {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Spinner />
|
||||||
|
<h1>Retrieving shift information...</h1>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data) {
|
||||||
|
const weeks = new Map<number, Record<string, Shift>>();
|
||||||
|
|
||||||
|
data.parsed.forEach((shift) => {
|
||||||
|
const weekNumber = DateTime.fromISO(shift.start).weekNumber;
|
||||||
|
const dayName = DateTime.fromISO(shift.start).weekdayLong;
|
||||||
|
|
||||||
|
const current = weeks.get(weekNumber);
|
||||||
|
|
||||||
|
weeks.set(weekNumber, { ...current, [dayName]: shift });
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<table className={styles.table}>
|
||||||
|
<caption>
|
||||||
|
<h1 className={styles.tableHeader}>Work timesheet</h1>
|
||||||
|
</caption>
|
||||||
|
<thead>
|
||||||
|
<tr className={styles.weekDays}>
|
||||||
|
<th></th>
|
||||||
|
{Info.weekdays().map((day) => (
|
||||||
|
<th key={day}>{day}</th>
|
||||||
|
))}
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{Array.from(weeks).map(([weekNumber, week], i) => (
|
||||||
|
<tr key={i}>
|
||||||
|
<th>{weekNumber}</th>
|
||||||
|
{Info.weekdays().map((weekDay) => {
|
||||||
|
week[weekDay] ? (
|
||||||
|
<td key={week[weekDay].start}>
|
||||||
|
{stringToTime(week[weekDay].start)} - {stringToTime(week[weekDay].end)}
|
||||||
|
</td>
|
||||||
|
) : (
|
||||||
|
<td></td>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</tr>
|
||||||
|
))}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const Shifts: NextPage = () => (
|
||||||
|
<Page description="Check mijn AH rooster" title="Shifts">
|
||||||
|
<Layout>
|
||||||
|
<div className={styles.body}>
|
||||||
|
<div className={styles.content}>
|
||||||
|
<div>
|
||||||
|
<Table />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Layout>
|
||||||
|
</Page>
|
||||||
|
);
|
||||||
|
|
||||||
|
export default Shifts;
|
Binary file not shown.
Binary file not shown.
@ -1,57 +1,9 @@
|
|||||||
/* cyrillic-ext */
|
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: 'Raleway';
|
font-family: 'Raleway';
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
font-display: swap;
|
font-display: swap;
|
||||||
src: url(https://fonts.gstatic.com/s/raleway/v19/1Ptxg8zYS_SKggPN4iEgvnHyvveLxVvaorCFPrEVJz9d-c8.woff2)
|
src: url(./fonts/raleway.woff2) format('woff2');
|
||||||
format('woff2');
|
|
||||||
unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* cyrillic */
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Raleway';
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 400;
|
|
||||||
font-display: swap;
|
|
||||||
src: url(https://fonts.gstatic.com/s/raleway/v19/1Ptxg8zYS_SKggPN4iEgvnHyvveLxVvaorCMPrEVJz9d-c8.woff2)
|
|
||||||
format('woff2');
|
|
||||||
unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* vietnamese */
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Raleway';
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 400;
|
|
||||||
font-display: swap;
|
|
||||||
src: url(https://fonts.gstatic.com/s/raleway/v19/1Ptxg8zYS_SKggPN4iEgvnHyvveLxVvaorCHPrEVJz9d-c8.woff2)
|
|
||||||
format('woff2');
|
|
||||||
unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0,
|
|
||||||
U+1EA0-1EF9, U+20AB;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* latin-ext */
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Raleway';
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 400;
|
|
||||||
font-display: swap;
|
|
||||||
src: url(https://fonts.gstatic.com/s/raleway/v19/1Ptxg8zYS_SKggPN4iEgvnHyvveLxVvaorCGPrEVJz9d-c8.woff2)
|
|
||||||
format('woff2');
|
|
||||||
unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113,
|
|
||||||
U+2C60-2C7F, U+A720-A7FF;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* latin */
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Raleway';
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 400;
|
|
||||||
font-display: swap;
|
|
||||||
src: url(https://fonts.gstatic.com/s/raleway/v19/1Ptxg8zYS_SKggPN4iEgvnHyvveLxVvaorCIPrEVJz9d.woff2)
|
|
||||||
format('woff2');
|
|
||||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F,
|
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F,
|
||||||
U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
|
U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,8 @@
|
|||||||
|
@font-face {
|
||||||
|
font-family: 'Roboto';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 400;
|
||||||
|
src: url(./fonts/roboto.woff2) format('woff2');
|
||||||
|
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F,
|
||||||
|
U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
|
||||||
|
}
|
@ -0,0 +1,3 @@
|
|||||||
|
import { DateTime } from 'luxon';
|
||||||
|
|
||||||
|
export const stringToTime = (date: string): string => DateTime.fromISO(date).toFormat('T');
|
Loading…
Reference in new issue