fix admin pages

This commit is contained in:
root
2026-05-17 17:37:13 -04:00
parent 0b73504455
commit 5ea1780134
12 changed files with 42 additions and 53 deletions
@@ -1,8 +1,7 @@
'use client' 'use client'
import { useEffect, useState } from 'react' import { useEffect, useState } from 'react'
import { ADMIN_API_BASE } from '@/lib/api'
const API_BASE = '/api/v1'
interface AdminUser { interface AdminUser {
id: string id: string
@@ -29,7 +28,7 @@ export default function AdminUsersPage() {
async function fetchAdmins() { async function fetchAdmins() {
try { try {
const res = await fetch(`${API_BASE}/admin/admins`, { const res = await fetch(`${ADMIN_API_BASE}/admin/admins`, {
headers: { Authorization: `Bearer ${getToken()}` }, headers: { Authorization: `Bearer ${getToken()}` },
cache: 'no-store', cache: 'no-store',
}) })
@@ -50,7 +49,7 @@ export default function AdminUsersPage() {
setCreating(true) setCreating(true)
setError(null) setError(null)
try { try {
const res = await fetch(`${API_BASE}/admin/admins`, { const res = await fetch(`${ADMIN_API_BASE}/admin/admins`, {
method: 'POST', method: 'POST',
headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${getToken()}` }, headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${getToken()}` },
body: JSON.stringify(form), body: JSON.stringify(form),
@@ -1,8 +1,7 @@
'use client' 'use client'
import { useEffect, useState } from 'react' import { useEffect, useState } from 'react'
import { ADMIN_API_BASE } from '@/lib/api'
const API_BASE = '/api/v1'
interface AuditLog { interface AuditLog {
id: string id: string
@@ -30,7 +29,7 @@ export default function AdminAuditLogsPage() {
useEffect(() => { useEffect(() => {
const token = localStorage.getItem('admin_token') ?? '' const token = localStorage.getItem('admin_token') ?? ''
fetch(`${API_BASE}/admin/audit-logs`, { fetch(`${ADMIN_API_BASE}/admin/audit-logs`, {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
cache: 'no-store', cache: 'no-store',
}) })
@@ -2,8 +2,7 @@
import { useEffect, useState } from 'react' import { useEffect, useState } from 'react'
import { useAdminI18n } from '@/components/I18nProvider' import { useAdminI18n } from '@/components/I18nProvider'
import { ADMIN_API_BASE } from '@/lib/api'
const API_BASE = '/api/v1'
interface Company { interface Company {
id: string id: string
@@ -216,7 +215,7 @@ export default function AdminBillingPage() {
try { try {
const params = new URLSearchParams({ pageSize: '50' }) const params = new URLSearchParams({ pageSize: '50' })
if (status) params.set('status', status) if (status) params.set('status', status)
const res = await fetch(`${API_BASE}/admin/billing?${params}`, { const res = await fetch(`${ADMIN_API_BASE}/admin/billing?${params}`, {
headers: token ? { Authorization: `Bearer ${token}` } : {}, headers: token ? { Authorization: `Bearer ${token}` } : {},
cache: 'no-store', cache: 'no-store',
}) })
@@ -236,7 +235,7 @@ export default function AdminBillingPage() {
async function downloadInvoicePdf(invoiceId: string, createdAt: string) { async function downloadInvoicePdf(invoiceId: string, createdAt: string) {
const token = localStorage.getItem('admin_token') const token = localStorage.getItem('admin_token')
try { try {
const res = await fetch(`${API_BASE}/admin/billing/invoices/${invoiceId}/pdf`, { const res = await fetch(`${ADMIN_API_BASE}/admin/billing/invoices/${invoiceId}/pdf`, {
headers: token ? { Authorization: `Bearer ${token}` } : {}, headers: token ? { Authorization: `Bearer ${token}` } : {},
}) })
if (!res.ok) throw new Error('Failed to generate PDF') if (!res.ok) throw new Error('Failed to generate PDF')
@@ -259,7 +258,7 @@ export default function AdminBillingPage() {
setInvoicesLoading(true) setInvoicesLoading(true)
const token = localStorage.getItem('admin_token') const token = localStorage.getItem('admin_token')
try { try {
const res = await fetch(`${API_BASE}/admin/billing/${companyId}/invoices?pageSize=50`, { const res = await fetch(`${ADMIN_API_BASE}/admin/billing/${companyId}/invoices?pageSize=50`, {
headers: token ? { Authorization: `Bearer ${token}` } : {}, headers: token ? { Authorization: `Bearer ${token}` } : {},
}) })
const json = await res.json() const json = await res.json()
@@ -3,8 +3,7 @@
import { useEffect, useState } from 'react' import { useEffect, useState } from 'react'
import { useParams, useRouter } from 'next/navigation' import { useParams, useRouter } from 'next/navigation'
import Link from 'next/link' import Link from 'next/link'
import { ADMIN_API_BASE } from '@/lib/api'
const API_BASE = '/api/v1'
interface CompanyDetail { interface CompanyDetail {
id: string id: string
@@ -239,8 +238,8 @@ export default function AdminCompanyDetailPage() {
const headers = { Authorization: `Bearer ${getToken()}` } const headers = { Authorization: `Bearer ${getToken()}` }
try { try {
const [cRes, aRes] = await Promise.all([ const [cRes, aRes] = await Promise.all([
fetch(`${API_BASE}/admin/companies/${id}`, { headers, cache: 'no-store' }), fetch(`${ADMIN_API_BASE}/admin/companies/${id}`, { headers, cache: 'no-store' }),
fetch(`${API_BASE}/admin/audit-logs?entityId=${id}&pageSize=10`, { headers, cache: 'no-store' }), fetch(`${ADMIN_API_BASE}/admin/audit-logs?entityId=${id}&pageSize=10`, { headers, cache: 'no-store' }),
]) ])
const cJson = await cRes.json() const cJson = await cRes.json()
const aJson = await aRes.json() const aJson = await aRes.json()
@@ -268,7 +267,7 @@ export default function AdminCompanyDetailPage() {
setSavedMessage(null) setSavedMessage(null)
setError(null) setError(null)
try { try {
const res = await fetch(`${API_BASE}/admin/companies/${id}`, { const res = await fetch(`${ADMIN_API_BASE}/admin/companies/${id}`, {
method: 'PATCH', method: 'PATCH',
headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${getToken()}` }, headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${getToken()}` },
body: JSON.stringify({ body: JSON.stringify({
@@ -346,7 +345,7 @@ export default function AdminCompanyDetailPage() {
setActioning(true) setActioning(true)
setError(null) setError(null)
try { try {
const res = await fetch(`${API_BASE}/admin/companies/${id}/status`, { const res = await fetch(`${ADMIN_API_BASE}/admin/companies/${id}/status`, {
method: 'PATCH', method: 'PATCH',
headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${getToken()}` }, headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${getToken()}` },
body: JSON.stringify({ status }), body: JSON.stringify({ status }),
@@ -364,7 +363,7 @@ export default function AdminCompanyDetailPage() {
async function deleteCompany() { async function deleteCompany() {
setActioning(true) setActioning(true)
try { try {
const res = await fetch(`${API_BASE}/admin/companies/${id}`, { const res = await fetch(`${ADMIN_API_BASE}/admin/companies/${id}`, {
method: 'DELETE', method: 'DELETE',
headers: { Authorization: `Bearer ${getToken()}` }, headers: { Authorization: `Bearer ${getToken()}` },
}) })
@@ -3,8 +3,7 @@
import { useEffect, useState } from 'react' import { useEffect, useState } from 'react'
import Link from 'next/link' import Link from 'next/link'
import { useAdminI18n } from '@/components/I18nProvider' import { useAdminI18n } from '@/components/I18nProvider'
import { ADMIN_API_BASE } from '@/lib/api'
const API_BASE = '/api/v1'
interface Company { interface Company {
id: string id: string
@@ -83,7 +82,7 @@ export default function AdminCompaniesPage() {
async function fetchCompanies() { async function fetchCompanies() {
const token = localStorage.getItem('admin_token') const token = localStorage.getItem('admin_token')
try { try {
const res = await fetch(`${API_BASE}/admin/companies`, { const res = await fetch(`${ADMIN_API_BASE}/admin/companies`, {
headers: token ? { Authorization: `Bearer ${token}` } : {}, headers: token ? { Authorization: `Bearer ${token}` } : {},
cache: 'no-store', cache: 'no-store',
}) })
@@ -109,7 +108,7 @@ export default function AdminCompaniesPage() {
setActioning(id) setActioning(id)
const token = localStorage.getItem('admin_token') const token = localStorage.getItem('admin_token')
try { try {
const res = await fetch(`${API_BASE}/admin/companies/${id}/status`, { const res = await fetch(`${ADMIN_API_BASE}/admin/companies/${id}/status`, {
method: 'PATCH', method: 'PATCH',
headers: { 'Content-Type': 'application/json', ...(token ? { Authorization: `Bearer ${token}` } : {}) }, headers: { 'Content-Type': 'application/json', ...(token ? { Authorization: `Bearer ${token}` } : {}) },
body: JSON.stringify({ status }), body: JSON.stringify({ status }),
@@ -1,8 +1,7 @@
'use client' 'use client'
import { useCallback, useEffect, useRef, useState } from 'react' import { useCallback, useEffect, useRef, useState } from 'react'
import { ADMIN_API_BASE } from '@/lib/api'
const API_BASE = '/api/v1'
type ContainerStatus = 'PENDING' | 'CREATING' | 'RUNNING' | 'STOPPED' | 'RESTARTING' | 'REMOVING' | 'ERROR' type ContainerStatus = 'PENDING' | 'CREATING' | 'RUNNING' | 'STOPPED' | 'RESTARTING' | 'REMOVING' | 'ERROR'
@@ -58,7 +57,7 @@ function LogsModal({ companyId, companyName, onClose }: { companyId: string; com
const fetchLogs = useCallback(async (lines: number) => { const fetchLogs = useCallback(async (lines: number) => {
setLoading(true) setLoading(true)
try { try {
const res = await fetch(`${API_BASE}/admin/containers/${companyId}/logs?tail=${lines}`, { headers: authHeaders() }) const res = await fetch(`${ADMIN_API_BASE}/admin/containers/${companyId}/logs?tail=${lines}`, { headers: authHeaders() })
const json = await res.json() const json = await res.json()
setLogs(json.data?.logs ?? '') setLogs(json.data?.logs ?? '')
} catch { } catch {
@@ -127,7 +126,7 @@ export default function ContainersPage() {
const fetchContainers = useCallback(async () => { const fetchContainers = useCallback(async () => {
try { try {
const res = await fetch(`${API_BASE}/admin/containers`, { headers: authHeaders() }) const res = await fetch(`${ADMIN_API_BASE}/admin/containers`, { headers: authHeaders() })
const json = await res.json().catch(() => null) const json = await res.json().catch(() => null)
if (!res.ok) { if (!res.ok) {
throw new Error(json?.message ?? 'Failed to load containers.') throw new Error(json?.message ?? 'Failed to load containers.')
@@ -152,7 +151,7 @@ export default function ContainersPage() {
setProvisioning(true) setProvisioning(true)
setProvisionResults(null) setProvisionResults(null)
try { try {
const res = await fetch(`${API_BASE}/admin/containers/provision-all`, { method: 'POST', headers: authHeaders() }) const res = await fetch(`${ADMIN_API_BASE}/admin/containers/provision-all`, { method: 'POST', headers: authHeaders() })
const json = await res.json().catch(() => null) const json = await res.json().catch(() => null)
if (!res.ok) throw new Error(json?.message ?? 'Provisioning failed.') if (!res.ok) throw new Error(json?.message ?? 'Provisioning failed.')
setProvisionResults(json.data?.results ?? []) setProvisionResults(json.data?.results ?? [])
@@ -171,8 +170,8 @@ export default function ContainersPage() {
const method = action === 'remove' ? 'DELETE' : 'POST' const method = action === 'remove' ? 'DELETE' : 'POST'
const url = const url =
action === 'remove' action === 'remove'
? `${API_BASE}/admin/containers/${companyId}` ? `${ADMIN_API_BASE}/admin/containers/${companyId}`
: `${API_BASE}/admin/containers/${companyId}/${action}` : `${ADMIN_API_BASE}/admin/containers/${companyId}/${action}`
const res = await fetch(url, { method, headers: authHeaders() }) const res = await fetch(url, { method, headers: authHeaders() })
const json = await res.json().catch(() => null) const json = await res.json().catch(() => null)
if (!res.ok) { if (!res.ok) {
+2 -3
View File
@@ -3,8 +3,7 @@
import { useEffect, useState } from 'react' import { useEffect, useState } from 'react'
import Link from 'next/link' import Link from 'next/link'
import { useAdminI18n } from '@/components/I18nProvider' import { useAdminI18n } from '@/components/I18nProvider'
import { ADMIN_API_BASE } from '@/lib/api'
const API_BASE = '/api/v1'
interface Metrics { interface Metrics {
totalCompanies: number totalCompanies: number
@@ -50,7 +49,7 @@ export default function AdminDashboardPage() {
useEffect(() => { useEffect(() => {
const token = localStorage.getItem('admin_token') ?? '' const token = localStorage.getItem('admin_token') ?? ''
fetch(`${API_BASE}/admin/metrics`, { fetch(`${ADMIN_API_BASE}/admin/metrics`, {
headers: { Authorization: `Bearer ${token}` }, headers: { Authorization: `Bearer ${token}` },
cache: 'no-store', cache: 'no-store',
}) })
@@ -2,8 +2,7 @@
import { useEffect, useState } from 'react' import { useEffect, useState } from 'react'
import { useAdminI18n } from '@/components/I18nProvider' import { useAdminI18n } from '@/components/I18nProvider'
import { ADMIN_API_BASE } from '@/lib/api'
const API_BASE = '/api/v1'
interface Renter { interface Renter {
id: string id: string
@@ -75,7 +74,7 @@ export default function AdminRentersPage() {
async function fetchRenters() { async function fetchRenters() {
try { try {
const res = await fetch(`${API_BASE}/admin/renters`, { const res = await fetch(`${ADMIN_API_BASE}/admin/renters`, {
headers: { Authorization: `Bearer ${getToken()}` }, headers: { Authorization: `Bearer ${getToken()}` },
cache: 'no-store', cache: 'no-store',
}) })
@@ -103,7 +102,7 @@ export default function AdminRentersPage() {
setActioning(id) setActioning(id)
try { try {
const endpoint = isBlocked ? 'unblock' : 'block' const endpoint = isBlocked ? 'unblock' : 'block'
const res = await fetch(`${API_BASE}/admin/renters/${id}/${endpoint}`, { const res = await fetch(`${ADMIN_API_BASE}/admin/renters/${id}/${endpoint}`, {
method: 'POST', method: 'POST',
headers: { Authorization: `Bearer ${getToken()}` }, headers: { Authorization: `Bearer ${getToken()}` },
}) })
@@ -11,8 +11,7 @@ import {
type MarketplaceLanguage, type MarketplaceLanguage,
} from '@rentaldrivego/types' } from '@rentaldrivego/types'
import { useAdminI18n } from '@/components/I18nProvider' import { useAdminI18n } from '@/components/I18nProvider'
import { ADMIN_API_BASE } from '@/lib/api'
const API_BASE = '/api/v1'
interface Company { interface Company {
id: string id: string
@@ -187,11 +186,11 @@ export default function AdminSiteConfigPage() {
const token = localStorage.getItem('admin_token') const token = localStorage.getItem('admin_token')
try { try {
const [companiesRes, homepageRes] = await Promise.all([ const [companiesRes, homepageRes] = await Promise.all([
fetch(`${API_BASE}/admin/companies`, { fetch(`${ADMIN_API_BASE}/admin/companies`, {
headers: token ? { Authorization: `Bearer ${token}` } : {}, headers: token ? { Authorization: `Bearer ${token}` } : {},
cache: 'no-store', cache: 'no-store',
}), }),
fetch(`${API_BASE}/admin/site-config/marketplace-homepage`, { fetch(`${ADMIN_API_BASE}/admin/site-config/marketplace-homepage`, {
headers: token ? { Authorization: `Bearer ${token}` } : {}, headers: token ? { Authorization: `Bearer ${token}` } : {},
cache: 'no-store', cache: 'no-store',
}), }),
@@ -280,7 +279,7 @@ export default function AdminSiteConfigPage() {
const token = localStorage.getItem('admin_token') const token = localStorage.getItem('admin_token')
try { try {
const res = await fetch(`${API_BASE}/admin/site-config/marketplace-homepage`, { const res = await fetch(`${ADMIN_API_BASE}/admin/site-config/marketplace-homepage`, {
method: 'PATCH', method: 'PATCH',
headers: { headers: {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
+2 -3
View File
@@ -3,8 +3,7 @@
import Link from 'next/link' import Link from 'next/link'
import { useState } from 'react' import { useState } from 'react'
import PublicShell from '@/components/PublicShell' import PublicShell from '@/components/PublicShell'
import { ADMIN_API_BASE } from '@/lib/api'
const API_BASE = '/api/v1'
export default function AdminForgotPasswordPage() { export default function AdminForgotPasswordPage() {
const [email, setEmail] = useState('') const [email, setEmail] = useState('')
@@ -17,7 +16,7 @@ export default function AdminForgotPasswordPage() {
setLoading(true) setLoading(true)
setError(null) setError(null)
try { try {
const res = await fetch(`${API_BASE}/admin/auth/forgot-password`, { const res = await fetch(`${ADMIN_API_BASE}/admin/auth/forgot-password`, {
method: 'POST', method: 'POST',
headers: { 'Content-Type': 'application/json' }, headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ email }), body: JSON.stringify({ email }),
+2 -3
View File
@@ -4,8 +4,7 @@ import Link from 'next/link'
import { useState, Suspense } from 'react' import { useState, Suspense } from 'react'
import { useSearchParams, useRouter } from 'next/navigation' import { useSearchParams, useRouter } from 'next/navigation'
import PublicShell from '@/components/PublicShell' import PublicShell from '@/components/PublicShell'
import { ADMIN_API_BASE } from '@/lib/api'
const API_BASE = '/api/v1'
export default function AdminResetPasswordPage() { export default function AdminResetPasswordPage() {
return ( return (
@@ -33,7 +32,7 @@ function AdminResetPasswordContent() {
setLoading(true) setLoading(true)
setError(null) setError(null)
try { try {
const res = await fetch(`${API_BASE}/admin/auth/reset-password`, { const res = await fetch(`${ADMIN_API_BASE}/admin/auth/reset-password`, {
method: 'POST', method: 'POST',
headers: { 'Content-Type': 'application/json' }, headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ token, password }), body: JSON.stringify({ token, password }),
+5 -5
View File
@@ -1,10 +1,10 @@
const API_BASE = export const ADMIN_API_BASE =
(typeof window === 'undefined' ? process.env.API_INTERNAL_URL : '/api/v1') typeof window === 'undefined'
?? process.env.NEXT_PUBLIC_API_URL ? (process.env.API_INTERNAL_URL ?? process.env.NEXT_PUBLIC_API_URL ?? 'http://localhost:4000/api/v1')
?? 'http://localhost:4000/api/v1' : (process.env.NEXT_PUBLIC_API_URL ?? '/admin/api/v1')
export async function adminFetch<T>(path: string, token?: string): Promise<T> { export async function adminFetch<T>(path: string, token?: string): Promise<T> {
const res = await fetch(`${API_BASE}${path}`, { const res = await fetch(`${ADMIN_API_BASE}${path}`, {
cache: 'no-store', cache: 'no-store',
headers: token ? { Authorization: `Bearer ${token}` } : undefined, headers: token ? { Authorization: `Bearer ${token}` } : undefined,
}) })