refactor(lib): organize modules by feature
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
"use server";
|
"use server";
|
||||||
|
|
||||||
import { requireAdmin } from "@/lib/auth";
|
import { requireAdmin } from "@/lib/auth/auth";
|
||||||
import { getGuildRolesInternal, type DiscordRole } from "@/lib/discord";
|
import { getGuildRolesInternal, type DiscordRole } from "@/lib/discord/discord";
|
||||||
|
|
||||||
export async function getGuildRoles(): Promise<DiscordRole[]> {
|
export async function getGuildRoles(): Promise<DiscordRole[]> {
|
||||||
await requireAdmin();
|
await requireAdmin();
|
||||||
|
|||||||
@@ -7,9 +7,9 @@ import { cdn, questions } from "@/db/schema";
|
|||||||
import type { ImageAnswerMode, QuestionType } from "@/db/schema";
|
import type { ImageAnswerMode, QuestionType } from "@/db/schema";
|
||||||
import { eq } from "drizzle-orm";
|
import { eq } from "drizzle-orm";
|
||||||
import { revalidatePath } from "next/cache";
|
import { revalidatePath } from "next/cache";
|
||||||
import { requireAdmin } from "@/lib/auth";
|
import { requireAdmin } from "@/lib/auth/auth";
|
||||||
import { sanitizeHtml } from "@/lib/sanitize-html";
|
import { sanitizeHtml } from "@/lib/sanitize-html";
|
||||||
import { sse } from "@/lib/sse";
|
import { sse } from "@/lib/realtime/sse";
|
||||||
|
|
||||||
export async function createQuestion(
|
export async function createQuestion(
|
||||||
formId: string,
|
formId: string,
|
||||||
|
|||||||
@@ -5,16 +5,16 @@ import { submissions, answers } from "@/db/schema";
|
|||||||
import { and, count, eq, lt, lte, or } from "drizzle-orm";
|
import { and, count, eq, lt, lte, or } from "drizzle-orm";
|
||||||
import { revalidatePath } from "next/cache";
|
import { revalidatePath } from "next/cache";
|
||||||
import { getServerSession } from "next-auth";
|
import { getServerSession } from "next-auth";
|
||||||
import { authOptions } from "@/lib/auth-options";
|
import { authOptions } from "@/lib/auth/auth-options";
|
||||||
import { requireAdmin, requireDiscordId, requireFormAccess } from "@/lib/auth";
|
import { requireAdmin, requireDiscordId, requireFormAccess } from "@/lib/auth/auth";
|
||||||
import { sse } from "@/lib/sse";
|
import { sse } from "@/lib/realtime/sse";
|
||||||
import type { FormAnswerPayload } from "@/lib/form-answer-values";
|
import type { FormAnswerPayload } from "@/lib/form/form-answer-values";
|
||||||
import {
|
import {
|
||||||
normalizeSubmissionAnswers,
|
normalizeSubmissionAnswers,
|
||||||
type StoredAnswerSnapshot,
|
type StoredAnswerSnapshot,
|
||||||
} from "@/lib/submission-intake";
|
} from "@/lib/form/submission-intake";
|
||||||
import { submissionWebhookMessage } from "@/lib/submission-webhook";
|
import { submissionWebhookMessage } from "@/lib/form/submission-webhook";
|
||||||
import { isFormAcceptingSubmissions } from "@/lib/form-availability";
|
import { isFormAcceptingSubmissions } from "@/lib/form/form-availability";
|
||||||
|
|
||||||
function getSubmissionResultLink(formId: string, submissionId: string) {
|
function getSubmissionResultLink(formId: string, submissionId: string) {
|
||||||
const baseUrl = process.env.BASE_URL || process.env.NEXTAUTH_URL;
|
const baseUrl = process.env.BASE_URL || process.env.NEXTAUTH_URL;
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ import {
|
|||||||
getQuestionResponseSettings,
|
getQuestionResponseSettings,
|
||||||
getQuestionResponseType,
|
getQuestionResponseType,
|
||||||
type QuestionResponseType,
|
type QuestionResponseType,
|
||||||
} from "@/lib/question-response-type";
|
} from "@/lib/form/question-response-type";
|
||||||
import {
|
import {
|
||||||
SaveStatusIndicator,
|
SaveStatusIndicator,
|
||||||
SortableQuestion,
|
SortableQuestion,
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import { toast } from "sonner";
|
|||||||
import { testDiscordWebhook, updateForm } from "@/app/admin/form/actions";
|
import { testDiscordWebhook, updateForm } from "@/app/admin/form/actions";
|
||||||
import { Loader2, ChevronDown, Check, AlertCircle, Send } from "lucide-react";
|
import { Loader2, ChevronDown, Check, AlertCircle, Send } from "lucide-react";
|
||||||
import { getGuildRoles } from "@/app/actions/discord";
|
import { getGuildRoles } from "@/app/actions/discord";
|
||||||
import type { DiscordRole } from "@/lib/discord";
|
import type { DiscordRole } from "@/lib/discord/discord";
|
||||||
import {
|
import {
|
||||||
DropdownMenu,
|
DropdownMenu,
|
||||||
DropdownMenuCheckboxItem,
|
DropdownMenuCheckboxItem,
|
||||||
@@ -23,7 +23,7 @@ import { getErrorMessage } from "@/lib/utils";
|
|||||||
import {
|
import {
|
||||||
isValidDiscordWebhookUrl,
|
isValidDiscordWebhookUrl,
|
||||||
previewWebhookTemplate,
|
previewWebhookTemplate,
|
||||||
} from "@/lib/discord-webhook-settings";
|
} from "@/lib/discord/discord-webhook-settings";
|
||||||
import {
|
import {
|
||||||
useDebouncedAutoSave,
|
useDebouncedAutoSave,
|
||||||
type AutoSaveStatus,
|
type AutoSaveStatus,
|
||||||
|
|||||||
@@ -2,14 +2,14 @@ import { SidebarProvider, SidebarTrigger } from "@/components/ui/sidebar";
|
|||||||
import { FormAdminSidebar } from "@/components/form-admin-sidebar";
|
import { FormAdminSidebar } from "@/components/form-admin-sidebar";
|
||||||
import { Metadata } from "next";
|
import { Metadata } from "next";
|
||||||
import { getServerSession } from "next-auth";
|
import { getServerSession } from "next-auth";
|
||||||
import { authOptions } from "@/lib/auth-options";
|
import { authOptions } from "@/lib/auth/auth-options";
|
||||||
import { getSessionDiscordId } from "@/lib/auth";
|
import { getSessionDiscordId } from "@/lib/auth/auth";
|
||||||
import { getDiscordMemberProfile } from "@/lib/discord";
|
import { getDiscordMemberProfile } from "@/lib/discord/discord";
|
||||||
import { db } from "@/db";
|
import { db } from "@/db";
|
||||||
import { submissions } from "@/db/schema";
|
import { submissions } from "@/db/schema";
|
||||||
import { asc, eq } from "drizzle-orm";
|
import { asc, eq } from "drizzle-orm";
|
||||||
import { notFound } from "next/navigation";
|
import { notFound } from "next/navigation";
|
||||||
import { isFormAcceptingSubmissions } from "@/lib/form-availability";
|
import { isFormAcceptingSubmissions } from "@/lib/form/form-availability";
|
||||||
|
|
||||||
export const metadata: Metadata = {
|
export const metadata: Metadata = {
|
||||||
title: {
|
title: {
|
||||||
|
|||||||
@@ -42,8 +42,8 @@ import {
|
|||||||
import Image from 'next/image';
|
import Image from 'next/image';
|
||||||
import { stripHtml } from "@/lib/utils";
|
import { stripHtml } from "@/lib/utils";
|
||||||
import { HtmlDisplay } from "@/components/html-display";
|
import { HtmlDisplay } from "@/components/html-display";
|
||||||
import { formatStoredAnswer } from "@/lib/form-answer-values";
|
import { formatStoredAnswer } from "@/lib/form/form-answer-values";
|
||||||
import { normalizeStoredAnswerSnapshot } from "@/lib/submission-intake";
|
import { normalizeStoredAnswerSnapshot } from "@/lib/form/submission-intake";
|
||||||
import { updateSubmissionAdminNote } from "@/app/admin/form/actions";
|
import { updateSubmissionAdminNote } from "@/app/admin/form/actions";
|
||||||
import {
|
import {
|
||||||
useDebouncedAutoSave,
|
useDebouncedAutoSave,
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import { ArrowLeft, ArrowRight } from "lucide-react";
|
|||||||
import SubmissionDetailClient from "./client";
|
import SubmissionDetailClient from "./client";
|
||||||
import { DeleteSubmissionButton } from "@/components/delete-buttons";
|
import { DeleteSubmissionButton } from "@/components/delete-buttons";
|
||||||
import { RealtimeRefresh } from "@/components/realtime-refresh";
|
import { RealtimeRefresh } from "@/components/realtime-refresh";
|
||||||
import { getDiscordMemberProfile } from "@/lib/discord";
|
import { getDiscordMemberProfile } from "@/lib/discord/discord";
|
||||||
|
|
||||||
interface SubmissionDetailPageProps {
|
interface SubmissionDetailPageProps {
|
||||||
params: Promise<{
|
params: Promise<{
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@
|
|||||||
import { Pagination, PaginationContent, PaginationItem, PaginationLink, PaginationNext, PaginationPrevious } from "@/components/ui/pagination";
|
import { Pagination, PaginationContent, PaginationItem, PaginationLink, PaginationNext, PaginationPrevious } from "@/components/ui/pagination";
|
||||||
import { DeleteAllSubmissionsButton, DeleteSubmissionButton } from "@/components/delete-buttons";
|
import { DeleteAllSubmissionsButton, DeleteSubmissionButton } from "@/components/delete-buttons";
|
||||||
import { ResultsFilters } from "@/components/results-filters";
|
import { ResultsFilters } from "@/components/results-filters";
|
||||||
import type { DiscordMemberProfile } from "@/lib/discord";
|
import type { DiscordMemberProfile } from "@/lib/discord/discord";
|
||||||
|
|
||||||
const RESULTS_PAGE_SIZE = 25;
|
const RESULTS_PAGE_SIZE = 25;
|
||||||
type ResultFilters = {
|
type ResultFilters = {
|
||||||
|
|||||||
@@ -2,12 +2,12 @@ import { NextResponse } from "next/server";
|
|||||||
import { db } from "@/db";
|
import { db } from "@/db";
|
||||||
import { answers } from "@/db/schema";
|
import { answers } from "@/db/schema";
|
||||||
import { inArray } from "drizzle-orm";
|
import { inArray } from "drizzle-orm";
|
||||||
import { requireAdmin } from "@/lib/auth";
|
import { requireAdmin } from "@/lib/auth/auth";
|
||||||
import {
|
import {
|
||||||
getFilteredSubmissions,
|
getFilteredSubmissions,
|
||||||
parseResultFilters,
|
parseResultFilters,
|
||||||
} from "@/lib/admin-form-results";
|
} from "@/lib/form/admin-form-results";
|
||||||
import { answerCellValue } from "@/lib/form-answer-values";
|
import { answerCellValue } from "@/lib/form/form-answer-values";
|
||||||
import { stripHtml } from "@/lib/utils";
|
import { stripHtml } from "@/lib/utils";
|
||||||
|
|
||||||
function csvCell(value: unknown) {
|
function csvCell(value: unknown) {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { parseResultFilters, getFilteredSubmissions } from "@/lib/admin-form-results";
|
import { parseResultFilters, getFilteredSubmissions } from "@/lib/form/admin-form-results";
|
||||||
import { getDiscordMemberProfile } from "@/lib/discord";
|
import { getDiscordMemberProfile } from "@/lib/discord/discord";
|
||||||
import { RealtimeRefresh } from "@/components/realtime-refresh";
|
import { RealtimeRefresh } from "@/components/realtime-refresh";
|
||||||
import ResultsClient from "./client";
|
import ResultsClient from "./client";
|
||||||
|
|
||||||
|
|||||||
@@ -5,10 +5,10 @@ import { forms, submissions } from "@/db/schema";
|
|||||||
import { and, eq } from "drizzle-orm";
|
import { and, eq } from "drizzle-orm";
|
||||||
import { revalidatePath } from "next/cache";
|
import { revalidatePath } from "next/cache";
|
||||||
import { redirect } from "next/navigation";
|
import { redirect } from "next/navigation";
|
||||||
import { requireAdmin } from "@/lib/auth";
|
import { requireAdmin } from "@/lib/auth/auth";
|
||||||
import { sanitizeHtml } from "@/lib/sanitize-html";
|
import { sanitizeHtml } from "@/lib/sanitize-html";
|
||||||
import { sse } from "@/lib/sse";
|
import { sse } from "@/lib/realtime/sse";
|
||||||
import { isValidDiscordWebhookUrl } from "@/lib/discord-webhook-settings";
|
import { isValidDiscordWebhookUrl } from "@/lib/discord/discord-webhook-settings";
|
||||||
|
|
||||||
export async function createForm(formData: FormData) {
|
export async function createForm(formData: FormData) {
|
||||||
await requireAdmin();
|
await requireAdmin();
|
||||||
|
|||||||
@@ -15,9 +15,9 @@ import { DeleteFormButton } from "@/components/delete-buttons";
|
|||||||
import { AdminShellServer } from "@/components/admin-shell-server";
|
import { AdminShellServer } from "@/components/admin-shell-server";
|
||||||
import { createDefaultForm } from "./actions";
|
import { createDefaultForm } from "./actions";
|
||||||
import { RealtimeRefresh } from "@/components/realtime-refresh";
|
import { RealtimeRefresh } from "@/components/realtime-refresh";
|
||||||
import { getFormSubmissionStats } from "@/lib/form-submission-stats";
|
import { getFormSubmissionStats } from "@/lib/form/form-submission-stats";
|
||||||
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
||||||
import { isFormAcceptingSubmissions } from "@/lib/form-availability";
|
import { isFormAcceptingSubmissions } from "@/lib/form/form-availability";
|
||||||
|
|
||||||
export const dynamic = "force-dynamic";
|
export const dynamic = "force-dynamic";
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { getServerSession } from "next-auth";
|
import { getServerSession } from "next-auth";
|
||||||
import { authOptions } from "@/lib/auth-options";
|
import { authOptions } from "@/lib/auth/auth-options";
|
||||||
import { redirect } from "next/navigation";
|
import { redirect } from "next/navigation";
|
||||||
import { getAdminDiscordIds, getSessionDiscordId } from "@/lib/auth";
|
import { getAdminDiscordIds, getSessionDiscordId } from "@/lib/auth/auth";
|
||||||
|
|
||||||
export default async function AdminLayout({
|
export default async function AdminLayout({
|
||||||
children,
|
children,
|
||||||
|
|||||||
+1
-1
@@ -18,7 +18,7 @@ import {
|
|||||||
TableHeader,
|
TableHeader,
|
||||||
TableRow,
|
TableRow,
|
||||||
} from "@/components/ui/table";
|
} from "@/components/ui/table";
|
||||||
import { getAdminDashboardData } from "@/lib/admin-dashboard";
|
import { getAdminDashboardData } from "@/lib/admin/admin-dashboard";
|
||||||
import {
|
import {
|
||||||
ClipboardList,
|
ClipboardList,
|
||||||
FilePlus2,
|
FilePlus2,
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { Readable } from "node:stream";
|
|||||||
import { pipeline } from "node:stream/promises";
|
import { pipeline } from "node:stream/promises";
|
||||||
import { randomUUID } from "node:crypto";
|
import { randomUUID } from "node:crypto";
|
||||||
import { NextResponse } from "next/server";
|
import { NextResponse } from "next/server";
|
||||||
import { requireAdmin } from "@/lib/auth";
|
import { requireAdmin } from "@/lib/auth/auth";
|
||||||
|
|
||||||
export const dynamic = "force-dynamic";
|
export const dynamic = "force-dynamic";
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { NextResponse } from "next/server";
|
import { NextResponse } from "next/server";
|
||||||
import { requireAdmin } from "@/lib/auth";
|
import { requireAdmin } from "@/lib/auth/auth";
|
||||||
import { saveVideoUpload } from "@/lib/video-upload-storage";
|
import { saveVideoUpload } from "@/lib/video/video-upload-storage";
|
||||||
|
|
||||||
export const dynamic = "force-dynamic";
|
export const dynamic = "force-dynamic";
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import NextAuth from "next-auth";
|
import NextAuth from "next-auth";
|
||||||
import { authOptions } from "@/lib/auth-options";
|
import { authOptions } from "@/lib/auth/auth-options";
|
||||||
|
|
||||||
const handler = NextAuth(authOptions);
|
const handler = NextAuth(authOptions);
|
||||||
export { handler as GET, handler as POST };
|
export { handler as GET, handler as POST };
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { NextRequest, NextResponse } from "next/server";
|
import { NextRequest, NextResponse } from "next/server";
|
||||||
import { cookies } from "next/headers";
|
import { cookies } from "next/headers";
|
||||||
import { requireAdmin } from "@/lib/auth";
|
import { requireAdmin } from "@/lib/auth/auth";
|
||||||
|
|
||||||
const TIKTOK_OAUTH_STATE_COOKIE = "tiktok-oauth-state";
|
const TIKTOK_OAUTH_STATE_COOKIE = "tiktok-oauth-state";
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { NextResponse } from "next/server";
|
import { NextResponse } from "next/server";
|
||||||
import { randomBytes } from "node:crypto";
|
import { randomBytes } from "node:crypto";
|
||||||
import { cookies } from "next/headers";
|
import { cookies } from "next/headers";
|
||||||
import { requireAdmin } from "@/lib/auth";
|
import { requireAdmin } from "@/lib/auth/auth";
|
||||||
|
|
||||||
const TIKTOK_OAUTH_STATE_COOKIE = "tiktok-oauth-state";
|
const TIKTOK_OAUTH_STATE_COOKIE = "tiktok-oauth-state";
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { cookies } from "next/headers";
|
import { cookies } from "next/headers";
|
||||||
import { NextRequest, NextResponse } from "next/server";
|
import { NextRequest, NextResponse } from "next/server";
|
||||||
import { requireAdmin } from "@/lib/auth";
|
import { requireAdmin } from "@/lib/auth/auth";
|
||||||
|
|
||||||
function escapeHtml(value: unknown) {
|
function escapeHtml(value: unknown) {
|
||||||
return String(value ?? "")
|
return String(value ?? "")
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { randomBytes } from "node:crypto";
|
import { randomBytes } from "node:crypto";
|
||||||
import { cookies } from "next/headers";
|
import { cookies } from "next/headers";
|
||||||
import { NextResponse } from "next/server";
|
import { NextResponse } from "next/server";
|
||||||
import { requireAdmin } from "@/lib/auth";
|
import { requireAdmin } from "@/lib/auth/auth";
|
||||||
|
|
||||||
const COOKIE = "youtube-oauth-state";
|
const COOKIE = "youtube-oauth-state";
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { NextResponse } from "next/server";
|
import { NextResponse } from "next/server";
|
||||||
import { processDueVideoUploads } from "@/lib/video-platforms";
|
import { processDueVideoUploads } from "@/lib/video/video-platforms";
|
||||||
|
|
||||||
export const dynamic = "force-dynamic";
|
export const dynamic = "force-dynamic";
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import { NextResponse } from "next/server";
|
import { NextResponse } from "next/server";
|
||||||
import { db } from "@/db";
|
import { db } from "@/db";
|
||||||
import { cdn } from "@/db/schema";
|
import { cdn } from "@/db/schema";
|
||||||
import { requireDiscordId } from "@/lib/auth";
|
import { requireDiscordId } from "@/lib/auth/auth";
|
||||||
import { validateImageUploadFile, cdnUrl } from "@/lib/cdn-images";
|
import { validateImageUploadFile, cdnUrl } from "@/lib/cdn/cdn-images";
|
||||||
|
|
||||||
export async function POST(req: Request) {
|
export async function POST(req: Request) {
|
||||||
let discordId: string;
|
let discordId: string;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { db } from "@/db";
|
import { db } from "@/db";
|
||||||
import { cdnImageResponse } from "@/lib/cdn-images";
|
import { cdnImageResponse } from "@/lib/cdn/cdn-images";
|
||||||
|
|
||||||
export async function GET(
|
export async function GET(
|
||||||
_request: Request,
|
_request: Request,
|
||||||
|
|||||||
@@ -1,17 +1,17 @@
|
|||||||
import { db } from "@/db";
|
import { db } from "@/db";
|
||||||
import { FormFillerClient } from "../client";
|
import { FormFillerClient } from "../client";
|
||||||
import { getServerSession } from "next-auth";
|
import { getServerSession } from "next-auth";
|
||||||
import { authOptions } from "@/lib/auth-options";
|
import { authOptions } from "@/lib/auth/auth-options";
|
||||||
import { notFound } from "next/navigation";
|
import { notFound } from "next/navigation";
|
||||||
import LoginDialog from "@/components/login-dialog";
|
import LoginDialog from "@/components/login-dialog";
|
||||||
import { canAccessForm, getSessionDiscordId } from "@/lib/auth";
|
import { canAccessForm, getSessionDiscordId } from "@/lib/auth/auth";
|
||||||
import { RealtimeRefresh } from "@/components/realtime-refresh";
|
import { RealtimeRefresh } from "@/components/realtime-refresh";
|
||||||
import {
|
import {
|
||||||
decodeCheckboxAnswer,
|
decodeCheckboxAnswer,
|
||||||
type FormAnswerValue,
|
type FormAnswerValue,
|
||||||
} from "@/lib/form-answer-values";
|
} from "@/lib/form/form-answer-values";
|
||||||
import { getFormSubmissionStats } from "@/lib/form-submission-stats";
|
import { getFormSubmissionStats } from "@/lib/form/form-submission-stats";
|
||||||
import { isFormAcceptingSubmissions } from "@/lib/form-availability";
|
import { isFormAcceptingSubmissions } from "@/lib/form/form-availability";
|
||||||
|
|
||||||
export const dynamic = "force-dynamic";
|
export const dynamic = "force-dynamic";
|
||||||
|
|
||||||
|
|||||||
+3
-3
@@ -55,8 +55,8 @@ import {
|
|||||||
import { Spinner } from "@/components/ui/spinner";
|
import { Spinner } from "@/components/ui/spinner";
|
||||||
import {
|
import {
|
||||||
type FormAnswerValue,
|
type FormAnswerValue,
|
||||||
} from "@/lib/form-answer-values";
|
} from "@/lib/form/form-answer-values";
|
||||||
import { isImageOnlyResponse } from "@/lib/question-response-type";
|
import { isImageOnlyResponse } from "@/lib/form/question-response-type";
|
||||||
import {
|
import {
|
||||||
buildFormSchema,
|
buildFormSchema,
|
||||||
parseStoredDraft,
|
parseStoredDraft,
|
||||||
@@ -64,7 +64,7 @@ import {
|
|||||||
type FormFillerClientProps,
|
type FormFillerClientProps,
|
||||||
type FormValues,
|
type FormValues,
|
||||||
type StoredDraft,
|
type StoredDraft,
|
||||||
} from "@/lib/form-client";
|
} from "@/lib/form/form-client";
|
||||||
|
|
||||||
export function FormLayoutClient({
|
export function FormLayoutClient({
|
||||||
userName,
|
userName,
|
||||||
|
|||||||
+4
-4
@@ -1,12 +1,12 @@
|
|||||||
import { getServerSession } from "next-auth";
|
import { getServerSession } from "next-auth";
|
||||||
import { authOptions } from "@/lib/auth-options";
|
import { authOptions } from "@/lib/auth/auth-options";
|
||||||
import { FormLayoutClient, LoginButton } from "./client";
|
import { FormLayoutClient, LoginButton } from "./client";
|
||||||
import { Metadata } from "next";
|
import { Metadata } from "next";
|
||||||
import { ThemeToggle } from "@/components/theme-toggle";
|
import { ThemeToggle } from "@/components/theme-toggle";
|
||||||
import { getSessionDiscordId } from "@/lib/auth";
|
import { getSessionDiscordId } from "@/lib/auth/auth";
|
||||||
import { getDiscordMemberProfile } from "@/lib/discord";
|
import { getDiscordMemberProfile } from "@/lib/discord/discord";
|
||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
import { getAdminDiscordIds } from "@/lib/auth";
|
import { getAdminDiscordIds } from "@/lib/auth/auth";
|
||||||
|
|
||||||
const siteUrl = process.env.BASE_URL;
|
const siteUrl = process.env.BASE_URL;
|
||||||
|
|
||||||
|
|||||||
+3
-3
@@ -7,11 +7,11 @@ import {
|
|||||||
} from "@/components/ui/card";
|
} from "@/components/ui/card";
|
||||||
import { HtmlDisplay } from "@/components/html-display";
|
import { HtmlDisplay } from "@/components/html-display";
|
||||||
import { getServerSession } from "next-auth";
|
import { getServerSession } from "next-auth";
|
||||||
import { authOptions } from "@/lib/auth-options";
|
import { authOptions } from "@/lib/auth/auth-options";
|
||||||
import { canAccessForm, getSessionDiscordId } from "@/lib/auth";
|
import { canAccessForm, getSessionDiscordId } from "@/lib/auth/auth";
|
||||||
import { RealtimeRefresh } from "@/components/realtime-refresh";
|
import { RealtimeRefresh } from "@/components/realtime-refresh";
|
||||||
import { Badge } from "@/components/ui/badge";
|
import { Badge } from "@/components/ui/badge";
|
||||||
import { getFormSubmissionStats } from "@/lib/form-submission-stats";
|
import { getFormSubmissionStats } from "@/lib/form/form-submission-stats";
|
||||||
|
|
||||||
export const dynamic = "force-dynamic";
|
export const dynamic = "force-dynamic";
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
import { getServerSession } from "next-auth";
|
import { getServerSession } from "next-auth";
|
||||||
import { authOptions } from "@/lib/auth-options";
|
import { authOptions } from "@/lib/auth/auth-options";
|
||||||
import {
|
import {
|
||||||
getAdminDiscordIds,
|
getAdminDiscordIds,
|
||||||
getSessionDiscordId,
|
getSessionDiscordId,
|
||||||
} from "@/lib/auth";
|
} from "@/lib/auth/auth";
|
||||||
import { isSseTopic, sse } from "@/lib/sse";
|
import { isSseTopic, sse } from "@/lib/realtime/sse";
|
||||||
|
|
||||||
export async function GET(
|
export async function GET(
|
||||||
request: Request,
|
request: Request,
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { getServerSession } from "next-auth";
|
import { getServerSession } from "next-auth";
|
||||||
import { authOptions } from "@/lib/auth-options";
|
import { authOptions } from "@/lib/auth/auth-options";
|
||||||
import { getSessionDiscordId } from "@/lib/auth";
|
import { getSessionDiscordId } from "@/lib/auth/auth";
|
||||||
import { getDiscordMemberProfile } from "@/lib/discord";
|
import { getDiscordMemberProfile } from "@/lib/discord/discord";
|
||||||
import { AdminShell } from "@/components/admin-shell";
|
import { AdminShell } from "@/components/admin-shell";
|
||||||
|
|
||||||
export async function AdminShellServer({ children }: { children: React.ReactNode }) {
|
export async function AdminShellServer({ children }: { children: React.ReactNode }) {
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import {
|
|||||||
DropdownMenuTrigger,
|
DropdownMenuTrigger,
|
||||||
} from "@/components/ui/dropdown-menu";
|
} from "@/components/ui/dropdown-menu";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import type { DiscordRole } from "@/lib/discord";
|
import type { DiscordRole } from "@/lib/discord/discord";
|
||||||
|
|
||||||
export interface DiscordMemberProfile {
|
export interface DiscordMemberProfile {
|
||||||
id: string;
|
id: string;
|
||||||
|
|||||||
@@ -2,11 +2,11 @@
|
|||||||
|
|
||||||
import { useEffect } from "react";
|
import { useEffect } from "react";
|
||||||
import { useRouter } from "next/navigation";
|
import { useRouter } from "next/navigation";
|
||||||
import { sse } from "@/lib/sse";
|
import { sse } from "@/lib/realtime/sse";
|
||||||
import {
|
import {
|
||||||
startRealtimeRefresh,
|
startRealtimeRefresh,
|
||||||
type RealtimeRefreshHandlers,
|
type RealtimeRefreshHandlers,
|
||||||
} from "@/lib/realtime-refresh";
|
} from "@/lib/realtime/realtime-refresh";
|
||||||
|
|
||||||
type FormRealtimeRefreshProps = {
|
type FormRealtimeRefreshProps = {
|
||||||
topic: "forms" | "submissions";
|
topic: "forms" | "submissions";
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ import {
|
|||||||
PopoverContent,
|
PopoverContent,
|
||||||
PopoverTrigger,
|
PopoverTrigger,
|
||||||
} from "@/components/ui/popover";
|
} from "@/components/ui/popover";
|
||||||
import type { ResultFilters } from "@/lib/admin-form-results";
|
import type { ResultFilters } from "@/lib/form/admin-form-results";
|
||||||
import { Download, X, CalendarDays } from "lucide-react";
|
import { Download, X, CalendarDays } from "lucide-react";
|
||||||
import { format, parseISO } from "date-fns";
|
import { format, parseISO } from "date-fns";
|
||||||
|
|
||||||
|
|||||||
@@ -4,8 +4,8 @@ import DiscordProvider from "next-auth/providers/discord";
|
|||||||
import { DrizzleAdapter } from "@auth/drizzle-adapter";
|
import { DrizzleAdapter } from "@auth/drizzle-adapter";
|
||||||
import { db } from "@/db";
|
import { db } from "@/db";
|
||||||
import { accounts, sessions, users, verificationTokens } from "@/db/schema";
|
import { accounts, sessions, users, verificationTokens } from "@/db/schema";
|
||||||
import type { SessionWithDiscord } from "@/lib/auth";
|
import type { SessionWithDiscord } from "@/lib/auth/auth";
|
||||||
import { addDiscordGuildMember } from "@/lib/discord";
|
import { addDiscordGuildMember } from "@/lib/discord/discord";
|
||||||
|
|
||||||
const discordIdCache = new Map<string, string>();
|
const discordIdCache = new Map<string, string>();
|
||||||
|
|
||||||
@@ -2,8 +2,8 @@ import "server-only";
|
|||||||
import { getServerSession } from "next-auth";
|
import { getServerSession } from "next-auth";
|
||||||
import type { Session } from "next-auth";
|
import type { Session } from "next-auth";
|
||||||
import { db } from "@/db";
|
import { db } from "@/db";
|
||||||
import { authOptions } from "@/lib/auth-options";
|
import { authOptions } from "@/lib/auth/auth-options";
|
||||||
import { getGuildMemberRoles } from "@/lib/discord";
|
import { getGuildMemberRoles } from "@/lib/discord/discord";
|
||||||
|
|
||||||
export type SessionWithDiscord = Session & {
|
export type SessionWithDiscord = Session & {
|
||||||
user?: Session["user"] & {
|
user?: Session["user"] & {
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
import { describe, expect, test } from "bun:test";
|
import { describe, expect, test } from "bun:test";
|
||||||
import { isFormAcceptingSubmissions } from "@/lib/form-availability";
|
import { isFormAcceptingSubmissions } from "@/lib/form/form-availability";
|
||||||
|
|
||||||
const now = new Date("2026-07-30T12:00:00.000Z");
|
const now = new Date("2026-07-30T12:00:00.000Z");
|
||||||
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
import type { FormAnswerValue } from "@/lib/form-answer-values";
|
import type { FormAnswerValue } from "@/lib/form/form-answer-values";
|
||||||
import { decodeCheckboxAnswer } from "@/lib/form-answer-values";
|
import { decodeCheckboxAnswer } from "@/lib/form/form-answer-values";
|
||||||
|
|
||||||
export type Question = {
|
export type Question = {
|
||||||
id: string;
|
id: string;
|
||||||
@@ -3,7 +3,7 @@ import {
|
|||||||
getQuestionResponseSettings,
|
getQuestionResponseSettings,
|
||||||
getQuestionResponseType,
|
getQuestionResponseType,
|
||||||
isImageOnlyResponse,
|
isImageOnlyResponse,
|
||||||
} from "@/lib/question-response-type";
|
} from "@/lib/form/question-response-type";
|
||||||
|
|
||||||
describe("question response types", () => {
|
describe("question response types", () => {
|
||||||
test("maps stored question settings to the four editor choices", () => {
|
test("maps stored question settings to the four editor choices", () => {
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
import { describe, expect, test } from "bun:test";
|
import { describe, expect, test } from "bun:test";
|
||||||
import { normalizeSubmissionAnswers } from "@/lib/submission-intake";
|
import { normalizeSubmissionAnswers } from "@/lib/form/submission-intake";
|
||||||
|
|
||||||
const question = {
|
const question = {
|
||||||
id: "question-1",
|
id: "question-1",
|
||||||
@@ -4,7 +4,7 @@ import {
|
|||||||
encodeAnswerValue,
|
encodeAnswerValue,
|
||||||
formatStoredAnswer,
|
formatStoredAnswer,
|
||||||
type FormAnswerValue,
|
type FormAnswerValue,
|
||||||
} from "@/lib/form-answer-values";
|
} from "@/lib/form/form-answer-values";
|
||||||
import { stripHtml } from "@/lib/utils";
|
import { stripHtml } from "@/lib/utils";
|
||||||
|
|
||||||
export type SubmissionQuestion = {
|
export type SubmissionQuestion = {
|
||||||
@@ -4,7 +4,7 @@ import {
|
|||||||
type NormalizedSubmissionAnswer,
|
type NormalizedSubmissionAnswer,
|
||||||
type OldAnswersByQuestionId,
|
type OldAnswersByQuestionId,
|
||||||
type SubmissionQuestion,
|
type SubmissionQuestion,
|
||||||
} from "@/lib/submission-intake";
|
} from "@/lib/form/submission-intake";
|
||||||
|
|
||||||
const NEW_SUBMISSION_TEMPLATE = "New submission from {username} ({id}).";
|
const NEW_SUBMISSION_TEMPLATE = "New submission from {username} ({id}).";
|
||||||
const UPDATED_SUBMISSION_TEMPLATE = "Submission updated by {username} ({id}).\n{update}";
|
const UPDATED_SUBMISSION_TEMPLATE = "Submission updated by {username} ({id}).\n{update}";
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
import { describe, expect, test } from "bun:test";
|
import { describe, expect, test } from "bun:test";
|
||||||
import { isSseTopic, sse } from "@/lib/sse";
|
import { isSseTopic, sse } from "@/lib/realtime/sse";
|
||||||
|
|
||||||
describe("leaderboard SSE contract", () => {
|
describe("leaderboard SSE contract", () => {
|
||||||
test("registers the public leaderboards topic", () => {
|
test("registers the public leaderboards topic", () => {
|
||||||
@@ -13,7 +13,7 @@ import {
|
|||||||
validateThumbnailFile,
|
validateThumbnailFile,
|
||||||
validateVideoFile,
|
validateVideoFile,
|
||||||
publishVideoJob,
|
publishVideoJob,
|
||||||
} from "@/lib/video-platforms";
|
} from "@/lib/video/video-platforms";
|
||||||
import { eq } from "drizzle-orm";
|
import { eq } from "drizzle-orm";
|
||||||
|
|
||||||
const VIDEO_DIR = process.env.VIDEO_UPLOAD_DIR || "/nfs/erika";
|
const VIDEO_DIR = process.env.VIDEO_UPLOAD_DIR || "/nfs/erika";
|
||||||
Reference in New Issue
Block a user