Skip to content

Commit

Permalink
feat: add climate page and location page
Browse files Browse the repository at this point in the history
  • Loading branch information
oyvindis committed Apr 23, 2022
1 parent 2ea158f commit fdc9b61
Show file tree
Hide file tree
Showing 20 changed files with 266 additions and 0 deletions.
1 change: 1 addition & 0 deletions .env.development
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
NEXT_PUBLIC_READING_BASE_URI=https://www.oyvindis.com
1 change: 1 addition & 0 deletions .env.production
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
NEXT_PUBLIC_READING_BASE_URI=https://www.oyvindis.com
11 changes: 11 additions & 0 deletions components/container/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import React, { memo, FC, PropsWithChildren } from 'react';

import SC from './styled';

interface Props {}

const Container: FC<PropsWithChildren<Props>> = ({ children }) => (
<SC.Container>{children}</SC.Container>
);

export default memo(Container);
20 changes: 20 additions & 0 deletions components/container/styled.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import styled from 'styled-components';

const onDesktopView = '@media (min-width: 900px)';

const Container = styled.div`
display: flex;
flex-direction: column;
margin: 0 auto;
padding: 0 calc(12px + (32 - 12) * ((100vw - 320px) / (900 - 320)));
width: 1200px;
z-index: 10;
${onDesktopView} {
& {
padding: 0;
}
}
`;

export default { Container };
27 changes: 27 additions & 0 deletions components/pages/climate/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import React, { memo, FC } from 'react';
import Link from 'next/link';

import Container from '../../container';
import SC from './styled';
import { Location } from '../../../types';

interface Props {
locations: Location[];
}

const ClimatePageWrapper: FC<Props> = ({ locations }) => (
<Container>
<SC.ClimatePage>
<ul>
{locations?.length > 0 &&
locations.map(({ id, name }) => (
<li key={id}>
<Link href={`/climate/location/${id}`}>{name}</Link>
</li>
))}
</ul>
</SC.ClimatePage>
</Container>
);

export default memo(ClimatePageWrapper);
7 changes: 7 additions & 0 deletions components/pages/climate/styled.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import styled from 'styled-components';

const ClimatePage = styled.div`
display: flex;
`;

export default { ClimatePage };
11 changes: 11 additions & 0 deletions env.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { validateEnv } from './utils/common';

const NAMESPACE = process.env.NAMESPACE! ?? 'dev';
const READING_BASE_URI = process.env.NEXT_PUBLIC_READING_BASE_URI! ?? 'https://www.oyvindis.com'

const env = {
NAMESPACE,
READING_BASE_URI
}

export default validateEnv(env);
42 changes: 42 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
"lint": "next lint --fix"
},
"dependencies": {
"axios": "^0.26.1",
"next": "12.1.0",
"react": "17.0.2",
"react-dom": "17.0.2",
Expand Down
23 changes: 23 additions & 0 deletions pages/climate/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import type { NextPage, GetServerSidePropsResult } from 'next';

import { getLocations } from '../../services/api/climate/locations';

import ClimatePageWrapper from '../../components/pages/climate';
import { Location } from '../../types';

interface Props {
locations: Location[];
}

const Climate: NextPage<Props> = ({ locations }) => {
return <ClimatePageWrapper locations={locations} />;
};

export async function getServerSideProps(): Promise<
GetServerSidePropsResult<Props>
> {
const locations = await getLocations();
return { props: { locations } };
}

export default Climate;
38 changes: 38 additions & 0 deletions pages/climate/location/[id]/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import type { NextPage } from 'next';
import { useRouter } from 'next/router';
import { useEffect, useState } from 'react';

import { Reading } from '../../../../types';
import { getReadings } from '../../../../services/api/climate/readings';

interface Props {}

const Location: NextPage<Props> = () => {
const [readings, setReadings] = useState<Reading[]>([]);

const router = useRouter();
const { id } = router.query;

useEffect(() => {
getReadings(Array.isArray(id) ? id[0] : id).then(readings =>
setReadings(readings)
);
}, [id]);

return (
<div>
<ul>
{readings?.length > 0 &&
readings.map(({ id, humidity, temp, localDateTime }) => (
<li key={id}>
<div>
{temp} - {humidity} - {localDateTime}
</div>
</li>
))}
</ul>
</div>
);
};

export default Location;
27 changes: 27 additions & 0 deletions services/api/climate/host.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import axios from 'axios';
import env from '../../../env';

interface Props {
path: string;
method: any;
data?: any;
params?: URLSearchParams;
}

const { READING_BASE_URI } = env;

export const climateReading = ({ path, method, data, params }: Props) =>
axios({
url: `${READING_BASE_URI}${path}`,
method,
data,
params
})
.then(response => response.data)
.catch(() => null);

export const climateReadingPost = (path: string, body: any) =>
climateReading({ path, method: 'POST', data: body });

export const climateReadingGet = (path: string, params?: URLSearchParams) =>
climateReading({ path, method: 'GET', params });
4 changes: 4 additions & 0 deletions services/api/climate/locations.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { climateReadingGet } from './host';

export const getLocations = () =>
climateReadingGet('/climate-api/location')
4 changes: 4 additions & 0 deletions services/api/climate/readings.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { climateReadingGet } from './host';

export const getReadings = (location: string) =>
climateReadingGet(`/climate-api/reading/${location}`)
3 changes: 3 additions & 0 deletions types/common.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export type Actions<T extends { [key: string]: (...args: any) => any }> = {
[K in keyof T]: ReturnType<T[K]>;
}[keyof T];
19 changes: 19 additions & 0 deletions types/domain.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
export interface Location {
id: string;
name: string;
}

export interface Reading {
id: string;
location: string;
localDateTime: string;
battery: string;
co2: string;
humidity: string;
pm1: string;
pm25: string;
pressure: string;
temp: string;
time: string;
voc: string;
}
3 changes: 3 additions & 0 deletions types/enums.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export enum Namespace {
DEVELOPMENT = 'dev'
}
4 changes: 4 additions & 0 deletions types/env.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export interface EnvironmentVariables {
NAMESPACE: string;
READING_BASE_URI: string;
}
3 changes: 3 additions & 0 deletions types/index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export * from './env';
export * from './common';
export * from './domain';
17 changes: 17 additions & 0 deletions utils/common/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import type { EnvironmentVariables } from '../../types';

function assertIsDefined<T>(
key: string,
value: T
): asserts value is NonNullable<T> {
if (value === undefined || value === null) {
throw new Error(`Expected ${key} to be defined, but received ${value}`);
}
}

export const validateEnv = (
env: EnvironmentVariables
): EnvironmentVariables => {
Object.entries(env).forEach(([key, value]) => assertIsDefined(key, value));
return env;
};

0 comments on commit fdc9b61

Please sign in to comment.