Skip to content

Commit

Permalink
make it work
Browse files Browse the repository at this point in the history
  • Loading branch information
Gabor Juhasz committed Jul 8, 2022
1 parent dcd0d38 commit 2e5a7f7
Show file tree
Hide file tree
Showing 13 changed files with 338 additions and 87 deletions.
71 changes: 71 additions & 0 deletions components/Form.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import { Filter } from "pages";
import React, { FC, useRef } from "react";
import { Location, Program, Range } from "types";

interface FormProps {
filter: Filter;
setFilter: (filter: Filter) => void;
}
export const Form: FC<FormProps> = ({ filter, setFilter }) => {
const formRef = useRef<HTMLFormElement>(null);
const onChange = React.useCallback(() => {
if (!formRef.current) {
return;
}
const data = new FormData(formRef.current);
setFilter({
range: data.get("range") as Range,
program: data.getAll("program") as Program[],
location: data.getAll("location") as Location[],
});
}, [setFilter]);

return (
<form ref={formRef}>
<div>
{Object.values(Location).map((location) => {
return (
<input
key={location}
type="checkbox"
name="location"
value={location}
checked={filter.location?.includes(location)}
onChange={onChange}
/>
);
})}
</div>

<div>
{Object.values(Program).map((program) => {
return (
<input
key={program}
type="checkbox"
name="program"
value={program}
checked={filter.program?.includes(program)}
onChange={onChange}
/>
);
})}
</div>

<div>
{Object.values(Range).map((range) => {
return (
<input
key={range}
type="radio"
name="range"
value={range}
checked={range === filter.range}
onChange={onChange}
/>
);
})}
</div>
</form>
);
};
1 change: 1 addition & 0 deletions data.json

Large diffs are not rendered by default.

11 changes: 11 additions & 0 deletions package-lock.json

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

4 changes: 4 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
"lint": "next lint"
},
"dependencies": {
"dayjs": "^1.11.3",
"next": "12.2.1",
"react": "18.2.0",
"react-dom": "18.2.0"
Expand All @@ -20,5 +21,8 @@
"eslint": "8.19.0",
"eslint-config-next": "12.2.1",
"typescript": "4.7.4"
},
"prettier": {
"printWidth": 120
}
}
8 changes: 4 additions & 4 deletions pages/_app.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import '../styles/globals.css'
import type { AppProps } from 'next/app'
import "styles/globals.css";
import type { AppProps } from "next/app";

function MyApp({ Component, pageProps }: AppProps) {
return <Component {...pageProps} />
return <Component {...pageProps} />;
}

export default MyApp
export default MyApp;
97 changes: 97 additions & 0 deletions pages/api/filter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
import type { NextApiRequest, NextApiResponse } from "next";
import { Range, Location, Program, Item } from "types";
import dayjs from "dayjs";

const getUrl = (host?: string) => {
if (!host) {
return;
}
const protocol = host.includes("localhost") ? "http://" : "https://";
return protocol + host;
};

const normalizeQueryValue = (value: string | string[] | undefined): any[] | undefined => {
if (typeof value === "string") {
return value.split(",");
}
return value;
};

export default async function handler(req: NextApiRequest, res: NextApiResponse) {
const response = await fetch(getUrl(req.headers.host) + "/api");
if (!response.ok) {
res.status(response.status).end();
return;
}

const data = await response.json();
let list: Item[] = data.data.centerpiece;
list = list.map((item, index) => {
item.id = index;
return item;
});

list = filterByLocation(list, normalizeQueryValue(req.query.location));
list = filterByProgram(list, normalizeQueryValue(req.query.program));
list = filterByRange(list, req.query.range as Range);
res.json(list);
}

const filterByLocation = (list: Item[], locations: Location[] | undefined) => {
if (!locations) {
return list;
}
return list.filter((item) => {
if (!item.village) {
return true;
}
return locations.some((location) => location === item.village?.name);
});
};

const filterByProgram = (list: Item[], programs: Program[] | undefined) => {
if (!programs) {
return list;
}
return list.filter((item) => {
if (!item.labels) {
return true;
}
return programs.some((program) => {
const labelNames = item.labels?.map((label) => label.name);
return labelNames?.includes(program);
});
});
};

const parseDate = (item: Item) => {
return new Date("2022 " + item.time?.name).getTime() / 1000;
};

const getDateForRange = (range: Range): number => {
switch (range) {
case Range.three: {
return dayjs().add(3, "hours").unix();
}
case Range.today: {
return dayjs().endOf("day").unix();
}
case Range.tomorrow: {
return dayjs().add(1, "day").endOf("day").unix();
}
default: {
return 0;
}
}
};

const filterByRange = (list: Item[], range: Range) => {
if (range === Range.all) {
return list;
}
const rangeDate = getDateForRange(range);
return list.filter((item) => {
const date = parseDate(item);
return date < rangeDate;
});
};
13 changes: 0 additions & 13 deletions pages/api/hello.ts

This file was deleted.

23 changes: 23 additions & 0 deletions pages/api/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import type { NextApiRequest, NextApiResponse } from "next";
import jsonData from "data.json";

const URL = "https://ordogkatlan.hu/2022";

export default async function handler(req: NextApiRequest, res: NextApiResponse) {
res.json(jsonData);
return;

console.log("fetching " + URL);
const response = await fetch(URL, {
headers: { Accept: "application/json" },
});

if (!response.ok) {
res.status(response.status).end();
return;
}

const data = await response.json();
res.setHeader("Cache-Control", "public, s-maxage=3600, stale-while-revalidate");
res.json(data);
}
113 changes: 46 additions & 67 deletions pages/index.tsx
100755 → 100644
Original file line number Diff line number Diff line change
@@ -1,72 +1,51 @@
import type { NextPage } from 'next'
import Head from 'next/head'
import Image from 'next/image'
import styles from '../styles/Home.module.css'
import { Form } from "components/Form";
import type { NextPage } from "next";
import React, { useEffect, useState } from "react";
import { useLocalStorage } from "utils/useLocalStorage";
import { Location, Program, Range, Item } from "types";

export interface Filter {
range: Range;
program?: Program[];
location?: Location[];
}

const Home: NextPage = () => {
return (
<div className={styles.container}>
<Head>
<title>Create Next App</title>
<meta name="description" content="Generated by create next app" />
<link rel="icon" href="/favicon.ico" />
</Head>

<main className={styles.main}>
<h1 className={styles.title}>
Welcome to <a href="https://nextjs.org">Next.js!</a>
</h1>

<p className={styles.description}>
Get started by editing{' '}
<code className={styles.code}>pages/index.tsx</code>
</p>

<div className={styles.grid}>
<a href="https://nextjs.org/docs" className={styles.card}>
<h2>Documentation &rarr;</h2>
<p>Find in-depth information about Next.js features and API.</p>
</a>
const [filter, setFilter] = useLocalStorage<Filter>("DD_KATLAN_FILTER", {
range: Range.all,
program: Object.values(Program),
location: Object.values(Location),
});
const [list, setList] = useState<Item[]>([]);

useEffect(() => {
// @ts-ignore
const query = new URLSearchParams(filter);
// console.log(filter, query.toString());
fetch("/api/filter?" + query)
.then((r) => r.json())
.then((r) => setList(r));
}, [filter]);

<a href="https://nextjs.org/learn" className={styles.card}>
<h2>Learn &rarr;</h2>
<p>Learn about Next.js in an interactive course with quizzes!</p>
</a>

<a
href="https://github.com/vercel/next.js/tree/canary/examples"
className={styles.card}
>
<h2>Examples &rarr;</h2>
<p>Discover and deploy boilerplate example Next.js projects.</p>
</a>

<a
href="https://vercel.com/new?utm_source=create-next-app&utm_medium=default-template&utm_campaign=create-next-app"
className={styles.card}
>
<h2>Deploy &rarr;</h2>
<p>
Instantly deploy your Next.js site to a public URL with Vercel.
</p>
</a>
</div>
</main>

<footer className={styles.footer}>
<a
href="https://vercel.com?utm_source=create-next-app&utm_medium=default-template&utm_campaign=create-next-app"
target="_blank"
rel="noopener noreferrer"
>
Powered by{' '}
<span className={styles.logo}>
<Image src="/vercel.svg" alt="Vercel Logo" width={72} height={16} />
</span>
</a>
</footer>
return (
<div>
<h1>{list.length}</h1>
{list.map((item) => (
<li key={item.id}>{item.title}</li>
))}

<div
style={{
width: "100%",
background: "white",
position: "fixed",
bottom: 0,
}}
>
<Form filter={filter} setFilter={setFilter} />
</div>
</div>
)
}
);
};

export default Home
export default Home;
4 changes: 2 additions & 2 deletions styles/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ html,
body {
padding: 0;
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen,
Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif;
font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen, Ubuntu, Cantarell, Fira Sans, Droid Sans,
Helvetica Neue, sans-serif;
}

a {
Expand Down
Loading

0 comments on commit 2e5a7f7

Please sign in to comment.