Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions apps/web/app/(protected)/disputes/[id]/page.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
'use client'

import React, { useState, useEffect } from 'react'
import { createClient } from '@/lib/superbase/client'
import { createClient } from '@/lib/supabase/client'
import { useParams, useRouter } from 'next/navigation'
import {
ShieldAlert,
Expand Down Expand Up @@ -32,6 +32,11 @@ export default function DisputeDetailPage() {
async function fetchDispute() {
try {
setLoading(true)
if (!params?.id) {
setError('Dispute ID not found')
setLoading(false)
return
}
const { data, error } = await supabase
.from('disputes')
.select(`
Expand All @@ -42,7 +47,7 @@ export default function DisputeDetailPage() {
listings (title)
)
`)
.eq('id', params.id)
.eq('id', params.id as string)
.single()

if (error) throw error
Expand Down
2 changes: 1 addition & 1 deletion apps/web/app/(protected)/disputes/page.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
'use client'

import React, { useState, useEffect } from 'react'
import { createClient } from '@/lib/superbase/client'
import { createClient } from '@/lib/supabase/client'
import {
AlertCircle,
CheckCircle2,
Expand Down
4 changes: 3 additions & 1 deletion apps/web/app/admin/disputes/[id]/page.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
'use client'

import React, { useState, useEffect } from 'react'
import { createClient } from '@/lib/superbase/client'
import { createClient } from '@/lib/supabase/client'
import { useParams, useRouter } from 'next/navigation'
import {
ShieldCheck,
Expand Down Expand Up @@ -37,6 +37,7 @@ export default function AdminDisputeDetailPage() {
async function fetchDispute() {
try {
setLoading(true)
if (!params?.id) throw new Error('Dispute ID not found')
const { data, error } = await supabase
.from('disputes')
.select(`
Expand Down Expand Up @@ -64,6 +65,7 @@ export default function AdminDisputeDetailPage() {
const handleUpdate = async (status: string) => {
setUpdating(true)
try {
if (!params?.id) throw new Error('Dispute ID not found')
const response = await fetch(`/api/disputes/${params.id}`, {
method: 'PATCH',
headers: { 'Content-Type': 'application/json' },
Expand Down
2 changes: 1 addition & 1 deletion apps/web/app/admin/disputes/page.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
'use client'

import React, { useState, useEffect } from 'react'
import { createClient } from '@/lib/superbase/client'
import { createClient } from '@/lib/supabase/client'
import {
ShieldCheck,
AlertTriangle,
Expand Down
4 changes: 4 additions & 0 deletions apps/web/app/admin/errors/[id]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ export const dynamic = "force-dynamic";
export default async function ErrorDetailPage({ params }: { params: { id: string } }) {
const supabase = await getServerClient();

if (!supabase) {
notFound();
}

// 1. Fetch the error group
const { data: group, error: groupError } = await supabase
.from("error_groups")
Expand Down
5 changes: 5 additions & 0 deletions apps/web/app/admin/errors/page.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
import { getServerClient } from "@/lib/supabase/server";
import Link from "next/link";
import { notFound } from "next/navigation";

export const dynamic = "force-dynamic";

export default async function ErrorListPage() {
const supabase = await getServerClient();

if (!supabase) {
notFound();
}

const { data: groups, error } = await supabase
.from("error_groups")
.select("*")
Expand Down
5 changes: 5 additions & 0 deletions apps/web/app/admin/errors/rules/page.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
import { getServerClient } from "@/lib/supabase/server";
import Link from "next/link";
import { notFound } from "next/navigation";

export const dynamic = "force-dynamic";

export default async function AlertRulesPage() {
const supabase = await getServerClient();

if (!supabase) {
notFound();
}

const { data: rules, error } = await supabase
.from("alert_rules")
.select("*")
Expand Down
2 changes: 1 addition & 1 deletion apps/web/app/api/admin/users/[id]/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ function buildUserDetail(user: AdminUser): AdminUserDetail {
const activityLog: ActivityEvent[] = [
{
id: `${user.id}-act-1`,
type: "auth",
type: "auth" as const,
description: "User account created",
created_at: user.created_at,
},
Expand Down
4 changes: 2 additions & 2 deletions apps/web/app/api/disputes/[id]/route.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { createClient } from '@/lib/superbase/server'
import { createAdminClient } from '@/lib/superbase/admin'
import { createClient } from '@/lib/supabase/server'
import { createAdminClient } from '@/lib/supabase/admin'
import { NextResponse } from 'next/server'

export async function GET(
Expand Down
2 changes: 1 addition & 1 deletion apps/web/app/api/disputes/route.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { createClient } from '@/lib/superbase/server'
import { createClient } from '@/lib/supabase/server'
import { NextResponse } from 'next/server'

export async function POST(request: Request) {
Expand Down
2 changes: 1 addition & 1 deletion apps/web/app/api/ratings/route.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { createClient } from '@/lib/superbase/server'
import { createClient } from '@/lib/supabase/server'
import { NextResponse } from 'next/server'
import { validateSubmitRating } from '@/lib/validators/ratings'
import { Rating } from '@/lib/db/types'
Expand Down
4 changes: 2 additions & 2 deletions apps/web/app/api/users/[id]/stats/route.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { createClient } from '@/lib/superbase/server'
import { createClient } from '@/lib/supabase/server'
import { errorResponse, successResponse } from '@/lib/api-utils'
import { fetchUserStatsCached } from '@/lib/queries/user'
import { fetchUserStatsCached } from '@/lib/queries/users'

/**
* GET /api/users/[id]/stats
Expand Down
2 changes: 1 addition & 1 deletion apps/web/app/api/users/profile/route.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { NextRequest } from "next/server";
import { createClient } from "@/lib/superbase/server";
import { createClient } from "@/lib/supabase/server";
import { successResponse, handleError } from "@/app/api/utils/response";
import { requireAuth } from "@/app/api/utils/auth";

Expand Down
31 changes: 21 additions & 10 deletions apps/web/app/auth/register/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,9 @@ export default function RegisterPage() {
connect = wallet.connect;
isWalletConnecting = wallet.isInitializing;
} catch {
// During build, provider might not be available
isConnected = false;
walletPublicKey = null;
connect = async () => { };
connect = async () => {};
isWalletConnecting = false;
}

Expand All @@ -49,7 +48,15 @@ export default function RegisterPage() {
formState: { errors, isSubmitting },
} = useForm<RegisterFormData>({
resolver: zodResolver(registerSchema),
mode: "onChange",
// FIX 1: Only validate on submit, not on every keystroke.
mode: "onSubmit",
// FIX 2: All fields start as empty strings, not undefined.
defaultValues: {
username: "",
email: "",
password: "",
walletAddress: "",
},
});

const walletAddress = watch("walletAddress");
Expand All @@ -61,18 +68,16 @@ export default function RegisterPage() {
setError("Failed to connect wallet");
}
};

// Sync wallet public key into form when it changes
// FIX 3: shouldValidate: false so connecting a wallet doesn't trigger
useEffect(() => {
if (walletPublicKey) {
setValue("walletAddress", walletPublicKey);
setValue("walletAddress", walletPublicKey, { shouldValidate: false });
}
}, [walletPublicKey, setValue]);

const onSubmit = async (data: RegisterFormData) => {
setError("");
try {
// 1. Sign up user
const { data: authData, error: authError } = await supabase.auth.signUp({
email: data.email,
password: data.password,
Expand All @@ -90,7 +95,6 @@ export default function RegisterPage() {
}

if (authData.user) {
// 2. Create profile
const { error: profileError } = await supabase.from("profiles").insert({
id: authData.user.id,
username: data.username,
Expand All @@ -106,7 +110,7 @@ export default function RegisterPage() {
router.push("/dashboard");
router.refresh();
}
} catch (e) {
} catch {
setError("Something went wrong");
}
};
Expand Down Expand Up @@ -164,6 +168,13 @@ export default function RegisterPage() {
error={errors.password?.message}
register={register("password")}
/>
{/*
FIX 4: Register walletAddress as a hidden input so react-hook-form
actually tracks the field. Without this, the field is unknown to RHF
and its value stays `undefined` in the form state — causing Zod to
throw "expected string, received undefined" on any validation pass.
*/}
<input type="hidden" {...register("walletAddress")} />

<div className="space-y-2">
<label className="block text-sm font-medium text-gray-700 dark:text-gray-200">
Expand Down Expand Up @@ -198,4 +209,4 @@ export default function RegisterPage() {
</div>
</div>
);
}
}
2 changes: 1 addition & 1 deletion apps/web/app/disputes/new/page.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
'use client'

import React, { useState, useEffect } from 'react'
import { createClient } from '@/lib/superbase/client'
import { createClient } from '@/lib/supabase/client'
import { useSearchParams, useRouter } from 'next/navigation'
import {
ShieldAlert,
Expand Down
8 changes: 5 additions & 3 deletions apps/web/app/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
import "../lib/env";
import type { Metadata } from "next";
import { Inter } from "@fontsource-variable/inter";
import { ThemeProvider } from "@/lib/theme/provider";
import { ServiceWorkerProvider } from "@/components/providers/ServiceWorkerProvider";
import { ErrorProvider } from "@/components/providers/ErrorProvider";
import NextTopLoader from 'nextjs-toploader';
Expand All @@ -16,6 +14,8 @@ import { AnalyticsTracker } from '@/components/AnalyticsTracker';
import { Toaster } from 'react-hot-toast';
import "./globals.css";
import "@fontsource-variable/inter";
import { ThemeProvider } from "@/lib/theme/provider";
import ProtectedRoute from "@/components/protectedRoute";

// Dynamically import ComparisonBar to reduce initial bundle size
const ComparisonBar = dynamic(() => import("@/components/ComparisonBar"), {
Expand Down Expand Up @@ -44,9 +44,10 @@ export default function RootLayout({
>
{/* Global error boundary - wraps everything inside ThemeProvider */}
<ErrorProvider>
<ProtectedRoute>
{/* Loading bar at the top */}
<NextTopLoader color="#7D00FF" showSpinner={false} />

{/* Analytics tracking */}
<AnalyticsTracker />

Expand Down Expand Up @@ -91,6 +92,7 @@ export default function RootLayout({
},
}}
/>
</ProtectedRoute>
</ErrorProvider>
</ThemeProvider>
</body>
Expand Down
2 changes: 1 addition & 1 deletion apps/web/app/payments/page.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
'use client'

import React, { useState, useEffect } from 'react'
import { createClient } from '@/lib/superbase/client'
import { createClient } from '@/lib/supabase/client'
import {
CreditCard,
CheckCircle2,
Expand Down
34 changes: 23 additions & 11 deletions apps/web/app/profile/edit/page.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,8 @@
import { redirect } from "next/navigation";
import { createClient } from "@/lib/supabase/server";
import EditProfileForm from "@/components/profile/EditProfileForm";

import { useEffect, useState } from "react";
import { useRouter } from "next/navigation";
import Image from "next/image";
import useAuth from "@/lib/hooks/useAuth";
import { createBrowserClient } from "@/lib/supabase/client";

export default async function EditProfilePage() {
const supabase = await createClient();

Expand All @@ -19,6 +15,9 @@ export default async function EditProfilePage() {
redirect("/auth/login");
}

const uploading = false; // Replace with actual uploading state
const saving = false; // Replace with actual saving state

const { data: user, error: userError } = await supabase
.from("users")
.select("*")
Expand All @@ -34,23 +33,36 @@ export default async function EditProfilePage() {
);
}

const { username, email, bio, avatar_url: avatarUrl } = user;
const handleSave = async (updatedData: { username: string; email: string; bio: string; avatarUrl: string | null }) => {
// Implement profile update logic here, e.g. call an API route to update the user profile in the database
console.log("Saving profile with data:", updatedData);
}
const handleFileChange = async (e: React.ChangeEvent<HTMLInputElement>) => {
const file = e.target.files?.[0];
if (!file) return;

// Implement file upload logic here, e.g. upload to Supabase Storage and get the public URL
console.log("Selected file for avatar:", file);
}

return (
<main className="p-6 max-w-3xl mx-auto">
<h1 id="edit-profile-heading" className="text-2xl font-semibold mb-4">Edit Profile</h1>
<form onSubmit={handleSave} aria-labelledby="edit-profile-heading" className="grid gap-4 md:grid-cols-2">
<form onSubmit={()=>handleSave({ username, email, bio, avatarUrl })} aria-labelledby="edit-profile-heading" className="grid gap-4 md:grid-cols-2">
<label className="block md:col-span-1">
<div className="text-sm text-gray-300">Username</div>
<input id="username" value={username} onChange={(e) => setUsername(e.target.value)} className="mt-1 w-full rounded-md px-3 py-2 bg-gray-800 border border-white/10 focus:outline-none focus:ring-2 focus:ring-indigo-500" />
<input id="username" value={username} className="mt-1 w-full rounded-md px-3 py-2 bg-gray-800 border border-white/10 focus:outline-none focus:ring-2 focus:ring-indigo-500" />
</label>

<label className="block md:col-span-1">
<div className="text-sm text-gray-300">Email</div>
<input id="email" value={email} onChange={(e) => setEmail(e.target.value)} className="mt-1 w-full rounded-md px-3 py-2 bg-gray-800 border border-white/10 focus:outline-none focus:ring-2 focus:ring-indigo-500" />
<input id="email" value={email} className="mt-1 w-full rounded-md px-3 py-2 bg-gray-800 border border-white/10 focus:outline-none focus:ring-2 focus:ring-indigo-500" />
</label>

<label className="block md:col-span-2">
<div className="text-sm text-gray-300">Bio</div>
<textarea id="bio" value={bio} onChange={(e) => setBio(e.target.value)} className="mt-1 w-full rounded-md px-3 py-2 bg-gray-800 border border-white/10 focus:outline-none focus:ring-2 focus:ring-indigo-500" />
<textarea id="bio" value={bio} className="mt-1 w-full rounded-md px-3 py-2 bg-gray-800 border border-white/10 focus:outline-none focus:ring-2 focus:ring-indigo-500" />
</label>

<label className="block md:col-span-2">
Expand All @@ -72,10 +84,9 @@ export default async function EditProfilePage() {

<div className="flex items-center gap-3 md:col-span-2">
<button type="submit" disabled={saving} className="rounded-xl px-4 py-2 bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-indigo-500">{saving ? 'Saving...' : 'Save'}</button>
<button type="button" onClick={() => router.back()} className="rounded-xl px-4 py-2 border border-white/10">Cancel</button>
<button type="button" className="rounded-xl px-4 py-2 border border-white/10">Cancel</button>
</div>
</form>
</main>
<div className="container mx-auto px-4 py-8 md:py-12 max-w-4xl">
<div className="mb-8">
<h1 className="text-3xl font-bold text-white mb-2">Edit Profile</h1>
Expand All @@ -86,5 +97,6 @@ export default async function EditProfilePage() {

<EditProfileForm user={user} />
</div>
</main>
);
}
2 changes: 1 addition & 1 deletion apps/web/components/ErrorBoundary.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ class ErrorBoundary extends Component<Props, State> {
Something went wrong
</h2>
<p className="mb-6 text-gray-600 dark:text-gray-400">
We've been notified and are looking into it.
{"We've been notified and are looking into it."}
</p>
<button
onClick={() => this.setState({ hasError: false })}
Expand Down
Loading