feat: add ability to log and display sanctions

This commit is contained in:
2025-08-25 15:55:48 -07:00
parent a9126ec826
commit 908f22d6aa
17 changed files with 19018 additions and 6 deletions
@@ -2,8 +2,7 @@
<p>Here are the most recent updates for our products and communities.</p>
<p>
If you want to see the full history, check out our
<a href="https://chat.nhcarrigan.com" target="_blank">chat server</a> or our
<a href="https://forum.nhcarrigan.com" target="_blank">forum</a>.
<a href="https://chat.nhcarrigan.com" target="_blank">chat server</a>.
</p>
<div class="announcement" *ngFor="let announcement of announcements">
<hr />
+2
View File
@@ -8,11 +8,13 @@ import { Routes } from "@angular/router";
import { Announcements } from "./announcements/announcements.js";
import { Home } from "./home/home.js";
import { Products } from "./products/products.js";
import { Sanctions } from "./sanctions/sanctions.js";
import { Soon } from "./soon/soon.js";
export const routes: Routes = [
{ component: Home, path: "", pathMatch: "full" },
{ component: Products, path: "products" },
{ component: Announcements, path: "announcements" },
{ component: Sanctions, path: "sanctions" },
{ component: Soon, path: "**" },
];
+2
View File
@@ -9,6 +9,8 @@
<hr />
<a routerLink="/products" class="nav-link">Products</a>
<hr />
<a routerLink="/sanctions" class="nav-link">Sanctions</a>
<hr />
<a routerLink="/account" class="nav-link">Account</a>
<hr />
<a routerLink="/settings" class="nav-link">Settings</a>
+44
View File
@@ -0,0 +1,44 @@
/**
* @copyright nhcarrigan
* @license Naomi's Public License
* @author Naomi Carrigan
*/
import { Injectable } from "@angular/core";
@Injectable({
providedIn: "root",
})
export class SanctionsService {
public constructor() {}
// eslint-disable-next-line @typescript-eslint/class-methods-use-this -- Getter for static URL.
private get url(): string {
return "http://localhost:20000/sanctions";
}
public async getSanctions(): Promise<
Array<{
number: number;
uuid: string;
type: string;
platform: string;
reason: string;
username: string;
createdAt: string;
}>
> {
const response = await fetch(this.url);
if (!response.ok) {
return [];
}
return (await response.json()) as Array<{
number: number;
uuid: string;
type: string;
platform: string;
reason: string;
username: string;
createdAt: string;
}>;
}
}
+33
View File
@@ -0,0 +1,33 @@
hr {
width: 100%;
border: none;
border-top: 1px solid var(--foreground);
margin: 0;
}
:host ::ng-deep ul{
list-style-type: disc;
list-style-position: inside;
}
.sanction {
margin: auto;
margin-bottom: 1em;
width: 90%;
}
.tag {
display: inline-block;
padding: 0 0.5em;
border-radius: 50px;
font-size: 0.8em;
background-color: #e0f7fa;
color: #006064;
}
.date {
font-style: italic;
}
.metadata {
font-size: 0.75rem;
}
+23
View File
@@ -0,0 +1,23 @@
<h1>Sanctions</h1>
<p>Here are the most recent moderation actions taken to keep our community safe.</p>
<p>
If you want to see the full history, check out our
<a href="https://chat.nhcarrigan.com" target="_blank">chat server</a>.
</p>
<div class="sanction" *ngFor="let sanction of sanctions">
<hr />
<h2>Case #{{ sanction.number }}: {{ sanction.type.toUpperCase() }}</h2>
<p>
<span class="tag">{{sanction.platform}}</span>
<span class="date"> {{ sanction.createdAt | date: "mediumDate" }}</span>
</p>
<p>{{ sanction.reason }}</p>
<ul class="metadata">
<li>Username: {{ sanction.username }}</li>
<li>UUID: {{ sanction.uuid }}</li>
</ul>
</div>
<div class="no-sanctions" *ngIf="!sanctions.length">
<p>There are no sanctions at this time.</p>
</div>
+40
View File
@@ -0,0 +1,40 @@
/**
* @copyright nhcarrigan
* @license Naomi's Public License
* @author Naomi Carrigan
*/
import { CommonModule, DatePipe } from "@angular/common";
import { Component } from "@angular/core";
import { SanctionsService } from "../sanctions.js";
@Component({
imports: [ CommonModule, DatePipe ],
selector: "app-sanctions",
styleUrl: "./sanctions.css",
templateUrl: "./sanctions.html",
})
export class Sanctions {
public sanctions: Array<{
number: number;
uuid: string;
type: string;
platform: string;
reason: string;
username: string;
createdAt: string;
}> = [];
public constructor(
private readonly sanctionsService: SanctionsService,
) {
void this.loadSanctions();
}
private async loadSanctions(): Promise<void> {
const sanctions = await this.sanctionsService.getSanctions();
this.sanctions = sanctions.sort((a, b) => {
return b.createdAt > a.createdAt
? 1
: -1;
});
}
}