Merge branch 'main' of https://gitlab.epicnabbo.nl/remco/EpicNext-Cms into codex/housekeeping-complete

This commit is contained in:
Simo committed 2026-08-29 21:16:46 +02:00
commit 3d385d1869
151 files changed
+765 -370

No files matched your search

+1 -1
View File
@@ -32,7 +32,7 @@ const nextConfig: NextConfig = {
reactStrictMode: true,
compress: true,
productionBrowserSourceMaps: false,
serverExternalPackages: ["lzma", "sharp", "pino", "pino-pretty"],
serverExternalPackages: ["lzma-wasm", "sharp", "pino", "pino-pretty"],
async redirects() {
return [
+1 -2
View File
@@ -48,7 +48,7 @@
"jszip": "3.10.1",
"lenis": "1.3.26",
"lucide-react": "1.33.0",
"lzma": "^2.3.2",
"lzma-wasm": "1.0.7",
"motion": "13.1.1",
"music-metadata": "11.15.0",
"mysql2": "3.23.4",
@@ -85,7 +85,6 @@
"tailwindcss": "4.3.3",
"tsx": "4.23.12",
"typescript": "7.0.2",
"vite": "8.2.2",
"vitest": "4.1.11"
}
}
+7 -10
View File
@@ -79,9 +79,9 @@ importers:
lucide-react:
specifier: 1.33.0
version: 1.33.0([email protected])
lzma:
specifier: ^2.3.2
version: 2.3.2
lzma-wasm:
specifier: 1.0.7
version: 1.0.7
motion:
specifier: 13.1.1
version: 13.1.1([email protected]([email protected]))([email protected])
@@ -185,9 +185,6 @@ importers:
typescript:
specifier: 7.0.2
version: 7.0.2
vite:
specifier: 8.2.2
version: 8.2.2(@types/[email protected])([email protected])([email protected])([email protected])([email protected])
vitest:
specifier: 4.1.11
version: 4.1.11(@types/[email protected])(@vitest/[email protected])([email protected](@types/[email protected])([email protected])([email protected])([email protected])([email protected]))
@@ -2450,9 +2447,9 @@ packages:
peerDependencies:
react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0
lzma@2.3.2:
resolution: {integrity: sha512-DcfiawQ1avYbW+hsILhF38IKAlnguc/fjHrychs9hdxe4qLykvhT5VTGNs5YRWgaNePh7NTxGD4uv4gKsRomCQ==}
hasBin: true
lzma[email protected]:
resolution: {integrity: sha512-/fm+kRC7MqF9aCAWU5GwmgWllzM7ehC46aB5Va7V1PAnUl0qSU8ZA2XWk8yOgZbkgL6MWLDyYIVJR+UQziwvUA==}
engines: {node: '>=16.0.0'}
[email protected]:
resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==}
@@ -4593,7 +4590,7 @@ snapshots:
dependencies:
react: 19.2.8
lzma@2.3.2: {}
lzma[email protected]: {}
[email protected]:
dependencies:
+26 -1
View File
@@ -9,7 +9,8 @@ import { logger } from "@/lib/logger";
/**
* Invalidate every CMS JWT for the signed-in user by bumping website_jwt_version,
* revoke personal access tokens, then end the current browser session too.
* revoke personal access tokens, revoke the game SSO ticket, then end the
* current browser session too.
*/
export async function signOutEverywhere(): Promise<void> {
const session = await auth();
@@ -24,6 +25,7 @@ export async function signOutEverywhere(): Promise<void> {
.update(User)
.set({
websiteJwtVersion: sql`${User.websiteJwtVersion} + 1`,
authTicket: "",
})
.where(eq(User.id, userId));
await invalidateJwtVersionCache(userId);
@@ -57,3 +59,26 @@ export async function signOutEverywhere(): Promise<void> {
await signOut({ redirectTo: "/login?signedOutAll=1" });
}
/**
* Log the current user out of the website AND revoke their game SSO ticket.
*
* Without revoking it, a ticket leaked via logs/history/referrers stays valid
* for the emulator after logout. Clearing the ticket makes any future client
* connection with it invalid.
*/
export async function signOutAndRevokeTicket(): Promise<void> {
const session = await auth();
const userId = Number(session?.user?.id);
if (Number.isInteger(userId) && userId > 0) {
try {
await db.update(User).set({ authTicket: "" }).where(eq(User.id, userId));
} catch (err) {
logger.warn("Failed to revoke SSO ticket during sign out", {
userId,
error: err instanceof Error ? err.message : "Unknown",
});
}
}
await signOut({ redirectTo: "/" });
}
+1 -1
View File
@@ -1,5 +1,5 @@
import Link from "next/link";
import { useTranslations } from "next-intl";
import Link from "@/components/link";
import { ContentCard } from "@/components/public/ui";
export const metadata = { title: "Community" };
+1 -1
View File
@@ -1,10 +1,10 @@
"use client";
import { Home, RefreshCw } from "lucide-react";
import Link from "next/link";
import { useTranslations } from "next-intl";
import { useEffect } from "react";
import { ErrorScreen } from "@/components/error-screen";
import Link from "@/components/link";
/**
* Site route-segment error boundary. Renders inside the site shell layout.
+1 -1
View File
@@ -1,8 +1,8 @@
import { and, asc, count, eq, inArray } from "drizzle-orm";
import Image from "next/image";
import Link from "next/link";
import { notFound } from "next/navigation";
import { getTranslations } from "next-intl/server";
import Link from "@/components/link";
import { ContentCard, EmptyState } from "@/components/public/ui";
import { auth } from "@/lib/auth";
import {
+1 -1
View File
@@ -1,7 +1,7 @@
import { count, desc, eq, inArray } from "drizzle-orm";
import Image from "next/image";
import Link from "next/link";
import { getTranslations } from "next-intl/server";
import Link from "@/components/link";
import { ContentCard, EmptyState } from "@/components/public/ui";
import {
db,
+1 -1
View File
@@ -1,8 +1,8 @@
import { headers } from "next/headers";
import Link from "next/link";
import { getTranslations } from "next-intl/server";
import { requestReset } from "@/actions/password-reset";
import { CaptchaWidget } from "@/components/auth/captcha-widget";
import Link from "@/components/link";
import { ContentCard } from "@/components/public/ui";
import { captchaConfig } from "@/lib/services/captcha";
+1 -1
View File
@@ -1,9 +1,9 @@
import { asc, eq, inArray, or } from "drizzle-orm";
import Link from "next/link";
import { redirect } from "next/navigation";
import { getTranslations } from "next-intl/server";
import type { CSSProperties } from "react";
import { removeFriendship } from "@/actions/messenger";
import Link from "@/components/link";
import { ContentCard, EmptyState, OnlineBadge } from "@/components/public/ui";
import { UserAvatarThumbnail } from "@/components/shared/user-avatar-thumbnail";
import { auth } from "@/lib/auth";
@@ -1,9 +1,9 @@
import { and, asc, eq, inArray } from "drizzle-orm";
import Link from "next/link";
import { notFound } from "next/navigation";
import { getTranslations } from "next-intl/server";
import type { CSSProperties } from "react";
import { replyToThread } from "@/actions/social";
import Link from "@/components/link";
import { ContentCard, EmptyState } from "@/components/public/ui";
import { auth } from "@/lib/auth";
import {
@@ -1,9 +1,9 @@
import { eq } from "drizzle-orm";
import Link from "next/link";
import { notFound, redirect } from "next/navigation";
import { getTranslations } from "next-intl/server";
import type { CSSProperties } from "react";
import { postThread } from "@/actions/social";
import Link from "@/components/link";
import { ContentCard } from "@/components/public/ui";
import { auth } from "@/lib/auth";
import { db, Guilds } from "@/lib/db";
+1 -1
View File
@@ -1,8 +1,8 @@
import { and, desc, eq, inArray } from "drizzle-orm";
import Link from "next/link";
import { notFound } from "next/navigation";
import { getTranslations } from "next-intl/server";
import type { CSSProperties } from "react";
import Link from "@/components/link";
import { ContentCard, EmptyState } from "@/components/public/ui";
import { db, Guilds, GuildsForumsThreads, User } from "@/lib/db";
import { formatDate } from "@/lib/format-date";
+1 -1
View File
@@ -1,7 +1,7 @@
import { asc, eq, inArray } from "drizzle-orm";
import Link from "next/link";
import { notFound } from "next/navigation";
import { getTranslations } from "next-intl/server";
import Link from "@/components/link";
import { ContentCard, EmptyState, StatBlock } from "@/components/public/ui";
import { UserAvatarThumbnail } from "@/components/shared/user-avatar-thumbnail";
import { db, Guilds, GuildsMembers, User } from "@/lib/db";
+1 -1
View File
@@ -1,6 +1,6 @@
import { desc } from "drizzle-orm";
import Link from "next/link";
import { getTranslations } from "next-intl/server";
import Link from "@/components/link";
import { ContentCard, EmptyState } from "@/components/public/ui";
import { db, Guilds } from "@/lib/db";
import { excerpt } from "@/lib/format";
+1 -1
View File
@@ -1,7 +1,7 @@
import { asc, eq, ne } from "drizzle-orm";
import Link from "next/link";
import { notFound } from "next/navigation";
import { getTranslations } from "next-intl/server";
import Link from "@/components/link";
import { ContentCard } from "@/components/public/ui";
import { SanitizedHtml } from "@/components/shared/sanitized-html";
import { db, WebsiteHelpCenterCategories } from "@/lib/db";
+1 -1
View File
@@ -1,6 +1,6 @@
import { asc } from "drizzle-orm";
import Link from "next/link";
import { getTranslations } from "next-intl/server";
import Link from "@/components/link";
import { ContentCard, EmptyState } from "@/components/public/ui";
import {
db,
+1 -1
View File
@@ -1,9 +1,9 @@
import { asc, eq, inArray } from "drizzle-orm";
import Link from "next/link";
import { notFound, redirect } from "next/navigation";
import { getTranslations } from "next-intl/server";
import type { CSSProperties } from "react";
import { closeHelpTicket, replyHelpTicket } from "@/actions/help-tickets";
import Link from "@/components/link";
import { ContentCard } from "@/components/public/ui";
import { positiveBigInt } from "@/lib/api";
import { auth } from "@/lib/auth";
+1 -1
View File
@@ -1,9 +1,9 @@
import { desc, eq } from "drizzle-orm";
import Link from "next/link";
import { redirect } from "next/navigation";
import { getTranslations } from "next-intl/server";
import type { CSSProperties } from "react";
import { createTicket } from "@/actions/help-tickets";
import Link from "@/components/link";
import { ContentCard, EmptyState, StatBlock } from "@/components/public/ui";
import { auth } from "@/lib/auth";
import { db, WebsiteHelpCenterTickets } from "@/lib/db";
+1 -1
View File
@@ -1,6 +1,6 @@
import { desc, eq } from "drizzle-orm";
import Link from "next/link";
import { getTranslations } from "next-intl/server";
import Link from "@/components/link";
import { ContentCard, EmptyState, RankBadge } from "@/components/public/ui";
import {
CurrencyIcon,
+1 -1
View File
@@ -1,11 +1,11 @@
import { count, desc, eq } from "drizzle-orm";
import { headers } from "next/headers";
import Image from "next/image";
import Link from "next/link";
import { getTranslations } from "next-intl/server";
import { LoginForm } from "@/components/auth/login-form";
import { Clock } from "@/components/clock";
import { LanguageSwitcher } from "@/components/language-switcher";
import Link from "@/components/link";
import { Reveal } from "@/components/motion-reveal";
import { UserAvatarThumbnail } from "@/components/shared/user-avatar-thumbnail";
import { SurfaceCard } from "@/components/surface-card";
+1 -2
View File
@@ -1,9 +1,9 @@
import { and, asc, count, desc, eq, gt, or } from "drizzle-orm";
import Image from "next/image";
import Link from "next/link";
import { redirect } from "next/navigation";
import type { CSSProperties, ReactNode } from "react";
import { claimReferral } from "@/actions/referral";
import Link from "@/components/link";
import { Reveal } from "@/components/motion-reveal";
import { UserAvatarThumbnail } from "@/components/shared/user-avatar-thumbnail";
@@ -282,7 +282,6 @@ export default async function MePage({
/>
<Link
href="/client"
prefetch={false}
className="btn-shine flex items-center justify-center gap-1.5 rounded-xl border py-2 px-4 font-extrabold text-xs transition-all duration-200 hover:scale-[1.02] active:scale-95 shadow-lg"
style={{
background: "var(--color-primary)",
+1 -1
View File
@@ -1,5 +1,4 @@
import { desc, eq, inArray, or } from "drizzle-orm";
import Link from "next/link";
import { redirect } from "next/navigation";
import { getTranslations } from "next-intl/server";
import type { CSSProperties } from "react";
@@ -8,6 +7,7 @@ import {
declineFriendRequest,
sendOfflineMessage,
} from "@/actions/messenger";
import Link from "@/components/link";
import { ContentCard, EmptyState } from "@/components/public/ui";
import { UserAvatarThumbnail } from "@/components/shared/user-avatar-thumbnail";
import { auth } from "@/lib/auth";
+1 -1
View File
@@ -1,11 +1,11 @@
import { and, asc, eq, inArray } from "drizzle-orm";
import type { Metadata } from "next";
import Link from "next/link";
import { notFound } from "next/navigation";
import { getTranslations } from "next-intl/server";
import type { CSSProperties } from "react";
import { postComment } from "@/actions/article-comments";
import { toggleReaction } from "@/actions/article-reactions";
import Link from "@/components/link";
import { ContentCard, EmptyState } from "@/components/public/ui";
import { SanitizedHtml } from "@/components/shared/sanitized-html";
import { auth } from "@/lib/auth";
+1 -1
View File
@@ -1,6 +1,6 @@
import Image from "next/image";
import Link from "next/link";
import { getTranslations } from "next-intl/server";
import Link from "@/components/link";
import { ContentCard, EmptyState } from "@/components/public/ui";
import { excerpt } from "@/lib/format";
import { formatDate } from "@/lib/format-date";
+1 -1
View File
@@ -1,7 +1,6 @@
import { count, desc, eq } from "drizzle-orm";
import { headers } from "next/headers";
import Image from "next/image";
import Link from "next/link";
import { redirect } from "next/navigation";
import { getTranslations } from "next-intl/server";
import { AmbientOrbs } from "@/components/ambient-orbs";
@@ -9,6 +8,7 @@ import { AnimatedCounter } from "@/components/animated-counter";
import { HomeLoginForm } from "@/components/auth/home-login-form";
import { Clock } from "@/components/clock";
import { LanguageSwitcher } from "@/components/language-switcher";
import Link from "@/components/link";
import { Reveal } from "@/components/motion-reveal";
import { UserAvatarThumbnail } from "@/components/shared/user-avatar-thumbnail";
import { SurfaceCard } from "@/components/surface-card";
+1 -1
View File
@@ -1,7 +1,7 @@
import { and, asc, eq, inArray } from "drizzle-orm";
import Link from "next/link";
import { notFound } from "next/navigation";
import { getTranslations } from "next-intl/server";
import Link from "@/components/link";
import { ContentCard, EmptyState } from "@/components/public/ui";
import { auth } from "@/lib/auth";
import {
+1 -1
View File
@@ -1,6 +1,6 @@
import { and, count, desc, inArray, isNull, lte, or } from "drizzle-orm";
import Link from "next/link";
import { getTranslations } from "next-intl/server";
import Link from "@/components/link";
import { ContentCard, EmptyState } from "@/components/public/ui";
import { db, WebsitePoll, WebsitePollQuestion } from "@/lib/db";
import { excerpt } from "@/lib/format";
+1 -1
View File
@@ -1,7 +1,7 @@
import { eq } from "drizzle-orm";
import Link from "next/link";
import { notFound } from "next/navigation";
import { getTranslations } from "next-intl/server";
import Link from "@/components/link";
import { ContentCard } from "@/components/public/ui";
import { db, RadioContests } from "@/lib/db";
import { formatDate } from "@/lib/format-date";
+1 -1
View File
@@ -1,6 +1,6 @@
import { desc, eq } from "drizzle-orm";
import Link from "next/link";
import { getTranslations } from "next-intl/server";
import Link from "@/components/link";
import { ContentCard, EmptyState } from "@/components/public/ui";
import { db, RadioContests } from "@/lib/db";
import { formatDate } from "@/lib/format-date";
+1 -1
View File
@@ -1,7 +1,7 @@
import { eq } from "drizzle-orm";
import Link from "next/link";
import { notFound } from "next/navigation";
import { getTranslations } from "next-intl/server";
import Link from "@/components/link";
import { ContentCard } from "@/components/public/ui";
import { db, RadioGiveaways } from "@/lib/db";
import { formatDate } from "@/lib/format-date";
+1 -1
View File
@@ -1,6 +1,6 @@
import { desc, eq } from "drizzle-orm";
import Link from "next/link";
import { getTranslations } from "next-intl/server";
import Link from "@/components/link";
import { ContentCard, EmptyState } from "@/components/public/ui";
import { db, RadioGiveaways } from "@/lib/db";
import { formatDate } from "@/lib/format-date";
+1 -1
View File
@@ -1,6 +1,6 @@
import Link from "next/link";
import { getTranslations } from "next-intl/server";
import type { ReactNode } from "react";
import Link from "@/components/link";
const RADIO_SIDEBAR_LINKS = [
{ key: "schedule", href: "/radio/schedule", icon: "🗓️" },
+1 -1
View File
@@ -1,6 +1,6 @@
import { sql } from "drizzle-orm";
import Link from "next/link";
import { getTranslations } from "next-intl/server";
import Link from "@/components/link";
import { ContentCard, EmptyState, RankBadge } from "@/components/public/ui";
import { UserAvatarThumbnail } from "@/components/shared/user-avatar-thumbnail";
import { db } from "@/lib/db";
+1 -1
View File
@@ -1,6 +1,6 @@
import { asc, eq, inArray } from "drizzle-orm";
import Link from "next/link";
import { getTranslations } from "next-intl/server";
import Link from "@/components/link";
import { ContentCard, EmptyState, OnlineBadge } from "@/components/public/ui";
import { db, RadioSchedules, User } from "@/lib/db";
import { siteSettings } from "@/lib/services/site-settings";
+1 -1
View File
@@ -1,6 +1,6 @@
import { desc } from "drizzle-orm";
import Link from "next/link";
import { getTranslations } from "next-intl/server";
import Link from "@/components/link";
import {
ContentCard,
EmptyState,
+1 -1
View File
@@ -1,7 +1,7 @@
import { asc, eq } from "drizzle-orm";
import Link from "next/link";
import { notFound } from "next/navigation";
import { getTranslations } from "next-intl/server";
import Link from "@/components/link";
import { ContentCard, EmptyState } from "@/components/public/ui";
import { db, WebsiteRareValueCategories, WebsiteRareValues } from "@/lib/db";
import { siteSettings } from "@/lib/services/site-settings";
+1 -1
View File
@@ -1,6 +1,6 @@
import { asc, count } from "drizzle-orm";
import Link from "next/link";
import { getTranslations } from "next-intl/server";
import Link from "@/components/link";
import { ContentCard, EmptyState } from "@/components/public/ui";
import { db, WebsiteRareValueCategories, WebsiteRareValues } from "@/lib/db";
import { siteSettings } from "@/lib/services/site-settings";
+1 -1
View File
@@ -1,11 +1,11 @@
import { count, desc, eq } from "drizzle-orm";
import { headers } from "next/headers";
import Image from "next/image";
import Link from "next/link";
import { getTranslations } from "next-intl/server";
import { RegisterForm } from "@/components/auth/register-form";
import { Clock } from "@/components/clock";
import { LanguageSwitcher } from "@/components/language-switcher";
import Link from "@/components/link";
import { Reveal } from "@/components/motion-reveal";
import { UserAvatarThumbnail } from "@/components/shared/user-avatar-thumbnail";
import { SurfaceCard } from "@/components/surface-card";
+1 -1
View File
@@ -1,6 +1,6 @@
import Link from "next/link";
import { getTranslations } from "next-intl/server";
import { resetPassword } from "@/actions/password-reset";
import Link from "@/components/link";
import { ContentCard } from "@/components/public/ui";
export default async function ResetPage({
+1 -1
View File
@@ -1,7 +1,7 @@
import { eq } from "drizzle-orm";
import type { Metadata } from "next";
import Link from "next/link";
import { notFound } from "next/navigation";
import Link from "@/components/link";
import { ContentCard, EmptyState, StatBlock } from "@/components/public/ui";
import { db, Rooms, User } from "@/lib/db";
+1 -1
View File
@@ -1,6 +1,6 @@
import { and, eq, like } from "drizzle-orm";
import type { Metadata } from "next";
import Link from "next/link";
import Link from "@/components/link";
import { UserAvatarThumbnail } from "@/components/shared/user-avatar-thumbnail";
import { SurfaceCard } from "@/components/surface-card";
import { db, Rooms, User } from "@/lib/db";
+1 -1
View File
@@ -1,5 +1,4 @@
import { eq } from "drizzle-orm";
import Link from "next/link";
import { redirect } from "next/navigation";
import { getTranslations } from "next-intl/server";
import {
@@ -7,6 +6,7 @@ import {
confirmTwoFactor,
disableTwoFactor,
} from "@/actions/twofactor";
import Link from "@/components/link";
import { ContentCard } from "@/components/public/ui";
import { env } from "@/env";
import { auth } from "@/lib/auth";
+1 -1
View File
@@ -1,9 +1,9 @@
import { eq } from "drizzle-orm";
import Image from "next/image";
import Link from "next/link";
import { redirect } from "next/navigation";
import { getTranslations } from "next-intl/server";
import { updateMotto } from "@/actions/user-settings";
import Link from "@/components/link";
import { Reveal } from "@/components/motion-reveal";
import { SurfaceCard } from "@/components/surface-card";
import { auth } from "@/lib/auth";
+1 -1
View File
@@ -1,8 +1,8 @@
import { asc, eq } from "drizzle-orm";
import Link from "next/link";
import { getTranslations } from "next-intl/server";
import type { CSSProperties } from "react";
import { buyShopArticle } from "@/actions/shop";
import Link from "@/components/link";
import { ContentCard, EmptyState } from "@/components/public/ui";
import { CurrencyIcon } from "@/components/shared/currency-icon";
import { auth } from "@/lib/auth";
+1 -1
View File
@@ -1,6 +1,6 @@
import { asc, desc, eq, gte } from "drizzle-orm";
import Link from "next/link";
import { getTranslations } from "next-intl/server";
import Link from "@/components/link";
import { ContentCard, EmptyState } from "@/components/public/ui";
import { db, User, WebsiteTeams } from "@/lib/db";
import { siteSettings } from "@/lib/services/site-settings";
+1 -1
View File
@@ -1,11 +1,11 @@
import { and, asc, desc, eq, inArray, or } from "drizzle-orm";
import type { Metadata } from "next";
import Link from "next/link";
import { notFound } from "next/navigation";
import { getTranslations } from "next-intl/server";
import type { CSSProperties } from "react";
import { postGuestbook } from "@/actions/guestbook";
import { sendFriendRequest } from "@/actions/social";
import Link from "@/components/link";
import {
ContentCard,
EmptyState,
+1 -1
View File
@@ -1,8 +1,8 @@
import { eq } from "drizzle-orm";
import { CheckCircle2, Clock, MailX } from "lucide-react";
import Link from "next/link";
import { getTranslations } from "next-intl/server";
import { isValidVerificationToken } from "@/actions/email-verify";
import Link from "@/components/link";
import { SurfaceCard } from "@/components/surface-card";
import { db, User } from "@/lib/db";
+1 -1
View File
@@ -1,9 +1,9 @@
import { eq } from "drizzle-orm";
import { Megaphone } from "lucide-react";
import Link from "next/link";
import { notFound, redirect } from "next/navigation";
import { getTranslations } from "next-intl/server";
import { updateAd } from "@/actions/admin-ads";
import Link from "@/components/link";
import { Button } from "@/components/ui/button";
import { db, WebsiteAds } from "@/lib/db";
import { canAccess, getAdminContext, PERMS } from "@/lib/permissions";
+1 -1
View File
@@ -1,10 +1,10 @@
"use client";
import { Trash2 } from "lucide-react";
import Link from "next/link";
import { useTranslations } from "next-intl";
import { deleteAd } from "@/actions/admin-ads";
import { useConfirmDialog } from "@/components/admin/confirm-dialog";
import Link from "@/components/link";
import { Button } from "@/components/ui/button";
import { useServerAction } from "@/hooks/use-server-action";
+1 -1
View File
@@ -1,7 +1,7 @@
import { Megaphone } from "lucide-react";
import Link from "next/link";
import { redirect } from "next/navigation";
import { createAd } from "@/actions/admin-ads";
import Link from "@/components/link";
import { Button } from "@/components/ui/button";
import { canAccess, getAdminContext, PERMS } from "@/lib/permissions";
+1 -1
View File
@@ -1,8 +1,8 @@
import { desc } from "drizzle-orm";
import Link from "next/link";
import { redirect } from "next/navigation";
import { getTranslations } from "next-intl/server";
import { StatusCard } from "@/components/admin/dashboard";
import Link from "@/components/link";
import { Button } from "@/components/ui/button";
import { db, WebsiteAds } from "@/lib/db";
import { formatDate } from "@/lib/format-date";
+1 -1
View File
@@ -1,9 +1,9 @@
import { desc, inArray } from "drizzle-orm";
import Link from "next/link";
import { redirect } from "next/navigation";
import { getTranslations } from "next-intl/server";
import { dismissApplication } from "@/actions/admin-applications";
import { StatusCard } from "@/components/admin/dashboard";
import Link from "@/components/link";
import { Button } from "@/components/ui/button";
import { db, User, WebsiteStaffApplications } from "@/lib/db";
import { formatDate } from "@/lib/format-date";
+1 -1
View File
@@ -1,10 +1,10 @@
import { eq } from "drizzle-orm";
import { Newspaper } from "lucide-react";
import Link from "next/link";
import { notFound, redirect } from "next/navigation";
import { getTranslations } from "next-intl/server";
import { deleteArticle, updateArticle } from "@/actions/admin-articles";
import { ArticleForm } from "@/components/admin/article-form";
import Link from "@/components/link";
import { Button } from "@/components/ui/button";
import { db, WebsiteArticles } from "@/lib/db";
import { canAccess, getAdminContext, PERMS } from "@/lib/permissions";
+1 -1
View File
@@ -1,9 +1,9 @@
import { Newspaper } from "lucide-react";
import Link from "next/link";
import { redirect } from "next/navigation";
import { getTranslations } from "next-intl/server";
import { createArticle } from "@/actions/admin-articles";
import { ArticleForm } from "@/components/admin/article-form";
import Link from "@/components/link";
import { canAccess, getAdminContext, PERMS } from "@/lib/permissions";
export default async function NewArticle({
+1 -1
View File
@@ -1,11 +1,11 @@
import { desc, inArray } from "drizzle-orm";
import { Newspaper } from "lucide-react";
import Link from "next/link";
import { redirect } from "next/navigation";
import { getTranslations } from "next-intl/server";
import { AdminPageShell } from "@/components/admin/admin-page-shell";
import { ArticleCard } from "@/components/admin/article-card";
import { StatusCard } from "@/components/admin/dashboard";
import Link from "@/components/link";
import { Button } from "@/components/ui/button";
import { db, User, WebsiteArticles } from "@/lib/db";
import { formatDate } from "@/lib/format-date";
+1 -1
View File
@@ -1,7 +1,7 @@
import { asc, eq } from "drizzle-orm";
import Link from "next/link";
import { notFound, redirect } from "next/navigation";
import { getTranslations } from "next-intl/server";
import Link from "@/components/link";
import { CalendarCampaigns, CalendarRewards, db } from "@/lib/db";
import { formatDate } from "@/lib/format-date";
import { canAccess, getAdminContext, PERMS } from "@/lib/permissions";
+1 -1
View File
@@ -1,8 +1,8 @@
import { count, desc } from "drizzle-orm";
import Link from "next/link";
import { redirect } from "next/navigation";
import { getTranslations } from "next-intl/server";
import { StatusCard } from "@/components/admin/dashboard";
import Link from "@/components/link";
import { CalendarCampaigns, CalendarRewards, db } from "@/lib/db";
import { formatDate } from "@/lib/format-date";
import { canAccess, getAdminContext, PERMS } from "@/lib/permissions";
@@ -12,7 +12,6 @@ import {
Settings,
Trash2,
} from "lucide-react";
import Link from "next/link";
import { useEffect, useRef, useState } from "react";
import { deleteCatalogPage, updateCatalogPage } from "@/actions/catalog";
import { CatalogImagePicker } from "@/components/admin/catalog/catalog-image-picker";
@@ -20,6 +19,7 @@ import { IconPicker } from "@/components/admin/catalog/icon-picker";
import { ImagePreview } from "@/components/admin/catalog-manager/image-preview";
import { CatalogIcon, LAYOUT_COLORS } from "@/components/admin/catalog-tree";
import { useConfirmDialog } from "@/components/admin/confirm-dialog";
import Link from "@/components/link";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
+1 -1
View File
@@ -1,8 +1,8 @@
import { asc, eq } from "drizzle-orm";
import { ChevronRight } from "lucide-react";
import Link from "next/link";
import { notFound, redirect } from "next/navigation";
import { Fragment } from "react";
import Link from "@/components/link";
import { CatalogPages, db } from "@/lib/db";
import { canAccess, getAdminContext, PERMS } from "@/lib/permissions";
import { loadCatalogItemsData } from "@/lib/services/catalog-items-loader";
@@ -10,7 +10,6 @@ import {
Save,
Trash2,
} from "lucide-react";
import Link from "next/link";
import { useEffect, useRef, useState } from "react";
import {
createBcItem,
@@ -19,6 +18,7 @@ import {
updateBcPage,
} from "@/actions/catalog-bc";
import { useConfirmDialog } from "@/components/admin/confirm-dialog";
import Link from "@/components/link";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
+1 -1
View File
@@ -1,10 +1,10 @@
"use client";
import { Pencil } from "lucide-react";
import Link from "next/link";
import { deleteCatalogPage, toggleCatalogPage } from "@/actions/catalog";
import { deleteBcTreePage, toggleBcPage } from "@/actions/catalog-bc";
import { DataTable } from "@/components/admin/data-table";
import Link from "@/components/link";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import { useServerAction } from "@/hooks/use-server-action";
+1 -1
View File
@@ -1,8 +1,8 @@
import { count, desc, eq, gte } from "drizzle-orm";
import { AlertTriangle, Database, HeartPulse, Server } from "lucide-react";
import Link from "next/link";
import { redirect } from "next/navigation";
import { getTranslations } from "next-intl/server";
import Link from "@/components/link";
import { Badge } from "@/components/ui/badge";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { fetchOpsHealth } from "@/lib/admin/ops-health";
+1 -1
View File
@@ -1,9 +1,9 @@
"use client";
import { LayoutDashboard, RefreshCw } from "lucide-react";
import Link from "next/link";
import { useTranslations } from "next-intl";
import { useEffect } from "react";
import Link from "@/components/link";
import { Button } from "@/components/ui/button";
/**
+1 -1
View File
@@ -1,11 +1,11 @@
"use client";
import { Pencil, Trash2 } from "lucide-react";
import Link from "next/link";
import { useTranslations } from "next-intl";
import { deleteEvent } from "@/actions/events";
import { useConfirmDialog } from "@/components/admin/confirm-dialog";
import { DataTable } from "@/components/admin/data-table";
import Link from "@/components/link";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import { useServerAction } from "@/hooks/use-server-action";
+1 -1
View File
@@ -1,6 +1,6 @@
import { count, desc, eq, like } from "drizzle-orm";
import Link from "next/link";
import { getTranslations } from "next-intl/server";
import Link from "@/components/link";
import { Button } from "@/components/ui/button";
import { fetchAdminList } from "@/lib/admin-list";
import { db, WebsiteEvent, WebsiteEventType } from "@/lib/db";
+1 -1
View File
@@ -1,8 +1,8 @@
import { asc, count, eq, inArray } from "drizzle-orm";
import Link from "next/link";
import { notFound, redirect } from "next/navigation";
import { getTranslations } from "next-intl/server";
import { disbandGuild } from "@/actions/admin-guilds";
import Link from "@/components/link";
import { Button } from "@/components/ui/button";
import { db, Guilds, GuildsForumsThreads, GuildsMembers, User } from "@/lib/db";
import { formatDate } from "@/lib/format-date";
+1 -1
View File
@@ -1,11 +1,11 @@
import { count, desc, eq, inArray, like, or } from "drizzle-orm";
import { Shield } from "lucide-react";
import Link from "next/link";
import { redirect } from "next/navigation";
import { getTranslations } from "next-intl/server";
import { AdminPageShell } from "@/components/admin/admin-page-shell";
import { AdminSimplePager } from "@/components/admin/admin-simple-pager";
import { StatusCard } from "@/components/admin/dashboard";
import Link from "@/components/link";
import { Button } from "@/components/ui/button";
import { calcPagination, parseListParams } from "@/lib/admin-helpers";
import { db, Guilds, GuildsMembers, User } from "@/lib/db";
+1 -1
View File
@@ -1,8 +1,8 @@
import { eq } from "drizzle-orm";
import { HelpCircle } from "lucide-react";
import Link from "next/link";
import { notFound, redirect } from "next/navigation";
import { deleteHelpQuestion, updateHelpQuestion } from "@/actions/admin-help";
import Link from "@/components/link";
import { Button } from "@/components/ui/button";
import { db, WebsiteHelpCenterCategories } from "@/lib/db";
import { canAccess, getAdminContext, PERMS } from "@/lib/permissions";
+1 -1
View File
@@ -1,7 +1,7 @@
import { HelpCircle } from "lucide-react";
import Link from "next/link";
import { redirect } from "next/navigation";
import { createHelpQuestion } from "@/actions/admin-help";
import Link from "@/components/link";
import { Button } from "@/components/ui/button";
import { canAccess, getAdminContext, PERMS } from "@/lib/permissions";
+1 -1
View File
@@ -1,8 +1,8 @@
import { asc } from "drizzle-orm";
import Link from "next/link";
import { redirect } from "next/navigation";
import { getTranslations } from "next-intl/server";
import { StatusCard } from "@/components/admin/dashboard";
import Link from "@/components/link";
import { Button } from "@/components/ui/button";
import { db, WebsiteHelpCenterCategories } from "@/lib/db";
import { canAccess, getAdminContext, PERMS } from "@/lib/permissions";
@@ -1,7 +1,6 @@
"use client";
import { ArrowLeft, Loader2, Mail, Send, Shield, User } from "lucide-react";
import Link from "next/link";
import { useTranslations } from "next-intl";
import { useEffect, useRef, useState } from "react";
import {
@@ -10,6 +9,7 @@ import {
reopenHelpCenterTicket,
replyHelpCenterTicket,
} from "@/actions/admin-help-tickets";
import Link from "@/components/link";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
@@ -1,8 +1,8 @@
"use client";
import Link from "next/link";
import { useTranslations } from "next-intl";
import { DataTable } from "@/components/admin/data-table";
import Link from "@/components/link";
import { Badge } from "@/components/ui/badge";
import type { DataTableColumn, PaginatedResult } from "@/types/common";
+1 -1
View File
@@ -1,7 +1,7 @@
import { asc, eq } from "drizzle-orm";
import Link from "next/link";
import { redirect } from "next/navigation";
import { getTranslations } from "next-intl/server";
import Link from "@/components/link";
import {
AclModelPermission,
AclPermission,
@@ -1,10 +1,10 @@
"use client";
import Link from "next/link";
import { useRouter } from "next/navigation";
import { useTranslations } from "next-intl";
import { useState } from "react";
import { updateItemsBase } from "@/actions/items-base";
import Link from "@/components/link";
import { Button } from "@/components/ui/button";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { Input } from "@/components/ui/input";
+1 -1
View File
@@ -1,8 +1,8 @@
"use client";
import { Eye, Package, Pencil } from "lucide-react";
import Link from "next/link";
import { DataTable } from "@/components/admin/data-table";
import Link from "@/components/link";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import type { DataTableColumn, PaginatedResult } from "@/types/common";
+1 -1
View File
@@ -1,6 +1,5 @@
import { eq } from "drizzle-orm";
import { LogOut } from "lucide-react";
import Link from "next/link";
import { redirect } from "next/navigation";
import { getTranslations } from "next-intl/server";
import type { ReactNode } from "react";
@@ -9,6 +8,7 @@ import { AdminMobileWrapper } from "@/components/admin/admin-mobile-wrapper";
import { AdminSidebarNav } from "@/components/admin/admin-sidebar-nav";
import { AdminTopbar } from "@/components/admin/admin-topbar";
import { LanguageSwitcher } from "@/components/language-switcher";
import Link from "@/components/link";
import { ThemeSwitcher } from "@/components/theme-switcher";
import { requireStaff } from "@/lib/admin/guard";
import { collectNavPermissionSlugs } from "@/lib/admin-nav";
+1 -1
View File
@@ -1,12 +1,12 @@
import { count, desc, eq, inArray } from "drizzle-orm";
import { Store } from "lucide-react";
import Link from "next/link";
import { redirect } from "next/navigation";
import { getTranslations } from "next-intl/server";
import { cancelMarketplaceListing } from "@/actions/admin-marketplace";
import { AdminPageShell } from "@/components/admin/admin-page-shell";
import { AdminSimplePager } from "@/components/admin/admin-simple-pager";
import { StatusCard } from "@/components/admin/dashboard";
import Link from "@/components/link";
import { Button } from "@/components/ui/button";
import { calcPagination, parseListParams } from "@/lib/admin-helpers";
import { db, MarketplaceItems, User } from "@/lib/db";
@@ -11,7 +11,6 @@ import {
VolumeX,
Zap,
} from "lucide-react";
import Link from "next/link";
import { useState } from "react";
import {
assignCfhTicket,
@@ -21,6 +20,7 @@ import {
quickMute,
updateCfhState,
} from "@/actions/moderation";
import Link from "@/components/link";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
+1 -1
View File
@@ -1,8 +1,8 @@
"use client";
import Link from "next/link";
import { useTranslations } from "next-intl";
import { DataTable } from "@/components/admin/data-table";
import Link from "@/components/link";
import { Badge } from "@/components/ui/badge";
import type { DataTableColumn, PaginatedResult } from "@/types/common";
+1 -1
View File
@@ -8,9 +8,9 @@ import {
Shield,
User as UserIcon,
} from "lucide-react";
import Link from "next/link";
import { redirect } from "next/navigation";
import { StatsCard } from "@/components/admin/stats-card";
import Link from "@/components/link";
import { Badge } from "@/components/ui/badge";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { getMinStaffRank } from "@/lib/admin/min-staff-rank";
+1 -1
View File
@@ -1,6 +1,6 @@
import { and, count, desc, gte, inArray, like } from "drizzle-orm";
import Link from "next/link";
import { redirect } from "next/navigation";
import Link from "@/components/link";
import { AvatarImage } from "@/components/shared/avatar-image";
import { Badge } from "@/components/ui/badge";
import { Card, CardContent } from "@/components/ui/card";
+1 -1
View File
@@ -7,9 +7,9 @@ import {
Newspaper,
Users,
} from "lucide-react";
import Link from "next/link";
import { getTranslations } from "next-intl/server";
import { StatusCard } from "@/components/admin/dashboard";
import Link from "@/components/link";
import { unixNow } from "@/lib/bans";
import { Ban, db, StaffActivities, User, WebsiteArticles } from "@/lib/db";
import { formatDate } from "@/lib/format-date";
@@ -13,13 +13,13 @@ import {
Terminal,
UserCheck,
} from "lucide-react";
import Link from "next/link";
import { useMemo, useState } from "react";
import { toast } from "sonner";
import {
saveRank as saveRankAction,
setCmsPermissions,
} from "@/actions/permissions";
import Link from "@/components/link";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
@@ -11,7 +11,6 @@ import {
UserCheck,
Users,
} from "lucide-react";
import Link from "next/link";
import { useState } from "react";
import { toast } from "sonner";
import {
@@ -19,6 +18,7 @@ import {
deleteRank,
repairAdminNavAclGrants,
} from "@/actions/permissions";
import Link from "@/components/link";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import {
+1 -1
View File
@@ -1,11 +1,11 @@
import { count, desc, inArray } from "drizzle-orm";
import { Camera } from "lucide-react";
import Link from "next/link";
import { redirect } from "next/navigation";
import { getTranslations } from "next-intl/server";
import { deletePhoto } from "@/actions/admin-photos";
import { AdminPageShell } from "@/components/admin/admin-page-shell";
import { StatusCard } from "@/components/admin/dashboard";
import Link from "@/components/link";
import { Button } from "@/components/ui/button";
import { calcPagination, parseListParams } from "@/lib/admin-helpers";
import { CameraWeb, db, User } from "@/lib/db";
+1 -1
View File
@@ -1,6 +1,6 @@
import { count, desc, like } from "drizzle-orm";
import Link from "next/link";
import { getTranslations } from "next-intl/server";
import Link from "@/components/link";
import { Button } from "@/components/ui/button";
import { fetchAdminList } from "@/lib/admin-list";
import { db, WebsitePoll } from "@/lib/db";
+1 -1
View File
@@ -1,11 +1,11 @@
"use client";
import { Pencil, Trash2 } from "lucide-react";
import Link from "next/link";
import { useTranslations } from "next-intl";
import { deletePoll } from "@/actions/polls";
import { useConfirmDialog } from "@/components/admin/confirm-dialog";
import { DataTable } from "@/components/admin/data-table";
import Link from "@/components/link";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import { useServerAction } from "@/hooks/use-server-action";
+1 -1
View File
@@ -1,6 +1,6 @@
import Link from "next/link";
import { getTranslations } from "next-intl/server";
import { StatusCard } from "@/components/admin/dashboard";
import Link from "@/components/link";
import { Button } from "@/components/ui/button";
import { resolveHotelName } from "@/lib/hotel-name";
import { siteSettings } from "@/lib/services/site-settings";
@@ -17,7 +17,6 @@ import {
Users,
UserX,
} from "lucide-react";
import Link from "next/link";
import { useMemo, useState } from "react";
import {
bulkDeleteRoomItems,
@@ -25,6 +24,7 @@ import {
roomRconAction,
} from "@/actions/rooms";
import { useConfirmDialog } from "@/components/admin/confirm-dialog";
import Link from "@/components/link";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import { Card, CardContent } from "@/components/ui/card";
+1 -1
View File
@@ -1,7 +1,7 @@
import { DoorOpen, Eye } from "lucide-react";
import Link from "next/link";
import { redirect } from "next/navigation";
import { AdminBreadcrumb } from "@/components/admin/admin-breadcrumb";
import Link from "@/components/link";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import { canAccess, getAdminContext, PERMS } from "@/lib/permissions";
+1 -1
View File
@@ -1,8 +1,8 @@
"use client";
import { Eye, Pencil, Sofa, Wifi } from "lucide-react";
import Link from "next/link";
import { DataTable } from "@/components/admin/data-table";
import Link from "@/components/link";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import type { DataTableColumn, PaginatedResult } from "@/types/common";
+1 -1
View File
@@ -1,7 +1,7 @@
import { DoorOpen, Eye, Globe, Lock, Pencil, Sofa, Users } from "lucide-react";
import Link from "next/link";
import { redirect } from "next/navigation";
import { AdminBreadcrumb } from "@/components/admin/admin-breadcrumb";
import Link from "@/components/link";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import { Card, CardContent } from "@/components/ui/card";
+1 -1
View File
@@ -1,9 +1,9 @@
import { eq } from "drizzle-orm";
import { Package } from "lucide-react";
import Link from "next/link";
import { notFound, redirect } from "next/navigation";
import { getTranslations } from "next-intl/server";
import { deleteShopArticle, updateShopArticle } from "@/actions/admin-shop";
import Link from "@/components/link";
import { Button } from "@/components/ui/button";
import { db, WebsiteShopArticles } from "@/lib/db";
import { canAccess, getAdminContext, PERMS } from "@/lib/permissions";
+1 -1
View File
@@ -1,8 +1,8 @@
import { Package } from "lucide-react";
import Link from "next/link";
import { redirect } from "next/navigation";
import { getTranslations } from "next-intl/server";
import { createShopArticle } from "@/actions/admin-shop";
import Link from "@/components/link";
import { Button } from "@/components/ui/button";
import { canAccess, getAdminContext, PERMS } from "@/lib/permissions";
+1 -1
View File
@@ -1,11 +1,11 @@
import { asc, count, desc } from "drizzle-orm";
import { ShoppingCart } from "lucide-react";
import Link from "next/link";
import { redirect } from "next/navigation";
import { getTranslations } from "next-intl/server";
import { AdminPageShell } from "@/components/admin/admin-page-shell";
import { AdminSimplePager } from "@/components/admin/admin-simple-pager";
import { StatusCard } from "@/components/admin/dashboard";
import Link from "@/components/link";
import { CurrencyIcon } from "@/components/shared/currency-icon";
import { Button } from "@/components/ui/button";
import { calcPagination, parseListParams } from "@/lib/admin-helpers";
+1 -1
View File
@@ -14,8 +14,8 @@ import {
Upload,
Wrench,
} from "lucide-react";
import Link from "next/link";
import { usePathname } from "next/navigation";
import Link from "@/components/link";
import { cn } from "@/lib/utils";
const TABS: { href: string; label: string; icon: LucideIcon }[] = [
@@ -10,7 +10,6 @@ import {
Shield,
User,
} from "lucide-react";
import Link from "next/link";
import { useEffect, useRef, useState } from "react";
import {
adminReplyTicket,
@@ -18,6 +17,7 @@ import {
updateTicketPriority,
updateTicketStatus,
} from "@/actions/tickets";
import Link from "@/components/link";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
+1 -1
View File
@@ -1,8 +1,8 @@
"use client";
import Link from "next/link";
import { useTranslations } from "next-intl";
import { DataTable } from "@/components/admin/data-table";
import Link from "@/components/link";
import { Badge } from "@/components/ui/badge";
import type { DataTableColumn, PaginatedResult } from "@/types/common";
@@ -1,8 +1,8 @@
"use client";
import Link from "next/link";
import { useTranslations } from "next-intl";
import { DataTable } from "@/components/admin/data-table";
import Link from "@/components/link";
import { Badge } from "@/components/ui/badge";
import type { DataTableColumn, PaginatedResult } from "@/types/common";
Loaded 100 of 151 files, more files were not shown because too many files have changed in this diff. Show more