nav updated

This commit is contained in:
Owen Rees
2023-06-09 16:50:32 +02:00
parent 4cf8566a59
commit 1ad2f1b306
19 changed files with 173 additions and 61 deletions
+2
View File
@@ -1,5 +1,7 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
TODO
# dependencies # dependencies
/node_modules /node_modules
/.pnp /.pnp
+26
View File
@@ -0,0 +1,26 @@
footer
light/dark theme
tests for tournois, testing the loading of map and table, then counting the markers
logo for navbar and favicon
tournament table scroll
hover on table needs fixing - this only seemed to happen once I moved the logic into its own hook
document my new hook
error handling
e2e tests for tournament page:
- make sure number of markers = tournamentData.length
home page
about page
contact page
SEO
+1 -1
View File
@@ -3,7 +3,7 @@ import Layout from "@/components/Layout";
export default function About() { export default function About() {
return ( return (
<Layout> <Layout>
<header className="grid h-[calc(100%-144px)] md:h-[calc(100%-112px)] place-items-center"> <header className="grid h-[calc(100%-156px)] md:h-[calc(100%-124px)] place-items-center">
<div className="relative h-full w-full bg-amber-200"></div> <div className="relative h-full w-full bg-amber-200"></div>
<div className="absolute"> <div className="absolute">
<h1>About Page</h1> <h1>About Page</h1>
+1 -1
View File
@@ -3,7 +3,7 @@ import Layout from "@/components/Layout";
export default function Contact() { export default function Contact() {
return ( return (
<Layout> <Layout>
<header className="grid h-[calc(100%-144px)] md:h-[calc(100%-112px)] place-items-center"> <header className="grid h-[calc(100%-156px)] md:h-[calc(100%-124px)] place-items-center">
<div className="relative h-full w-full bg-amber-200"></div> <div className="relative h-full w-full bg-amber-200"></div>
<div className="absolute"> <div className="absolute">
<h1>Contact Page</h1> <h1>Contact Page</h1>
+21 -6
View File
@@ -1,14 +1,29 @@
import Link from "next/link";
import Layout from "@/components/Layout"; import Layout from "@/components/Layout";
export default function Home() { export default function Home() {
return ( return (
<Layout> <Layout>
<header className="grid h-[calc(100%-144px)] md:h-[calc(100%-112px)] place-items-center"> <header className="grid h-[calc(100%-156px)] md:h-[calc(100%-124px)] place-items-center">
<div className="relative h-full w-full bg-[url('/images/map-bg.jpg')] brightness-[0.2]"></div> <div className="relative h-full w-full bg-[url('/images/map-bg.jpg')] bg-cover bg-center brightness-[0.2]"></div>
<div className="absolute"> <div className="absolute text-center">
<h1>Heading 1</h1> <h1 className="text-5xl p-5">Echecs France</h1>
<h2>Heading 2</h2> <h2 className="text-3xl p-5 capitalize">
<h3>Heading 3</h3> Find chess tournaments in France on a map
</h2>
<h3 className="text-xl p-5 mb-5">
A visual representation of all the chess tournaments published by
the{" "}
<Link href="http://www.echecs.asso.fr/" target="_blank">
<abbr title="Fédération Française des Échecs">FFE</abbr>
</Link>
</h3>
<Link
href="/tournois"
className="text-white bg-gradient-to-r from-teal-400 via-teal-500 to-teal-600 hover:bg-gradient-to-br focus:ring-4 focus:outline-none focus:ring-teal-300 dark:focus:ring-teal-800 font-medium rounded-lg text-sm px-5 py-2.5 text-center mr-2 mb-2"
>
Get Started
</Link>
</div> </div>
</header> </header>
</Layout> </Layout>
+4 -2
View File
@@ -1,7 +1,9 @@
export default function Footer() { export default function Footer() {
return ( return (
<footer className="w-full bg-gray-800 text-white p-3"> <footer className="grid grid-cols-2 bg-gray-800 text-white p-3">
<p>Footer</p> <div>
<p>&copy; {new Date().getFullYear()} - Owen Rees</p>
</div>
</footer> </footer>
); );
} }
+1 -1
View File
@@ -7,7 +7,7 @@ export default function Layout({
children: React.ReactNode; children: React.ReactNode;
}) { }) {
return ( return (
<div className="h-screen bg-white font-sans leading-normal tracking-normal"> <div className="h-screen min-h-[400px] bg-white font-sans leading-normal tracking-normal">
<Navbar /> <Navbar />
{children} {children}
<Footer /> <Footer />
+8 -8
View File
@@ -2,7 +2,7 @@ import Link from "next/link";
export default function Navbar() { export default function Navbar() {
return ( return (
<nav className="bg-gray-800 p-2 mt-0 w-full"> <nav className="bg-gray-800 mt-0 w-full">
<div className="container mx-auto flex flex-wrap items-center"> <div className="container mx-auto flex flex-wrap items-center">
<div className="flex w-full md:w-1/2 justify-center md:justify-start text-white font-extrabold"> <div className="flex w-full md:w-1/2 justify-center md:justify-start text-white font-extrabold">
<Link <Link
@@ -13,26 +13,26 @@ export default function Navbar() {
</Link> </Link>
</div> </div>
<div className="flex w-full pt-2 content-center justify-between md:w-1/2 md:justify-end"> <div className="flex w-full pt-2 content-center justify-between md:w-1/2 md:justify-end">
<ul className="list-reset text-white no-underline flex justify-between flex-1 md:flex-none items-center"> <ul className="list-reset text-white no-underline flex flex-1 md:flex-none items-center">
<li className="mr-3"> <li className="mr-10">
<Link <Link
className="inline-block hover:text-gray-200 hover:text-underline py-2 px-4" className="inline-block border-b-4 py-5 border-transparent hover:border-teal-600 transition-all ease-in-out duration-300"
href="/tournois" href="/tournois"
> >
Tournois Tournois
</Link> </Link>
</li> </li>
<li className="mr-3"> <li className="mr-10">
<Link <Link
className="inline-block hover:text-gray-200 hover:text-underline py-2 px-4" className="inline-block border-b-4 py-5 border-transparent hover:border-teal-600 transition-all ease-in-out duration-300"
href="/about" href="/about"
> >
About About
</Link> </Link>
</li> </li>
<li className="mr-3"> <li className="mr-10">
<Link <Link
className="inline-block hover:text-gray-200 hover:text-underline py-2 px-4" className="inline-block border-b-4 py-5 border-transparent hover:border-teal-600 transition-all ease-in-out duration-300"
href="/contact" href="/contact"
> >
Contact Contact
+1 -1
View File
@@ -24,7 +24,7 @@ export default function TournamentMap({ tournamentData }: TournamentDataProps) {
return ( return (
<section <section
id="tournament-map" id="tournament-map"
className="grid h-[calc(100vh-96px)] md:h-[calc(100vh-64px)]" className="grid h-[calc(100vh-108px)] md:h-[calc(100vh-76px)]"
> >
<MapContainer <MapContainer
center={center} center={center}
+1 -1
View File
@@ -7,7 +7,7 @@ export default defineConfig({
// implement node event listeners here // implement node event listeners here
}, },
}, },
chromeWebSecurity: false,
component: { component: {
devServer: { devServer: {
framework: "next", framework: "next",
+32 -30
View File
@@ -12,38 +12,40 @@ const navbarFooterCheck = () => {
}); });
}; };
describe("Verify home page", () => { describe("Verify component mount", () => {
beforeEach(() => { describe("Verify home page", () => {
cy.mount(<Home />); beforeEach(() => {
cy.mount(<Home />);
});
it("correct h1 tags with website name included", () => {
cy.get("h1").contains("echecs france", { matchCase: false });
});
navbarFooterCheck();
}); });
it("should have the correct h1 tags with website name included", () => { describe("Verify about page", () => {
cy.get("h1").contains("echecs france", { matchCase: false }); beforeEach(() => {
cy.mount(<About />);
});
it("correct h1 tags with page title included", () => {
cy.get("h1").contains("about", { matchCase: false });
});
navbarFooterCheck();
}); });
navbarFooterCheck(); describe("Verify contact page", () => {
}); beforeEach(() => {
cy.mount(<Contact />);
describe("Verify about page", () => { });
beforeEach(() => {
cy.mount(<About />); it("correct h1 tags with page title included", () => {
}); cy.get("h1").contains("contact", { matchCase: false });
});
it("should have the correct h1 tags with page title included", () => {
cy.get("h1").contains("about", { matchCase: false }); navbarFooterCheck();
}); });
navbarFooterCheck();
});
describe("Verify contact page", () => {
beforeEach(() => {
cy.mount(<Contact />);
});
it("should have the correct h1 tags with page title included", () => {
cy.get("h1").contains("contact", { matchCase: false });
});
navbarFooterCheck();
}); });
+55
View File
@@ -0,0 +1,55 @@
import { Tournament } from "@/types";
import getTournaments from "@/utils/getTournamentData";
import { createLayerGroups } from "@/utils/layerGroups";
// TODO cy.wrap() for promise resolution
// TODO DRY - variables and data fetching can be done before tests under the first describe block
describe("Unit tests of utils directory", () => {
describe("Retrieve tournament data from DB", () => {
let response: Tournament[];
let results: Tournament[];
describe("France", () => {
before(async () => {
response = await getTournaments("france");
results = response.splice(0, 5);
});
it("log first 5 results", () => {
results.forEach((result) => cy.log(JSON.stringify(result)));
});
it("check tournament urls are active", () => {
results.forEach((result) => cy.request(result.url));
});
});
});
describe("Create layer groups for map markers", () => {
let response: Tournament[];
let results: Tournament[];
describe("France", () => {
const timeControls = [
{ name: "Cadence Lente", colour: "green" },
{ name: "Rapide", colour: "blue" },
{ name: "Blitz", colour: "yellow" },
{ name: "1h KO", colour: "red" },
];
before(async () => {
response = await getTournaments("france");
results = response.splice(0, 5);
});
it("generate layer groups", () => {
const result = timeControls.map((timeControl) => {
return createLayerGroups(timeControl.name, timeControl.colour, {
tournamentData: results,
});
});
cy.wrap(result.length).should("be.greaterThan", 0);
});
});
});
});
Binary file not shown.
Binary file not shown.
Binary file not shown.
+1
View File
@@ -2,6 +2,7 @@ import { Tournament } from "@/types";
import { useState } from "react"; import { useState } from "react";
// TODO change 'any' // TODO change 'any'
// TODO document this hook with TSDoc
const useTournamentDataFilter = ( const useTournamentDataFilter = (
initialState: Tournament[] initialState: Tournament[]
): (any | ((searchQuery: string) => void))[] => { ): (any | ((searchQuery: string) => void))[] => {
+4 -3
View File
@@ -7,9 +7,10 @@
"build": "next build", "build": "next build",
"start": "next start", "start": "next start",
"lint": "next lint", "lint": "next lint",
"test": "jest", "test:e2e": "cypress run",
"cypress:open": "cypress open", "test:component": "cypress run --component",
"cypress:run": "cypress run" "test": "npm run test:component && npm run test:e2e",
"cypress": "cypress open"
}, },
"dependencies": { "dependencies": {
"@types/node": "20.2.3", "@types/node": "20.2.3",
+1
View File
@@ -3,6 +3,7 @@
"target": "es5", "target": "es5",
"lib": ["dom", "dom.iterable", "esnext"], "lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true, "allowJs": true,
"types": ["cypress"],
"skipLibCheck": true, "skipLibCheck": true,
"strict": true, "strict": true,
"forceConsistentCasingInFileNames": true, "forceConsistentCasingInFileNames": true,
+14 -7
View File
@@ -1,8 +1,17 @@
import { TournamentDataProps } from "@/types"; import { TournamentDataProps } from "@/types";
import { LatLngLiteral } from "leaflet";
import L from "leaflet"; import L from "leaflet";
import { LayerGroup, LayersControl, Marker, Popup } from "react-leaflet"; import { LayerGroup, LayersControl, Marker, Popup } from "react-leaflet";
const coordinateRandomisation = (lat: number, lng: number): LatLngLiteral => {
const randomisation = () => Math.random() * (-0.01 - 0.01) + 0.01;
return {
lat: lat + randomisation(),
lng: lng + randomisation(),
};
};
export const createLayerGroups = ( export const createLayerGroups = (
timeControl: string, timeControl: string,
colour: string, colour: string,
@@ -12,7 +21,6 @@ export const createLayerGroups = (
(t) => t.time_control === timeControl (t) => t.time_control === timeControl
); );
// TODO consider moving this into its own function
const iconOptions = new L.Icon({ const iconOptions = new L.Icon({
iconUrl: `images/leaflet/marker-icon-2x-${colour}.png`, iconUrl: `images/leaflet/marker-icon-2x-${colour}.png`,
shadowUrl: "images/leaflet/marker-shadow.png", shadowUrl: "images/leaflet/marker-shadow.png",
@@ -23,13 +31,12 @@ export const createLayerGroups = (
}); });
const layerGroup = filteredTournaments.map((t) => { const layerGroup = filteredTournaments.map((t) => {
// TODO move this coorindate randomisation into its own function to follow SRP
const coordinates = {
lat: t.coordinates[0] + Math.random() * (-0.01 - 0.01) + 0.01,
lng: t.coordinates[1] + Math.random() * (-0.01 - 0.01) + 0.01,
};
return ( return (
<Marker position={coordinates} key={t._id} icon={iconOptions}> <Marker
position={coordinateRandomisation(t.coordinates[0], t.coordinates[1])}
key={t._id}
icon={iconOptions}
>
<Popup> <Popup>
<p> <p>
{t.date} {t.date}