mirror of
https://github.com/TheRealOwenRees/echecsfrance.git
synced 2026-07-23 04:26:57 +00:00
Merge remote-tracking branch 'origin/main'
This commit is contained in:
@@ -1,44 +1,18 @@
|
|||||||
import clientPromise from "@/lib/mongodb";
|
import clientPromise from "@/lib/mongodb";
|
||||||
|
import { dateOrderingFrance } from "@/utils/dbDateOrdering";
|
||||||
|
|
||||||
// TODO collate only the country of France - redundant for now but will be needed when new countries are added
|
|
||||||
// probably do this by passing the country name as parameter
|
|
||||||
/**
|
/**
|
||||||
* Tournament data API endpoint
|
* Tournament data API endpoint
|
||||||
* @route /api/tournaments/france
|
* @route /api/tournaments/france
|
||||||
* @internal
|
* @internal
|
||||||
*/
|
*/
|
||||||
|
// TODO cache this result for 24 hours - using cache()
|
||||||
export async function GET() {
|
export async function GET() {
|
||||||
try {
|
try {
|
||||||
const client = await clientPromise;
|
const client = await clientPromise;
|
||||||
const db = client.db("tournamentsFranceDB");
|
const db = client.db("tournamentsFranceDB");
|
||||||
|
|
||||||
/**
|
const data = await dateOrderingFrance(db);
|
||||||
* Converts date from string into a date to allow ordering
|
|
||||||
*/
|
|
||||||
// TODO add into a middleware?
|
|
||||||
const data = await db
|
|
||||||
.collection("tournaments")
|
|
||||||
.aggregate([
|
|
||||||
{
|
|
||||||
$addFields: {
|
|
||||||
dateParts: {
|
|
||||||
$dateFromString: {
|
|
||||||
dateString: "$date",
|
|
||||||
format: "%d/%m/%Y",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
$sort: {
|
|
||||||
dateParts: 1,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
$unset: "dateParts",
|
|
||||||
},
|
|
||||||
])
|
|
||||||
.toArray();
|
|
||||||
|
|
||||||
return new Response(JSON.stringify(data), { status: 200 });
|
return new Response(JSON.stringify(data), { status: 200 });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
+10
-1
@@ -1,11 +1,20 @@
|
|||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
|
import Image from "next/image";
|
||||||
import Layout from "@/components/Layout";
|
import Layout from "@/components/Layout";
|
||||||
|
import bgImage from "@/public/images/map-bg.jpg";
|
||||||
|
|
||||||
export default function Home() {
|
export default function Home() {
|
||||||
return (
|
return (
|
||||||
<Layout>
|
<Layout>
|
||||||
<header className="grid h-[calc(100%-153px)] md:h-[calc(100%-173px)] place-items-center">
|
<header className="grid h-[calc(100%-153px)] md:h-[calc(100%-173px)] 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="relative h-full w-full brightness-[0.2]">
|
||||||
|
<Image
|
||||||
|
src={bgImage}
|
||||||
|
alt="Background image of France"
|
||||||
|
fill={true}
|
||||||
|
style={{ objectFit: "cover" }}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
<div className="absolute text-center">
|
<div className="absolute text-center">
|
||||||
<h1 className="text-5xl p-5">Echecs France</h1>
|
<h1 className="text-5xl p-5">Echecs France</h1>
|
||||||
<h2 className="text-3xl p-5">
|
<h2 className="text-3xl p-5">
|
||||||
|
|||||||
+20
-7
@@ -1,11 +1,9 @@
|
|||||||
import { Tournament } from "@/types";
|
import clientPromise from "@/lib/mongodb";
|
||||||
|
|
||||||
import dynamic from "next/dynamic";
|
import dynamic from "next/dynamic";
|
||||||
import Layout from "@/components/Layout";
|
import Layout from "@/components/Layout";
|
||||||
import TournamentTable from "@/components/TournamentTable";
|
import TournamentTable from "@/components/TournamentTable";
|
||||||
import getTournaments from "@/utils/getTournamentData";
|
import { dateOrderingFrance } from "@/utils/dbDateOrdering";
|
||||||
|
|
||||||
// TODO can these functions be put into a custom hook?
|
|
||||||
/**
|
/**
|
||||||
* Imports the tournament map component, ensuring CSR only.
|
* Imports the tournament map component, ensuring CSR only.
|
||||||
* @remarks SSR is not supported by react-leaflet
|
* @remarks SSR is not supported by react-leaflet
|
||||||
@@ -19,17 +17,32 @@ const TournamentMap = dynamic(() => import("@/components/TournamentMap"), {
|
|||||||
),
|
),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export const revalidate = 86400; // cache for 24 hours
|
||||||
|
|
||||||
|
const getTournaments = async () => {
|
||||||
|
try {
|
||||||
|
const client = await clientPromise;
|
||||||
|
const db = client.db("tournamentsFranceDB");
|
||||||
|
|
||||||
|
const data = await dateOrderingFrance(db);
|
||||||
|
|
||||||
|
return JSON.stringify(data);
|
||||||
|
} catch (error) {
|
||||||
|
throw new Error("Error fetching tournament data");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
export default async function Tournaments() {
|
export default async function Tournaments() {
|
||||||
const tournamentData = await getTournaments("france");
|
const tournamentData = await getTournaments();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Layout>
|
<Layout>
|
||||||
<main className="grid lg:grid-cols-2">
|
<main className="grid lg:grid-cols-2">
|
||||||
<div className="">
|
<div className="">
|
||||||
<TournamentMap tournamentData={tournamentData} />
|
<TournamentMap tournamentData={JSON.parse(tournamentData)} />
|
||||||
</div>
|
</div>
|
||||||
<div className="bg-white dark:bg-gray-800 lg:overflow-y-auto">
|
<div className="bg-white dark:bg-gray-800 lg:overflow-y-auto">
|
||||||
<TournamentTable tournamentData={tournamentData} />
|
<TournamentTable tournamentData={JSON.parse(tournamentData)} />
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
</Layout>
|
</Layout>
|
||||||
|
|||||||
@@ -1,54 +1,55 @@
|
|||||||
import { Tournament } from "@/types";
|
// import { Tournament } from "@/types";
|
||||||
import getTournaments from "@/utils/getTournamentData";
|
// import getTournaments from "@/utils/getTournamentData";
|
||||||
import { createLayerGroups } from "@/utils/layerGroups";
|
// import { createLayerGroups } from "@/utils/layerGroups";
|
||||||
|
//
|
||||||
|
|
||||||
// TODO cy.wrap() for promise resolution
|
// // TODO rewrite this test suite since I no longer use fetch for the map
|
||||||
// TODO DRY - variables and data fetching can be done before tests under the first describe block
|
// // TODO add tests for the API once it is active
|
||||||
describe("Unit tests of utils directory", () => {
|
// describe("Unit tests of utils directory", () => {
|
||||||
describe("Retrieve tournament data from DB", () => {
|
// describe("Retrieve tournament data from DB", () => {
|
||||||
let response: Tournament[];
|
// let response: Tournament[];
|
||||||
let results: Tournament[];
|
// let results: Tournament[];
|
||||||
|
//
|
||||||
describe("France", () => {
|
// describe("France", () => {
|
||||||
before(async () => {
|
// before(async () => {
|
||||||
response = await getTournaments("france");
|
// response = await getTournaments("france");
|
||||||
results = response.splice(0, 5);
|
// results = response.splice(0, 5);
|
||||||
});
|
// });
|
||||||
|
//
|
||||||
it("log first 5 results", () => {
|
// it("log first 5 results", () => {
|
||||||
results.forEach((result) => cy.log(JSON.stringify(result)));
|
// results.forEach((result) => cy.log(JSON.stringify(result)));
|
||||||
});
|
// });
|
||||||
|
//
|
||||||
it("check tournament urls are active", () => {
|
// it("check tournament urls are active", () => {
|
||||||
results.forEach((result) => cy.request(result.url));
|
// results.forEach((result) => cy.request(result.url));
|
||||||
});
|
// });
|
||||||
});
|
// });
|
||||||
});
|
// });
|
||||||
|
//
|
||||||
describe("Create layer groups for map markers", () => {
|
// describe("Create layer groups for map markers", () => {
|
||||||
let response: Tournament[];
|
// let response: Tournament[];
|
||||||
let results: Tournament[];
|
// let results: Tournament[];
|
||||||
describe("France", () => {
|
// describe("France", () => {
|
||||||
const timeControls = [
|
// const timeControls = [
|
||||||
{ name: "Cadence Lente", colour: "green" },
|
// { name: "Cadence Lente", colour: "green" },
|
||||||
{ name: "Rapide", colour: "blue" },
|
// { name: "Rapide", colour: "blue" },
|
||||||
{ name: "Blitz", colour: "yellow" },
|
// { name: "Blitz", colour: "yellow" },
|
||||||
{ name: "1h KO", colour: "red" },
|
// { name: "1h KO", colour: "red" },
|
||||||
];
|
// ];
|
||||||
|
//
|
||||||
before(async () => {
|
// before(async () => {
|
||||||
response = await getTournaments("france");
|
// response = await getTournaments("france");
|
||||||
results = response.splice(0, 5);
|
// results = response.splice(0, 5);
|
||||||
});
|
// });
|
||||||
|
//
|
||||||
it("generate layer groups", () => {
|
// it("generate layer groups", () => {
|
||||||
const result = timeControls.map((timeControl) => {
|
// const result = timeControls.map((timeControl) => {
|
||||||
return createLayerGroups(timeControl.name, timeControl.colour, {
|
// return createLayerGroups(timeControl.name, timeControl.colour, {
|
||||||
tournamentData: results,
|
// tournamentData: results,
|
||||||
});
|
// });
|
||||||
});
|
// });
|
||||||
cy.wrap(result.length).should("be.greaterThan", 0);
|
// cy.wrap(result.length).should("be.greaterThan", 0);
|
||||||
});
|
// });
|
||||||
});
|
// });
|
||||||
});
|
// });
|
||||||
});
|
// });
|
||||||
|
|||||||
@@ -1,7 +1,4 @@
|
|||||||
/** @type {import('next').NextConfig} */
|
/** @type {import('next').NextConfig} */
|
||||||
const dotenvExpand = require("dotenv-expand");
|
|
||||||
|
|
||||||
dotenvExpand.expand({ parsed: { ...process.env } });
|
|
||||||
const nextConfig = {};
|
const nextConfig = {};
|
||||||
|
|
||||||
module.exports = nextConfig;
|
module.exports = nextConfig;
|
||||||
|
|||||||
Generated
-9
@@ -13,7 +13,6 @@
|
|||||||
"@types/react-dom": "18.2.4",
|
"@types/react-dom": "18.2.4",
|
||||||
"@vercel/analytics": "^1.0.1",
|
"@vercel/analytics": "^1.0.1",
|
||||||
"autoprefixer": "10.4.14",
|
"autoprefixer": "10.4.14",
|
||||||
"dotenv-expand": "^10.0.0",
|
|
||||||
"eslint": "8.41.0",
|
"eslint": "8.41.0",
|
||||||
"eslint-config-next": "13.4.3",
|
"eslint-config-next": "13.4.3",
|
||||||
"leaflet": "^1.9.4",
|
"leaflet": "^1.9.4",
|
||||||
@@ -3526,14 +3525,6 @@
|
|||||||
"node": ">=12"
|
"node": ">=12"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/dotenv-expand": {
|
|
||||||
"version": "10.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-10.0.0.tgz",
|
|
||||||
"integrity": "sha512-GopVGCpVS1UKH75VKHGuQFqS1Gusej0z4FyQkPdwjil2gNIv+LNsqBlboOzpJFZKVT95GkCyWJbBSdFEFUWI2A==",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=12"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/ecc-jsbn": {
|
"node_modules/ecc-jsbn": {
|
||||||
"version": "0.1.2",
|
"version": "0.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz",
|
||||||
|
|||||||
@@ -18,7 +18,6 @@
|
|||||||
"@types/react-dom": "18.2.4",
|
"@types/react-dom": "18.2.4",
|
||||||
"@vercel/analytics": "^1.0.1",
|
"@vercel/analytics": "^1.0.1",
|
||||||
"autoprefixer": "10.4.14",
|
"autoprefixer": "10.4.14",
|
||||||
"dotenv-expand": "^10.0.0",
|
|
||||||
"eslint": "8.41.0",
|
"eslint": "8.41.0",
|
||||||
"eslint-config-next": "13.4.3",
|
"eslint-config-next": "13.4.3",
|
||||||
"leaflet": "^1.9.4",
|
"leaflet": "^1.9.4",
|
||||||
|
|||||||
@@ -0,0 +1,30 @@
|
|||||||
|
import { Db } from "mongodb";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts date from string into a date to allow ordering
|
||||||
|
*/
|
||||||
|
export const dateOrderingFrance = async (db: Db) => {
|
||||||
|
return await db
|
||||||
|
.collection("tournaments")
|
||||||
|
.aggregate([
|
||||||
|
{
|
||||||
|
$addFields: {
|
||||||
|
dateParts: {
|
||||||
|
$dateFromString: {
|
||||||
|
dateString: "$date",
|
||||||
|
format: "%d/%m/%Y",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
$sort: {
|
||||||
|
dateParts: 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
$unset: "dateParts",
|
||||||
|
},
|
||||||
|
])
|
||||||
|
.toArray();
|
||||||
|
};
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
/**
|
|
||||||
* Retrieves tournament data from /api/tournaments/:country
|
|
||||||
* @remarks The result is cached for the revalidation period in seconds
|
|
||||||
*/
|
|
||||||
export default async function getTournaments(country: string) {
|
|
||||||
const server = process.env.NEXT_PUBLIC_SITE_URL;
|
|
||||||
const res = await fetch(`${server}/api/tournaments/${country}`, {
|
|
||||||
next: { revalidate: 300 },
|
|
||||||
});
|
|
||||||
|
|
||||||
if (res.status !== 200) {
|
|
||||||
throw new Error("Failed to fetch tournament data");
|
|
||||||
}
|
|
||||||
return await res.json();
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user