Skip to content
/**
* Handle alerts sent by the server (moderation or internal)
*/
import { IAlert, IAlertKeyedMessages } from "@sc07-canvas/lib/src/net";
import EventEmitter from "eventemitter3";
import { JSX } from "react";
import { toast } from "react-toastify";
/**
* Handles IAlert outside of react
* @param alert
*/
export const handleAlert = (alert: IAlert) => {
switch (alert.is) {
case "toast":
handleToast(alert);
break;
case "modal":
handleModal(alert);
break;
}
};
export const handleDismiss = (id: string) => {
toast.dismiss(id);
};
export interface IDynamicModal {
title: string | JSX.Element;
body: string | JSX.Element;
}
/**
* Dynamic modal event root
*
* These are consumed by src/DynamicModals.tsx
*/
interface IDynamicModalEvents {
showModal: (modal: IDynamicModal) => void;
}
class DynamicModalClass extends EventEmitter<IDynamicModalEvents> {}
export const DynamicModal = new DynamicModalClass();
const getMessage = <T extends keyof IAlertKeyedMessages>(
key: T,
metadata: IAlertKeyedMessages[T]
): { title: string | JSX.Element; body: string | JSX.Element } => {
switch (key) {
case "banned": {
let metadata_ = metadata as IAlertKeyedMessages["banned"];
const until = new Date(metadata_.until);
return {
title: "You have been banned.",
body:
"You will be unbanned in " +
((until.getTime() - Date.now()) / 1000).toFixed(0) +
" seconds",
};
}
case "unbanned": {
return {
title: "You have been unbanned.",
body: "",
};
}
default:
return {
title: "Unknown Message?",
body: "Unknown message: " + key,
};
}
};
const handleToast = (alert: IAlert<"toast">) => {
let Body: JSX.Element;
if ("title" in alert) {
Body = (
<div>
<b>{alert.title}</b>
{alert.body && <> {alert.body}</>}
</div>
);
} else {
const message = getMessage(alert.message_key, alert.metadata);
Body = (
<div>
<b>{message.title}</b>
{message.body}
</div>
);
}
toast(Body, {
toastId: alert.id,
type: alert.severity,
autoClose: alert.autoDismiss ? 5000 : false,
});
};
const handleModal = (alert: IAlert<"modal">) => {
let modal: IDynamicModal;
if ("title" in alert) {
modal = {
title: alert.title,
body: alert.body || "",
};
} else {
const message = getMessage(alert.message_key, alert.metadata);
modal = {
title: message.title,
body: message.body,
};
}
DynamicModal.emit("showModal", modal);
};
This diff is collapsed.
export class CanvasUtils {
static canvasToPanZoomTransform(
x: number,
y: number,
canvas: [width: number, height: number],
useZoom: boolean
) {
let transformX = 0;
let transformY = 0;
if (useZoom) {
// CSS Zoom does not alter this (obviously)
transformX = canvas[0] / 2 - x;
transformY = canvas[1] / 2 - y;
} else {
transformX = canvas[0] / 2 - x;
transformY = canvas[1] / 2 - y;
}
return { transformX, transformY };
}
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
class Recaptcha_ {
load(site_key: string) {
const script = document.createElement("script");
script.setAttribute(
"src",
`https://www.google.com/recaptcha/api.js?render=explicit`
);
document.head.appendChild(script);
script.onload = () => {
grecaptcha.ready(() => {
grecaptcha.render("grecaptcha-badge", {
sitekey: site_key,
badge: "inline",
size: "invisible",
});
console.log("Google Recaptcha Loaded!");
});
};
}
executeChallenge(ack: (token: string) => void) {
console.log("[Recaptcha] Received challenge request...");
grecaptcha.execute().then((token) => {
console.log("[Recaptcha] Sending challenge token back");
ack(token as any);
});
}
}
export const Recaptcha = new Recaptcha_();
This diff is collapsed.
This diff is collapsed.
import { ICanvasPosition } from "../types";
export const Routes = {
canvas: (pos: ICanvasPosition) => {
const params = new URLSearchParams();
params.set("x", pos.x + "");
params.set("y", pos.y + "");
params.set("zoom", pos.zoom + "");
return "/#" + params;
},
};
import * as Sentry from "@sentry/react";
if (__SENTRY_DSN__) {
Sentry.init({
dsn: __SENTRY_DSN__,
environment: import.meta.env.MODE,
tunnel: "/api/_meta",
integrations: [
Sentry.browserTracingIntegration(),
Sentry.replayIntegration(),
],
// Tracing
tracesSampleRate: 1.0, // Capture 100% of the transactions
// Set 'tracePropagationTargets' to control for which URLs distributed tracing should be enabled
tracePropagationTargets: [
"localhost",
new RegExp(
"^" + window.location.protocol + "//" + window.location.host + "/api"
),
],
// Session Replay
replaysSessionSampleRate: 1.0, // This sets the sample rate at 10%. You may want to change it to 100% while in development and then sample at a lower rate in production.
replaysOnErrorSampleRate: 1.0, // If you're not already sampling the entire session, change the sample rate to 100% when sampling sessions where errors occur.
});
console.log("Sentry loaded with", __SENTRY_DSN__);
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
/// <reference types="vite/client" />
interface ImportMetaEnv {
readonly VITE_API_HOST: string;
readonly VITE_INCLUDE_EVENT_INFO: boolean;
}
interface ImportMeta {
readonly env: ImportMetaEnv;
}
declare const __COMMIT_HASH__: string;
declare const __SENTRY_DSN__: string | null;
This diff is collapsed.
This diff is collapsed.
......@@ -9,13 +9,6 @@ export const CanvasLib = new (class {
* @returns Seconds to take to give the pixel
*/
getPixelCooldown(pixelNumber: number, config: ClientConfig) {
return pixelNumber * config.canvas.pixel.cooldown;
// const factorial = (n: number) => (n == 0 ? 1 : n * factorial(n - 1));
// return (
// config.canvas.pixel.cooldown *
// config.canvas.pixel.multiplier *
// (2 + pixelNumber + factorial(pixelNumber))
// );
return config.pallete.pixel_cooldown / 1000;
}
})();
This diff is collapsed.