mirror of
https://github.com/TheRealOwenRees/echecsfrance.git
synced 2026-07-23 04:26: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.
|
||||
|
||||
TODO
|
||||
|
||||
# dependencies
|
||||
/node_modules
|
||||
/.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() {
|
||||
return (
|
||||
<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="absolute">
|
||||
<h1>About Page</h1>
|
||||
|
||||
@@ -3,7 +3,7 @@ import Layout from "@/components/Layout";
|
||||
export default function Contact() {
|
||||
return (
|
||||
<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="absolute">
|
||||
<h1>Contact Page</h1>
|
||||
|
||||
+21
-6
@@ -1,14 +1,29 @@
|
||||
import Link from "next/link";
|
||||
import Layout from "@/components/Layout";
|
||||
|
||||
export default function Home() {
|
||||
return (
|
||||
<Layout>
|
||||
<header className="grid h-[calc(100%-144px)] md:h-[calc(100%-112px)] place-items-center">
|
||||
<div className="relative h-full w-full bg-[url('/images/map-bg.jpg')] brightness-[0.2]"></div>
|
||||
<div className="absolute">
|
||||
<h1>Heading 1</h1>
|
||||
<h2>Heading 2</h2>
|
||||
<h3>Heading 3</h3>
|
||||
<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')] bg-cover bg-center brightness-[0.2]"></div>
|
||||
<div className="absolute text-center">
|
||||
<h1 className="text-5xl p-5">Echecs France</h1>
|
||||
<h2 className="text-3xl p-5 capitalize">
|
||||
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>
|
||||
</header>
|
||||
</Layout>
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
export default function Footer() {
|
||||
return (
|
||||
<footer className="w-full bg-gray-800 text-white p-3">
|
||||
<p>Footer</p>
|
||||
<footer className="grid grid-cols-2 bg-gray-800 text-white p-3">
|
||||
<div>
|
||||
<p>© {new Date().getFullYear()} - Owen Rees</p>
|
||||
</div>
|
||||
</footer>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ export default function Layout({
|
||||
children: React.ReactNode;
|
||||
}) {
|
||||
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 />
|
||||
{children}
|
||||
<Footer />
|
||||
|
||||
@@ -2,7 +2,7 @@ import Link from "next/link";
|
||||
|
||||
export default function Navbar() {
|
||||
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="flex w-full md:w-1/2 justify-center md:justify-start text-white font-extrabold">
|
||||
<Link
|
||||
@@ -13,26 +13,26 @@ export default function Navbar() {
|
||||
</Link>
|
||||
</div>
|
||||
<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">
|
||||
<li className="mr-3">
|
||||
<ul className="list-reset text-white no-underline flex flex-1 md:flex-none items-center">
|
||||
<li className="mr-10">
|
||||
<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"
|
||||
>
|
||||
Tournois
|
||||
</Link>
|
||||
</li>
|
||||
<li className="mr-3">
|
||||
<li className="mr-10">
|
||||
<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"
|
||||
>
|
||||
About
|
||||
</Link>
|
||||
</li>
|
||||
<li className="mr-3">
|
||||
<li className="mr-10">
|
||||
<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"
|
||||
>
|
||||
Contact
|
||||
|
||||
@@ -24,7 +24,7 @@ export default function TournamentMap({ tournamentData }: TournamentDataProps) {
|
||||
return (
|
||||
<section
|
||||
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
|
||||
center={center}
|
||||
|
||||
+1
-1
@@ -7,7 +7,7 @@ export default defineConfig({
|
||||
// implement node event listeners here
|
||||
},
|
||||
},
|
||||
|
||||
chromeWebSecurity: false,
|
||||
component: {
|
||||
devServer: {
|
||||
framework: "next",
|
||||
|
||||
@@ -12,38 +12,40 @@ const navbarFooterCheck = () => {
|
||||
});
|
||||
};
|
||||
|
||||
describe("Verify home page", () => {
|
||||
describe("Verify component mount", () => {
|
||||
describe("Verify home page", () => {
|
||||
beforeEach(() => {
|
||||
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 });
|
||||
});
|
||||
|
||||
navbarFooterCheck();
|
||||
});
|
||||
});
|
||||
|
||||
describe("Verify about page", () => {
|
||||
describe("Verify about page", () => {
|
||||
beforeEach(() => {
|
||||
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 });
|
||||
});
|
||||
|
||||
navbarFooterCheck();
|
||||
});
|
||||
});
|
||||
|
||||
describe("Verify contact page", () => {
|
||||
describe("Verify contact page", () => {
|
||||
beforeEach(() => {
|
||||
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 });
|
||||
});
|
||||
|
||||
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";
|
||||
|
||||
// TODO change 'any'
|
||||
// TODO document this hook with TSDoc
|
||||
const useTournamentDataFilter = (
|
||||
initialState: Tournament[]
|
||||
): (any | ((searchQuery: string) => void))[] => {
|
||||
|
||||
+4
-3
@@ -7,9 +7,10 @@
|
||||
"build": "next build",
|
||||
"start": "next start",
|
||||
"lint": "next lint",
|
||||
"test": "jest",
|
||||
"cypress:open": "cypress open",
|
||||
"cypress:run": "cypress run"
|
||||
"test:e2e": "cypress run",
|
||||
"test:component": "cypress run --component",
|
||||
"test": "npm run test:component && npm run test:e2e",
|
||||
"cypress": "cypress open"
|
||||
},
|
||||
"dependencies": {
|
||||
"@types/node": "20.2.3",
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
"target": "es5",
|
||||
"lib": ["dom", "dom.iterable", "esnext"],
|
||||
"allowJs": true,
|
||||
"types": ["cypress"],
|
||||
"skipLibCheck": true,
|
||||
"strict": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
|
||||
+14
-7
@@ -1,8 +1,17 @@
|
||||
import { TournamentDataProps } from "@/types";
|
||||
import { LatLngLiteral } from "leaflet";
|
||||
|
||||
import L from "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 = (
|
||||
timeControl: string,
|
||||
colour: string,
|
||||
@@ -12,7 +21,6 @@ export const createLayerGroups = (
|
||||
(t) => t.time_control === timeControl
|
||||
);
|
||||
|
||||
// TODO consider moving this into its own function
|
||||
const iconOptions = new L.Icon({
|
||||
iconUrl: `images/leaflet/marker-icon-2x-${colour}.png`,
|
||||
shadowUrl: "images/leaflet/marker-shadow.png",
|
||||
@@ -23,13 +31,12 @@ export const createLayerGroups = (
|
||||
});
|
||||
|
||||
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 (
|
||||
<Marker position={coordinates} key={t._id} icon={iconOptions}>
|
||||
<Marker
|
||||
position={coordinateRandomisation(t.coordinates[0], t.coordinates[1])}
|
||||
key={t._id}
|
||||
icon={iconOptions}
|
||||
>
|
||||
<Popup>
|
||||
<p>
|
||||
{t.date}
|
||||
|
||||
Reference in New Issue
Block a user