Compare commits
No commits in common. "cb7143ed3d998978a46a70d701a9332af07d69ec" and "6d6e59ed13a4362c5150a9ea108f100900d46924" have entirely different histories.
cb7143ed3d
...
6d6e59ed13
@ -25,6 +25,6 @@ RUN bun --filter '@ssr/common' build
|
|||||||
COPY --from=depends /app/projects/backend ./projects/backend
|
COPY --from=depends /app/projects/backend ./projects/backend
|
||||||
|
|
||||||
# Lint before starting
|
# Lint before starting
|
||||||
RUN bun --filter 'backend' lint
|
RUN bun --filter 'website' lint
|
||||||
|
|
||||||
CMD ["bun", "run", "--filter", "backend", "start"]
|
CMD ["bun", "run", "--filter", "backend", "start"]
|
||||||
|
@ -12,13 +12,6 @@ export default class AppController {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@Get("/health")
|
|
||||||
public async getHealth() {
|
|
||||||
return {
|
|
||||||
status: "OK",
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
@Get("/statistics")
|
@Get("/statistics")
|
||||||
public async getStatistics() {
|
public async getStatistics() {
|
||||||
return await AppService.getAppStatistics();
|
return await AppService.getAppStatistics();
|
||||||
|
@ -1,27 +0,0 @@
|
|||||||
import ky from "ky";
|
|
||||||
|
|
||||||
type ApiHealth = {
|
|
||||||
online: boolean;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the health of the api server.
|
|
||||||
*
|
|
||||||
* @param url the url of the api
|
|
||||||
*/
|
|
||||||
export async function getApiHealth(url: string): Promise<ApiHealth> {
|
|
||||||
try {
|
|
||||||
await ky
|
|
||||||
.get(url, {
|
|
||||||
cache: "no-cache",
|
|
||||||
})
|
|
||||||
.json();
|
|
||||||
return {
|
|
||||||
online: true,
|
|
||||||
};
|
|
||||||
} catch {
|
|
||||||
return {
|
|
||||||
online: false,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,5 +1,3 @@
|
|||||||
import ky from "ky";
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks if we're in production
|
* Checks if we're in production
|
||||||
*/
|
*/
|
||||||
@ -26,17 +24,3 @@ export function delay(ms: number) {
|
|||||||
export function getPageFromRank(rank: number, itemsPerPage: number) {
|
export function getPageFromRank(rank: number, itemsPerPage: number) {
|
||||||
return Math.floor(rank / itemsPerPage) + 1;
|
return Math.floor(rank / itemsPerPage) + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Fetches data from the given url.
|
|
||||||
*
|
|
||||||
* @param url the url to fetch
|
|
||||||
*/
|
|
||||||
export async function kyFetch<T>(url: string): Promise<T | undefined> {
|
|
||||||
try {
|
|
||||||
return await ky.get<T>(url).json();
|
|
||||||
} catch (error) {
|
|
||||||
console.error(`Error fetching data from ${url}:`, error);
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -1,14 +1,14 @@
|
|||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
|
import ky from "ky";
|
||||||
import { config } from "../../../config";
|
import { config } from "../../../config";
|
||||||
import { AppStatistics } from "@ssr/common/types/backend/app-statistics";
|
import { AppStatistics } from "@ssr/common/types/backend/app-statistics";
|
||||||
import Statistic from "@/components/home/statistic";
|
import Statistic from "@/components/home/statistic";
|
||||||
import { kyFetch } from "@ssr/common/utils/utils";
|
|
||||||
|
|
||||||
export const dynamic = "force-dynamic"; // Always generate the page on load
|
export const dynamic = "force-dynamic"; // Always generate the page on load
|
||||||
|
|
||||||
export default async function HomePage() {
|
export default async function HomePage() {
|
||||||
const statistics = await kyFetch<AppStatistics>(config.siteApi + "/statistics");
|
const statistics = await ky.get(config.siteApi + "/statistics").json<AppStatistics>();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<main className="flex flex-col items-center w-full gap-6 text-center">
|
<main className="flex flex-col items-center w-full gap-6 text-center">
|
||||||
@ -21,12 +21,10 @@ export default async function HomePage() {
|
|||||||
<p>ScoreSaber Reloaded is a website that allows you to track your ScoreSaber data over time.</p>
|
<p>ScoreSaber Reloaded is a website that allows you to track your ScoreSaber data over time.</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{statistics && (
|
|
||||||
<div className="flex items-center flex-col">
|
<div className="flex items-center flex-col">
|
||||||
<p className="font-semibold">Site Statistics</p>
|
<p className="font-semibold">Site Statistics</p>
|
||||||
<Statistic title="Total Tracked Players" value={statistics.trackedPlayers} />
|
<Statistic title="Total Tracked Players" value={statistics.trackedPlayers} />
|
||||||
</div>
|
</div>
|
||||||
)}
|
|
||||||
|
|
||||||
<div className="flex gap-2 flex-wrap">
|
<div className="flex gap-2 flex-wrap">
|
||||||
<Link href="/search">
|
<Link href="/search">
|
||||||
|
@ -14,7 +14,6 @@ import NavBar from "../components/navbar/navbar";
|
|||||||
import { Colors } from "@/common/colors";
|
import { Colors } from "@/common/colors";
|
||||||
import OfflineNetwork from "@/components/offline-network";
|
import OfflineNetwork from "@/components/offline-network";
|
||||||
import Script from "next/script";
|
import Script from "next/script";
|
||||||
import { ApiHealth } from "@/components/api/api-health";
|
|
||||||
|
|
||||||
const siteFont = localFont({
|
const siteFont = localFont({
|
||||||
src: "./fonts/JetBrainsMono.ttf",
|
src: "./fonts/JetBrainsMono.ttf",
|
||||||
@ -80,7 +79,6 @@ export default function RootLayout({
|
|||||||
<ThemeProvider attribute="class" defaultTheme="dark" enableSystem disableTransitionOnChange>
|
<ThemeProvider attribute="class" defaultTheme="dark" enableSystem disableTransitionOnChange>
|
||||||
<QueryProvider>
|
<QueryProvider>
|
||||||
<AnimatePresence>
|
<AnimatePresence>
|
||||||
<ApiHealth />
|
|
||||||
<main className="flex flex-col min-h-screen gap-2 text-white w-full">
|
<main className="flex flex-col min-h-screen gap-2 text-white w-full">
|
||||||
<NavBar />
|
<NavBar />
|
||||||
<div className="z-[1] m-auto flex flex-col flex-grow items-center w-full md:max-w-[1600px]">
|
<div className="z-[1] m-auto flex flex-col flex-grow items-center w-full md:max-w-[1600px]">
|
||||||
|
@ -1,46 +0,0 @@
|
|||||||
"use client";
|
|
||||||
|
|
||||||
import { useQuery } from "@tanstack/react-query";
|
|
||||||
import { useEffect, useRef, useState } from "react";
|
|
||||||
import { getApiHealth } from "@ssr/common/utils/api-utils";
|
|
||||||
import { config } from "../../../config";
|
|
||||||
import { useToast } from "@/hooks/use-toast";
|
|
||||||
import { useIsFirstRender } from "@uidotdev/usehooks";
|
|
||||||
|
|
||||||
export function ApiHealth() {
|
|
||||||
const { toast } = useToast();
|
|
||||||
const firstRender = useIsFirstRender();
|
|
||||||
const [online, setOnline] = useState<boolean>(true);
|
|
||||||
const previousOnlineStatus = useRef<boolean>(true);
|
|
||||||
|
|
||||||
useQuery({
|
|
||||||
queryKey: ["api-health"],
|
|
||||||
queryFn: async () => {
|
|
||||||
const status = (await getApiHealth(config.siteApi)).online;
|
|
||||||
setOnline(status);
|
|
||||||
return status;
|
|
||||||
},
|
|
||||||
refetchInterval: 1000 * 15,
|
|
||||||
});
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (firstRender) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Trigger toast only if the online status changes
|
|
||||||
if (previousOnlineStatus.current !== online) {
|
|
||||||
toast({
|
|
||||||
title: `The API is now ${online ? "Online" : "Offline"}!`,
|
|
||||||
description: online ? "The API has recovered connectivity." : "The API has lost connectivity.",
|
|
||||||
variant: online ? "success" : "destructive",
|
|
||||||
duration: 10_000, // 10 seconds
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update the previous online status
|
|
||||||
previousOnlineStatus.current = online;
|
|
||||||
}, [firstRender, online, toast]);
|
|
||||||
|
|
||||||
return <></>;
|
|
||||||
}
|
|
Reference in New Issue
Block a user