add docker

This commit is contained in:
Fabrice Lamant
2025-12-06 14:55:13 +01:00
parent 3015fc2e78
commit fef4690b0b
24 changed files with 1186 additions and 446 deletions

2
ui/.gitignore vendored
View File

@ -40,4 +40,4 @@ yarn-error.log*
*.tsbuildinfo
next-env.d.ts
/public/data/
/data/

21
ui/Dockerfile Normal file
View File

@ -0,0 +1,21 @@
FROM node:lts-alpine AS base
WORKDIR /app
COPY package*.json ./
RUN npm install
FROM base AS build
WORKDIR /app
COPY . .
RUN npm run build
FROM node:lts-alpine AS runner
WORKDIR /app
COPY --from=base /app/node_modules ./node_modules
COPY --from=build /app/public ./public
COPY --from=build /app/.next/standalone ./
COPY --from=build /app/.next/static ./.next/static
EXPOSE 3000
ENV PORT=3000
ENV HOSTNAME="0.0.0.0"
CMD ["node", "server.js"]

View File

@ -0,0 +1,24 @@
import { promises as fs } from "fs";
import { NextResponse } from "next/server";
import path from "path";
const DATA_FOLDER = path.resolve("data");
export async function GET(
request: Request,
{ params }: { params: Promise<{ slug?: string[] | undefined }> }
): Promise<NextResponse> {
try {
const { slug } = await params || [];
const filePath = slug ? path.join(DATA_FOLDER, ...slug) : null;
if (!filePath) throw new Error()
const content = await fs.readFile(filePath);
if (!content) throw new Error()
return new NextResponse(content, { status: 200 });
} catch (ex) {
console.log(ex);
return new NextResponse("File not found", { status: 404 });
}
}

View File

@ -1,6 +1,6 @@
export default function Flag({ iso3, name }: { iso3: string; name: string }) {
const iso3to2 = {
const iso3to2: { [key: string]: string } = {
AFG: "AF",
ALA: "AX",
ALB: "AL",

View File

@ -3,7 +3,6 @@
import { loadSchedule } from "../lib/data";
import { useEffect, useState } from "react";
import Flag from "./flag";
import { useSearchParams } from "next/navigation";
import { COPY, COPY_SUCCESS, FILTER_BY_COUNTRY, FILTER_BY_SPORT } from "../lib/text";
import useLocalStorage from "@/lib/local-storage";
@ -52,7 +51,7 @@ interface Calendar {
const COLORS = ['azzurro', 'giallo', 'rosa', 'rosso', 'verde', 'viola'];
export default function Home() {
const qs = useSearchParams();
const qs = typeof window !== 'undefined' ? window.location.search ? new URLSearchParams(window.location.search) : new URLSearchParams() : new URLSearchParams();
const [data, setData] = useState<Calendar | null>(null);
const [language, setLanguage] = useLocalStorage('lang', (navigator.language || 'en').split('-')[0]);
@ -95,7 +94,7 @@ export default function Home() {
const noc = qs.get('noc') || 'calendar';
const sport = qs.get('sport') || 'all-sports';
return `http://${host}/data/${language}/${sport}/${noc}.ics`;
return `http://${host}/api/data/${language}/${sport}/${noc}.ics`;
};
const getColor = (i: number) => COLORS[i % COLORS.length];

View File

@ -1,5 +1,5 @@
export const loadSchedule = async () => {
const response = await fetch('/data/calendar.json');
const response = await fetch('/api/data/calendar.json');
const data = await response.json();
return data;
};

View File

@ -1,7 +1,7 @@
import type { NextConfig } from "next";
const nextConfig: NextConfig = {
/* config options here */
output: "standalone",
};
export default nextConfig;