mirror of
https://github.com/TheRealOwenRees/echecsfrance.git
synced 2026-07-23 12:36:57 +00:00
nav updated
This commit is contained in:
@@ -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
|
||||||
|
|||||||
@@ -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
@@ -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>
|
||||||
|
|||||||
@@ -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
@@ -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>
|
||||||
|
|||||||
@@ -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>© {new Date().getFullYear()} - Owen Rees</p>
|
||||||
|
</div>
|
||||||
</footer>
|
</footer>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 />
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
@@ -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",
|
||||||
|
|||||||
@@ -12,38 +12,40 @@ const navbarFooterCheck = () => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
describe("Verify home page", () => {
|
describe("Verify component mount", () => {
|
||||||
|
describe("Verify home page", () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
cy.mount(<Home />);
|
cy.mount(<Home />);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should have the correct h1 tags with website name included", () => {
|
it("correct h1 tags with website name included", () => {
|
||||||
cy.get("h1").contains("echecs france", { matchCase: false });
|
cy.get("h1").contains("echecs france", { matchCase: false });
|
||||||
});
|
});
|
||||||
|
|
||||||
navbarFooterCheck();
|
navbarFooterCheck();
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("Verify about page", () => {
|
describe("Verify about page", () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
cy.mount(<About />);
|
cy.mount(<About />);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should have the correct h1 tags with page title included", () => {
|
it("correct h1 tags with page title included", () => {
|
||||||
cy.get("h1").contains("about", { matchCase: false });
|
cy.get("h1").contains("about", { matchCase: false });
|
||||||
});
|
});
|
||||||
|
|
||||||
navbarFooterCheck();
|
navbarFooterCheck();
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("Verify contact page", () => {
|
describe("Verify contact page", () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
cy.mount(<Contact />);
|
cy.mount(<Contact />);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should have the correct h1 tags with page title included", () => {
|
it("correct h1 tags with page title included", () => {
|
||||||
cy.get("h1").contains("contact", { matchCase: false });
|
cy.get("h1").contains("contact", { matchCase: false });
|
||||||
});
|
});
|
||||||
|
|
||||||
navbarFooterCheck();
|
navbarFooterCheck();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -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.
@@ -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
@@ -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",
|
||||||
|
|||||||
@@ -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
@@ -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}
|
||||||
|
|||||||
Reference in New Issue
Block a user