From 77c31ae4f9e10d6d337f4f3a1be3d2c3e644c0d1 Mon Sep 17 00:00:00 2001 From: Sean Date: Mon, 26 Jan 2026 14:58:56 -0500 Subject: [PATCH] fixed all admin email pages. added admin user info and button on builder page to route to admin page. --- app/(app)/(builder)/builder/page.tsx | 93 +++++++++++-------- app/admin/beta-invites/page.tsx | 52 +++-------- app/admin/email/manage/page.tsx | 25 +---- app/admin/email/page.tsx | 25 +---- app/admin/layout.tsx | 11 +-- app/api/admin/beta-invites/route.ts | 4 +- .../admin/beta/requests/[id]/invite/route.ts | 39 ++++++++ app/api/admin/beta/requests/route.ts | 39 ++++++++ app/api/admin/email/[id]/route.ts | 63 +++++++++++++ app/api/admin/email/route.ts | 56 +++++++++++ components/AdminLeftNavigation.tsx | 32 +++++-- components/Banner.tsx | 8 +- components/ui/RichTextEditor.tsx | 87 +++++++++-------- context/AuthContext.tsx | 11 +++ lib/api/emailRequests.ts | 62 ++++++------- 15 files changed, 393 insertions(+), 214 deletions(-) create mode 100644 app/api/admin/beta/requests/[id]/invite/route.ts create mode 100644 app/api/admin/beta/requests/route.ts create mode 100644 app/api/admin/email/[id]/route.ts create mode 100644 app/api/admin/email/route.ts diff --git a/app/(app)/(builder)/builder/page.tsx b/app/(app)/(builder)/builder/page.tsx index f119f43..36d745b 100644 --- a/app/(app)/(builder)/builder/page.tsx +++ b/app/(app)/(builder)/builder/page.tsx @@ -1195,53 +1195,64 @@ function GunbuilderPageContent() {
{/* Header */}
-
-

- BATTL BUILDERS -

-

- Builder Early Access -

-

- Explore components from trusted brands, choose one part per - category, track live prices, and watch your total build cost - update as you go. This early-access builder keeps your setup saved - locally so you can come back and refine it anytime. -

+
+
+

+ BATTL BUILDERS +

+

+ Builder Early Access +

+

+ Explore components from trusted brands, choose one part per + category, track live prices, and watch your total build cost + update as you go. This early-access builder keeps your setup saved + locally so you can come back and refine it anytime. +

+
-
- -

+ // Keep URL in sync, and clear transient action params + const qp = new URLSearchParams(searchParams.toString()); + qp.set("platform", normalizePlatformKey(next)); + qp.delete("select"); + qp.delete("remove"); + + router.replace(`/builder?${qp.toString()}`, { + scroll: false, + }); + }} + className="rounded-md border border-zinc-700 bg-zinc-900 px-2 py-1 text-xs text-zinc-100 focus:outline-none focus:ring-1 focus:ring-amber-400" + > + {PLATFORMS.map((p) => ( + + ))} + + +

Parts list updates automatically when you change platforms.

-
{/* Build summary panel */} diff --git a/app/admin/beta-invites/page.tsx b/app/admin/beta-invites/page.tsx index 87c6f18..2ac0715 100644 --- a/app/admin/beta-invites/page.tsx +++ b/app/admin/beta-invites/page.tsx @@ -1,11 +1,7 @@ "use client"; -import { useEffect, useMemo, useState } from "react"; +import { useEffect, useState } from "react"; import { Button, Field, Input } from "@/components/ui/form"; -import { useAuth } from "@/context/AuthContext"; - -const API_BASE_URL = - process.env.NEXT_PUBLIC_API_BASE_URL ?? ""; type AdminBetaRequestDto = { id: number; @@ -40,17 +36,12 @@ type AdminInviteResponse = { token?: string; }; -async function fetchJson( - path: string, - init: RequestInit = {}, - authHeaders: HeadersInit = {} -) { - const res = await fetch(`${API_BASE_URL}${path}`, { +async function fetchJson(path: string, init: RequestInit = {}) { + const res = await fetch(path, { ...init, headers: { "Content-Type": "application/json", ...(init.headers ?? {}), - ...authHeaders, }, cache: "no-store", }); @@ -101,9 +92,6 @@ function Badge({ } export default function AdminBetaInvitesPage() { - const { getAuthHeaders, user } = useAuth(); - const authHeaders = useMemo(() => getAuthHeaders(), [getAuthHeaders]); - // ------------------------------ // Batch invites // ------------------------------ @@ -126,11 +114,9 @@ export default function AdminBetaInvitesPage() { tokenMinutes: String(tokenMinutes || "30"), }); - const data = await fetchJson( - `/api/v1/admin/beta/invites/send?${qs.toString()}`, - { method: "POST" }, - authHeaders - ); + const data = await fetchJson(`/api/admin/beta-invites?${qs.toString()}`, { + method: "POST", + }); setBatchResult(data); await loadRequests(); @@ -166,9 +152,8 @@ export default function AdminBetaInvitesPage() { try { const data = (await fetchJson( - `/api/v1/admin/beta/requests?page=${page}&size=${size}`, - { method: "GET" }, - authHeaders + `/api/admin/beta/requests?page=${page}&size=${size}`, + { method: "GET" } )) as PageResponse; setRequests(data); @@ -181,11 +166,9 @@ export default function AdminBetaInvitesPage() { async function inviteSingle(userId: number): Promise { // calls backend: POST /api/v1/admin/beta/requests/{userId}/invite - return (await fetchJson( - `/api/v1/admin/beta/requests/${userId}/invite`, - { method: "POST" }, - authHeaders - )) as AdminInviteResponse; + return (await fetchJson(`/api/admin/beta/requests/${userId}/invite`, { + method: "POST", + })) as AdminInviteResponse; } async function onSendInviteEmail(userId: number) { @@ -241,19 +224,6 @@ export default function AdminBetaInvitesPage() { // eslint-disable-next-line react-hooks/exhaustive-deps }, [page]); - const isAdmin = (user?.role ?? "").toUpperCase() === "ADMIN"; - - if (!isAdmin) { - return ( -
-

Admin

-

- You don’t have access to this page. -

-
- ); - } - return (
diff --git a/app/admin/email/manage/page.tsx b/app/admin/email/manage/page.tsx index 11a61a8..375c4ce 100644 --- a/app/admin/email/manage/page.tsx +++ b/app/admin/email/manage/page.tsx @@ -1,7 +1,6 @@ "use client"; import { useCallback, useEffect, useMemo, useState } from "react"; -import { useAuth } from "@/context/AuthContext"; import { fetchEmailRequests, createEmailRequest, @@ -17,7 +16,6 @@ import { formatDate } from "@/lib/dateFormattingUtility"; type EmailStatusTab = "ALL" | "PENDING" | "SENT" | "FAILED" | "OTHER"; export default function AdminEmailPage() { - const { token } = useAuth(); const [emails, setEmails] = useState([]); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); @@ -33,11 +31,9 @@ export default function AdminEmailPage() { const [statusTab, setStatusTab] = useState("ALL"); const loadEmails = useCallback(async () => { - if (!token) return; - try { setLoading(true); - const data = await fetchEmailRequests(token); + const data = await fetchEmailRequests(); setEmails(data); setError(null); } catch (e: any) { @@ -46,7 +42,7 @@ export default function AdminEmailPage() { } finally { setLoading(false); } - }, [token]); + }, []); useEffect(() => { loadEmails(); @@ -108,11 +104,10 @@ export default function AdminEmailPage() { }; const handleDelete = async (id: number) => { - if (!token) return; if (!confirm("Are you sure you want to delete this email request?")) return; try { - await deleteEmailRequest(token, id); + await deleteEmailRequest(id); await loadEmails(); } catch (e: any) { alert(e?.message ?? "Failed to delete email request"); @@ -121,17 +116,15 @@ export default function AdminEmailPage() { const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); - if (!token) return; - try { setSubmitting(true); if (modalMode === "create") { - await createEmailRequest(token, formData); + await createEmailRequest(formData); } else if (selectedEmail) { const updateData: UpdateEmailRequestDto = {}; if (formData.email !== selectedEmail.email) updateData.email = formData.email; if (formData.status !== selectedEmail.status) updateData.status = formData.status; - await updateEmailRequest(token, selectedEmail.id, updateData); + await updateEmailRequest(selectedEmail.id, updateData); } setShowModal(false); await loadEmails(); @@ -142,14 +135,6 @@ export default function AdminEmailPage() { } }; - if (!token) { - return ( -
- You must be logged in to view this page. -
- ); - } - return (
{/* Header */} diff --git a/app/admin/email/page.tsx b/app/admin/email/page.tsx index 6c03355..d7360ea 100644 --- a/app/admin/email/page.tsx +++ b/app/admin/email/page.tsx @@ -1,7 +1,6 @@ "use client"; import { useCallback, useEffect, useState } from "react"; -import { useAuth } from "@/context/AuthContext"; import { fetchEmailRequests, createEmailRequest, @@ -14,7 +13,6 @@ import { import { Pencil, Trash2, Plus, X } from "lucide-react"; import { formatDate } from "@/lib/dateFormattingUtility"; export default function AdminEmailPage() { - const { token } = useAuth(); const [emails, setEmails] = useState([]); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); @@ -28,11 +26,9 @@ export default function AdminEmailPage() { const [submitting, setSubmitting] = useState(false); const loadEmails = useCallback(async () => { - if (!token) return; - try { setLoading(true); - const data = await fetchEmailRequests(token); + const data = await fetchEmailRequests(); setEmails(data); setError(null); } catch (e: any) { @@ -41,7 +37,7 @@ export default function AdminEmailPage() { } finally { setLoading(false); } - }, [token]); + }, []); useEffect(() => { loadEmails(); @@ -62,11 +58,10 @@ export default function AdminEmailPage() { }; const handleDelete = async (id: number) => { - if (!token) return; if (!confirm("Are you sure you want to delete this email request?")) return; try { - await deleteEmailRequest(token, id); + await deleteEmailRequest(id); await loadEmails(); } catch (e: any) { alert(e?.message ?? "Failed to delete email request"); @@ -75,17 +70,15 @@ export default function AdminEmailPage() { const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); - if (!token) return; - try { setSubmitting(true); if (modalMode === "create") { - await createEmailRequest(token, formData); + await createEmailRequest(formData); } else if (selectedEmail) { const updateData: UpdateEmailRequestDto = {}; if (formData.email !== selectedEmail.email) updateData.email = formData.email; if (formData.status !== selectedEmail.status) updateData.status = formData.status; - await updateEmailRequest(token, selectedEmail.id, updateData); + await updateEmailRequest(selectedEmail.id, updateData); } setShowModal(false); await loadEmails(); @@ -96,14 +89,6 @@ export default function AdminEmailPage() { } }; - if (!token) { - return ( -
- You must be logged in to view this page. -
- ); - } - return (
{/* Header */} diff --git a/app/admin/layout.tsx b/app/admin/layout.tsx index d787cd0..5552611 100644 --- a/app/admin/layout.tsx +++ b/app/admin/layout.tsx @@ -149,7 +149,7 @@ export default function AdminLayout({ return ( // ✅ prevent browser-level horizontal scroll from any wide children -
+
setCollapsed((v) => !v)} @@ -158,7 +158,7 @@ export default function AdminLayout({ {/* ✅ min-w-0 is the critical fix: lets the main column shrink */}
@@ -173,17 +173,14 @@ export default function AdminLayout({ Internal • v0.1 -
- ADMIN -
{/* ✅ min-w-0 here prevents table min-width from widening the page */} -
+
{children}
); -} \ No newline at end of file +} diff --git a/app/api/admin/beta-invites/route.ts b/app/api/admin/beta-invites/route.ts index 54d4417..d2606b4 100644 --- a/app/api/admin/beta-invites/route.ts +++ b/app/api/admin/beta-invites/route.ts @@ -6,7 +6,7 @@ const API_BASE_URL = // POST /api/admin/beta-invites?dryRun=true&limit=10&tokenMinutes=30 export async function POST(req: Request) { - const token = cookies().get("bb_access_token")?.value; + const token = cookies().get("session_token")?.value; if (!token) { return NextResponse.json({ error: "Missing admin token" }, { status: 401 }); @@ -32,4 +32,4 @@ export async function POST(req: Request) { status: res.status, headers: { "Content-Type": res.headers.get("content-type") ?? "application/json" }, }); -} \ No newline at end of file +} diff --git a/app/api/admin/beta/requests/[id]/invite/route.ts b/app/api/admin/beta/requests/[id]/invite/route.ts new file mode 100644 index 0000000..4fcb173 --- /dev/null +++ b/app/api/admin/beta/requests/[id]/invite/route.ts @@ -0,0 +1,39 @@ +import { NextResponse } from "next/server"; +import { cookies } from "next/headers"; + +const API_BASE_URL = + process.env.API_BASE_URL || process.env.NEXT_PUBLIC_API_BASE_URL; + +async function getAuthHeader() { + const token = cookies().get("session_token")?.value; + if (!token) throw new Error("Unauthorized"); + return { Authorization: `Bearer ${token}` }; +} + +export async function POST( + _req: Request, + { params }: { params: { id: string } } +) { + try { + const headers = await getAuthHeader(); + const res = await fetch( + `${API_BASE_URL}/api/v1/admin/beta/requests/${params.id}/invite`, + { + method: "POST", + headers, + cache: "no-store", + } + ); + + if (!res.ok) { + return NextResponse.json( + { error: await res.text() }, + { status: res.status } + ); + } + + return NextResponse.json(await res.json()); + } catch (err: any) { + return NextResponse.json({ error: "Unauthorized" }, { status: 401 }); + } +} diff --git a/app/api/admin/beta/requests/route.ts b/app/api/admin/beta/requests/route.ts new file mode 100644 index 0000000..a4b35d4 --- /dev/null +++ b/app/api/admin/beta/requests/route.ts @@ -0,0 +1,39 @@ +import { NextResponse } from "next/server"; +import { cookies } from "next/headers"; + +const API_BASE_URL = + process.env.API_BASE_URL || process.env.NEXT_PUBLIC_API_BASE_URL; + +async function getAuthHeader() { + const token = cookies().get("session_token")?.value; + if (!token) throw new Error("Unauthorized"); + return { Authorization: `Bearer ${token}` }; +} + +export async function GET(req: Request) { + try { + const headers = await getAuthHeader(); + const url = new URL(req.url); + const search = url.searchParams.toString(); + + const upstream = `${API_BASE_URL}/api/v1/admin/beta/requests${ + search ? `?${search}` : "" + }`; + + const res = await fetch(upstream, { + headers, + cache: "no-store", + }); + + if (!res.ok) { + return NextResponse.json( + { error: await res.text() }, + { status: res.status } + ); + } + + return NextResponse.json(await res.json()); + } catch (err: any) { + return NextResponse.json({ error: "Unauthorized" }, { status: 401 }); + } +} diff --git a/app/api/admin/email/[id]/route.ts b/app/api/admin/email/[id]/route.ts new file mode 100644 index 0000000..3cca2bc --- /dev/null +++ b/app/api/admin/email/[id]/route.ts @@ -0,0 +1,63 @@ +import { NextRequest, NextResponse } from "next/server"; +import { cookies } from "next/headers"; + +const API_BASE_URL = + process.env.API_BASE_URL || process.env.NEXT_PUBLIC_API_BASE_URL; + +async function getAuthHeader() { + const token = cookies().get("session_token")?.value; + if (!token) throw new Error("Unauthorized"); + return { Authorization: `Bearer ${token}` }; +} + +export async function PUT( + request: NextRequest, + { params }: { params: { id: string } } +) { + try { + const headers = await getAuthHeader(); + const body = await request.json(); + + const res = await fetch(`${API_BASE_URL}/api/email/${params.id}`, { + method: "PUT", + headers: { ...headers, "Content-Type": "application/json" }, + body: JSON.stringify(body), + }); + + if (!res.ok) { + return NextResponse.json( + { error: await res.text() }, + { status: res.status } + ); + } + + return NextResponse.json(await res.json()); + } catch (err: any) { + return NextResponse.json({ error: "Unauthorized" }, { status: 401 }); + } +} + +export async function DELETE( + request: NextRequest, + { params }: { params: { id: string } } +) { + try { + const headers = await getAuthHeader(); + + const res = await fetch(`${API_BASE_URL}/api/email/${params.id}`, { + method: "DELETE", + headers, + }); + + if (!res.ok) { + return NextResponse.json( + { error: await res.text() }, + { status: res.status } + ); + } + + return NextResponse.json({ ok: true }); + } catch (err: any) { + return NextResponse.json({ error: "Unauthorized" }, { status: 401 }); + } +} diff --git a/app/api/admin/email/route.ts b/app/api/admin/email/route.ts new file mode 100644 index 0000000..b03331f --- /dev/null +++ b/app/api/admin/email/route.ts @@ -0,0 +1,56 @@ +import { NextRequest, NextResponse } from "next/server"; +import { cookies } from "next/headers"; + +const API_BASE_URL = + process.env.API_BASE_URL || process.env.NEXT_PUBLIC_API_BASE_URL; + +async function getAuthHeader() { + const token = cookies().get("session_token")?.value; + if (!token) throw new Error("Unauthorized"); + return { Authorization: `Bearer ${token}` }; +} + +export async function GET() { + try { + const headers = await getAuthHeader(); + const res = await fetch(`${API_BASE_URL}/api/email`, { + headers, + cache: "no-store", + }); + + if (!res.ok) { + return NextResponse.json( + { error: await res.text() }, + { status: res.status } + ); + } + + return NextResponse.json(await res.json()); + } catch (err: any) { + return NextResponse.json({ error: "Unauthorized" }, { status: 401 }); + } +} + +export async function POST(request: NextRequest) { + try { + const headers = await getAuthHeader(); + const body = await request.json(); + + const res = await fetch(`${API_BASE_URL}/api/email`, { + method: "POST", + headers: { ...headers, "Content-Type": "application/json" }, + body: JSON.stringify(body), + }); + + if (!res.ok) { + return NextResponse.json( + { error: await res.text() }, + { status: res.status } + ); + } + + return NextResponse.json(await res.json()); + } catch (err: any) { + return NextResponse.json({ error: "Unauthorized" }, { status: 401 }); + } +} diff --git a/components/AdminLeftNavigation.tsx b/components/AdminLeftNavigation.tsx index b808bf8..d0da01d 100644 --- a/components/AdminLeftNavigation.tsx +++ b/components/AdminLeftNavigation.tsx @@ -5,6 +5,7 @@ import Link from "next/link"; import { usePathname } from "next/navigation"; import { Disclosure, DisclosureButton, DisclosurePanel } from "@headlessui/react"; import { ChevronRight, PanelLeftClose, PanelLeftOpen } from "lucide-react"; +import { useAuth } from "@/context/AuthContext"; export type AdminNavItem = { label: string; @@ -42,14 +43,21 @@ export default function AdminLeftNavigation({ groups: AdminNavGroup[]; }) { const pathname = usePathname() || "/admin"; + const { user } = useAuth(); + const identity = + user?.displayName?.trim() || + user?.username?.trim() || + user?.email?.trim() || + user?.uuid || + "Admin"; + const secondary = user?.email && user.email !== identity ? user.email : null; return ( ); -} \ No newline at end of file +} diff --git a/components/Banner.tsx b/components/Banner.tsx index b2f46b4..99e8d3d 100644 --- a/components/Banner.tsx +++ b/components/Banner.tsx @@ -1,8 +1,14 @@ +"use client"; + import React from "react"; +import { usePathname } from "next/navigation"; export function Banner() { + const pathname = usePathname(); + if (pathname?.startsWith("/admin")) return null; + return ( -
+
{/* Early access bar */}
diff --git a/components/ui/RichTextEditor.tsx b/components/ui/RichTextEditor.tsx index 49308b3..d81eb8f 100644 --- a/components/ui/RichTextEditor.tsx +++ b/components/ui/RichTextEditor.tsx @@ -1,17 +1,11 @@ -"use client"; -import dynamic from "next/dynamic"; -import type React from "react"; - -import "react-quill/dist/quill.snow.css"; - -// Import Quill modules after React Quill is loaded -if (typeof window !== 'undefined') { - const Quill = require('quill'); - const QuillImageResize = require('quill-image-resize-module').default; - Quill.register("modules/imageResize", QuillImageResize); -} - -const ReactQuill = dynamic(() => import("react-quill"), { ssr: false }); +"use client"; +import { useMemo } from "react"; +import dynamic from "next/dynamic"; +import type React from "react"; + +import "react-quill/dist/quill.snow.css"; + +const ReactQuill = dynamic(() => import("react-quill"), { ssr: false }); type RichTextEditorProps = { value: string; @@ -20,33 +14,38 @@ type RichTextEditorProps = { className?: string; }; -export default function RichTextEditor({ - value, - onChange, - placeholder, - className, - }: RichTextEditorProps) { - return ( -
-
- -
-
- ); -} \ No newline at end of file +export default function RichTextEditor({ + value, + onChange, + placeholder, + className, + }: RichTextEditorProps) { + const modules = useMemo( + () => ({ + toolbar: [ + [{ header: [1, 2, 3, false] }], + ["bold", "italic", "underline", "strike"], + [{ color: [] }, { background: [] }], + [{ list: "ordered" }, { list: "bullet" }], + ["blockquote", "code-block"], + ["link"], + ["clean"], + ], + }), + [] + ); + + return ( +
+
+ +
+
+ ); +} diff --git a/context/AuthContext.tsx b/context/AuthContext.tsx index ca9842c..6612a9b 100644 --- a/context/AuthContext.tsx +++ b/context/AuthContext.tsx @@ -33,6 +33,7 @@ type AuthContextValue = { register: (params: RegisterParams) => Promise; logout: () => void; refreshUser: () => Promise; + getAuthHeaders: () => HeadersInit; }; const AuthContext = createContext(undefined); @@ -210,6 +211,15 @@ export function AuthProvider({ children }: { children: ReactNode }) { }).catch(() => {}); }, [persistUser]); + const getAuthHeaders = useCallback((): HeadersInit => { + if (typeof window === "undefined") return {}; + const token = + localStorage.getItem("token") || + localStorage.getItem("jwt") || + localStorage.getItem("accessToken"); + return token ? { Authorization: `Bearer ${token}` } : {}; + }, []); + const value: AuthContextValue = { user, loading, @@ -217,6 +227,7 @@ export function AuthProvider({ children }: { children: ReactNode }) { register, logout, refreshUser, + getAuthHeaders, }; return {children}; diff --git a/lib/api/emailRequests.ts b/lib/api/emailRequests.ts index 0958bcd..dfe931e 100644 --- a/lib/api/emailRequests.ts +++ b/lib/api/emailRequests.ts @@ -17,64 +17,64 @@ export interface UpdateEmailRequestDto { status?: string; } -const API_BASE = process.env.NEXT_PUBLIC_API_BASE_URL || ''; +export async function fetchEmailRequests(): Promise { + const response = await fetch("/api/admin/email", { cache: "no-store" }); -export async function fetchEmailRequests(token: string): Promise { - const response = await fetch(`${API_BASE}/api/email`, { - headers: { - Authorization: `Bearer ${token}`, - }, - }); - if (!response.ok) { throw new Error(`Failed to fetch email requests: ${response.statusText}`); } - - return response.json(); + + const data = (await response.json()) as unknown; + if (Array.isArray(data)) return data as EmailRequest[]; + + const wrapped = data as { data?: unknown; content?: unknown }; + if (Array.isArray(wrapped.data)) return wrapped.data as EmailRequest[]; + if (Array.isArray(wrapped.content)) return wrapped.content as EmailRequest[]; + return []; } -export async function createEmailRequest(token: string, data: CreateEmailRequestDto): Promise { - const response = await fetch(`${API_BASE}/api/email`, { - method: 'POST', +export async function createEmailRequest( + data: CreateEmailRequestDto +): Promise { + const response = await fetch("/api/admin/email", { + method: "POST", headers: { - 'Content-Type': 'application/json', - Authorization: `Bearer ${token}`, + "Content-Type": "application/json", }, body: JSON.stringify(data), }); - + if (!response.ok) { throw new Error(`Failed to create email request: ${response.statusText}`); } - + return response.json(); } -export async function updateEmailRequest(token: string, id: number, data: UpdateEmailRequestDto): Promise { - const response = await fetch(`${API_BASE}/api/email/${id}`, { - method: 'PUT', +export async function updateEmailRequest( + id: number, + data: UpdateEmailRequestDto +): Promise { + const response = await fetch(`/api/admin/email/${id}`, { + method: "PUT", headers: { - 'Content-Type': 'application/json', - Authorization: `Bearer ${token}`, + "Content-Type": "application/json", }, body: JSON.stringify(data), }); - + if (!response.ok) { throw new Error(`Failed to update email request: ${response.statusText}`); } - + return response.json(); } -export async function deleteEmailRequest(token: string, id: number): Promise { - const response = await fetch(`${API_BASE}/api/email/${id}`, { - method: 'DELETE', - headers: { - Authorization: `Bearer ${token}`, - }, +export async function deleteEmailRequest(id: number): Promise { + const response = await fetch(`/api/admin/email/${id}`, { + method: "DELETE", }); - + if (!response.ok) { throw new Error(`Failed to delete email request: ${response.statusText}`); }