switch to another frontend framework wheeeeeeeeeeee

This commit is contained in:
sam 2024-09-05 22:29:12 +02:00
parent fa3c1ccaa7
commit c4adf6918c
Signed by: sam
GPG key ID: B4EF20DDE721CAA1
58 changed files with 6246 additions and 1703 deletions

View file

@ -0,0 +1,28 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
export type ApiError = {
status: number;
message: string;
code: ErrorCode;
errors?: ValidationError[];
};
export enum ErrorCode {
InternalServerError = "INTERNAL_SERVER_ERROR",
Forbidden = "FORBIDDEN",
BadRequest = "BAD_REQUEST",
AuthenticationError = "AUTHENTICATION_ERROR",
AuthenticationRequired = "AUTHENTICATION_REQUIRED",
MissingScopes = "MISSING_SCOPES",
GenericApiError = "GENERIC_API_ERROR",
UserNotFound = "USER_NOT_FOUND",
MemberNotFound = "MEMBER_NOT_FOUND",
}
export type ValidationError = {
message: string;
min_length?: number;
max_length?: number;
actual_length?: number;
allowed_values?: any[];
actual_value?: any;
};

View file

@ -0,0 +1,11 @@
export default interface Meta {
version: string;
hash: string;
users: {
total: number;
active_month: number;
active_week: number;
active_day: number;
};
members: number;
}

View file

@ -0,0 +1,13 @@
export type User = {
id: string;
username: string;
display_name: string | null;
bio: string | null;
member_title: string | null;
avatar_url: string | null;
links: string[];
};
export type UserSettings = {
dark_mode: boolean | null;
};

View file

@ -0,0 +1,66 @@
import { parse as parseCookie, serialize as serializeCookie } from "cookie";
import { API_BASE } from "~/env.server";
import { ApiError, ErrorCode } from "./api/error";
export type RequestParams = {
token?: string;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
body?: any;
headers?: Record<string, string>;
};
export default async function serverRequest<T>(
method: string,
path: string,
params: RequestParams = {},
) {
const url = `${API_BASE}/v2${path}`;
const resp = await fetch(url, {
method,
body: params.body ? JSON.stringify(params.body) : undefined,
headers: {
...params.headers,
...(params.token ? { Authorization: params.token } : {}),
"Content-Type": "application/json",
},
});
if (resp.headers.get("Content-Type")?.indexOf("application/json") === -1) {
// If we don't get a JSON response, the server almost certainly encountered an internal error it couldn't recover from
// (that, or the reverse proxy, which should also be treated as a 500 error)
throw {
status: 500,
code: ErrorCode.InternalServerError,
message: "Internal server error",
} as ApiError;
}
if (resp.status < 200 || resp.status >= 400)
throw (await resp.json()) as ApiError;
return (await resp.json()) as T;
}
export function getCookie(
req: Request,
cookieName: string,
): string | undefined {
const header = req.headers.get("Cookie");
if (!header) return undefined;
const cookie = parseCookie(header);
return cookieName in cookie ? cookie[cookieName] : undefined;
}
const YEAR = 365 * 86400;
export const writeCookie = (
cookieName: string,
value: string,
maxAge: number | undefined = YEAR,
) =>
serializeCookie(cookieName, value, {
maxAge,
path: "/",
sameSite: "lax",
httpOnly: true,
});

View file

@ -0,0 +1,23 @@
import { UserSettings } from "./api/user";
import { getCookie } from "./request.server";
export default function getLocalSettings(req: Request): UserSettings {
const settings = { dark_mode: null } as UserSettings;
const theme = getCookie(req, "pronounscc-theme");
switch (theme) {
case "auto":
settings.dark_mode = null;
break;
case "light":
settings.dark_mode = false;
break;
case "dark":
settings.dark_mode = true;
break;
default:
break;
}
return settings;
}