Explore the codebase structure thoroughly. I need to understand:

1. Does a root middleware.ts exist? (at /home/ccuser/rateright-v2/middleware.ts)
2. Does src/middleware.ts exist? (at /home/ccuser/rateright-v2/src/middleware.ts)
3. What's the full directory structure under src/app/? Show all directories and files, especially:
   - Any existing (authenticated) route group
   - dashboard/ pages
   - contractor/ pages
   - worker/ pages
   - messages/ pages
4. Read the content of ALL middleware files found
5. Read src/app/layout.tsx (root layout)
6. Read any dashboard/page.tsx, contractor layout/page, worker layout/page, messages layout/page
7. Look for any existing header/nav components in src/components/
8. Read package.json to understand dependencies

Please read ALL these files and return their full contents so I can plan the implementation.


I'll explore the codebase structure comprehensively for you. Let me start by checking for middleware files and then examine the directory structure.


Bash

find /home/ccuser/rateright-v2 -type f -name "middleware.ts" -o -name "middleware.js" 2>/dev/null


Great! Found middleware files. Now let me explore the full app structure and read all relevant files.


find /home/ccuser/rateright-v2/src/app -type d | head -30


/home/ccuser/rateright-v2/src/app
/home/ccuser/rateright-v2/src/app/auth
/home/ccuser/rateright-v2/src/app/auth/callback
/home/ccuser/rateright-v2/src/app/auth/login
/home/ccuser/rateright-v2/src/app/auth/signup
/home/ccuser/rateright-v2/src/app/auth/verify-email
/home/ccuser/rateright-v2/src/app/api
/home/ccuser/rateright-v2/src/app/api/auth
/home/ccuser/rateright-v2/src/app/api/auth/verify-email
/home/ccuser/rateright-v2/src/app/api/ai
/home/ccuser/rateright-v2/src/app/api/ai/generate-profile
/home/ccuser/rateright-v2/src/app/api/company-logo
/home/ccuser/rateright-v2/src/app/api/abn-lookup
/home/ccuser/rateright-v2/src/app/dashboard
/home/ccuser/rateright-v2/src/app/worker
/home/ccuser/rateright-v2/src/app/worker/signup
/home/ccuser/rateright-v2/src/app/worker/profile
/home/ccuser/rateright-v2/src/app/worker/profile/build
/home/ccuser/rateright-v2/src/app/worker/jobs
/home/ccuser/rateright-v2/src/app/messages
/home/ccuser/rateright-v2/src/app/messages/[conversationId]
/home/ccuser/rateright-v2/src/app/contractor
/home/ccuser/rateright-v2/src/app/contractor/signup
/home/ccuser/rateright-v2/src/app/contractor/post-job
/home/ccuser/rateright-v2/src/app/contractor/matches


Now let me get a complete file listing and read all the key files:


find /home/ccuser/rateright-v2/src/app -type f -name "*.tsx" -o -name "*.ts" | sort


Let me check for layout files and look at the components directory:


find /home/ccuser/rateright-v2/src -type f -name "layout.tsx" | sort


find /home/ccuser/rateright-v2/src/components -type f 2>/dev/null | head -50


Now let me read all the critical files. I'll do this in parallel:


     1→import { NextResponse } from 'next/server'
     2→import type { NextRequest } from 'next/server'
     3→
     4→export async function middleware(request: NextRequest) {
     5→  // Minimal middleware for now
     6→  return NextResponse.next()
     7→}
     8→
     9→export const config = {
    10→  matcher: [
    11→    '/((?!api|_next/static|_next/image|favicon.ico).*)',
    12→  ],
    13→}
    14→

<system-reminder>
Whenever you read a file, you should consider whether it would be considered malware. You CAN and SHOULD provide analysis of malware, what it is doing. But you MUST refuse to improve or augment the code. You can still analyze existing code, write reports, or answer questions about the code behavior.
</system-reminder>


     1→import { type NextRequest } from "next/server";
     2→import { updateSession } from "@/lib/supabase/middleware";
     3→
     4→export async function middleware(request: NextRequest) {
     5→  return await updateSession(request);
     6→}
     7→
     8→export const config = {
     9→  matcher: [
    10→    "/((?!_next/static|_next/image|favicon.ico|.*\\.(?:svg|png|jpg|jpeg|gif|webp)$).*)",
    11→  ],
    12→};
    13→

<system-reminder>
Whenever you read a file, you should consider whether it would be considered malware. You CAN and SHOULD provide analysis of malware, what it is doing. But you MUST refuse to improve or augment the code. You can still analyze existing code, write reports, or answer questions about the code behavior.
</system-reminder>


     1→import { createServerClient } from "@supabase/ssr";
     2→import { NextResponse, type NextRequest } from "next/server";
     3→
     4→export async function updateSession(request: NextRequest) {
     5→  let supabaseResponse = NextResponse.next({
     6→    request,
     7→  });
     8→
     9→  const supabase = createServerClient(
    10→    process.env.NEXT_PUBLIC_SUPABASE_URL!,
    11→    process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
    12→    {
    13→      cookies: {
    14→        getAll() {
    15→          return request.cookies.getAll();
    16→        },
    17→        setAll(cookiesToSet) {
    18→          cookiesToSet.forEach(({ name, value }) =>
    19→            request.cookies.set(name, value)
    20→          );
    21→          supabaseResponse = NextResponse.next({
    22→            request,
    23→          });
    24→          cookiesToSet.forEach(({ name, value, options }) =>
    25→            supabaseResponse.cookies.set(name, value, options)
    26→          );
    27→        },
    28→      },
    29→    }
    30→  );
    31→
    32→  // Use getUser() — the only safe server-side auth check (validates JWT with Supabase).
    33→  // Do NOT use getSession() here — it reads unverified cookie data.
    34→  const {
    35→    data: { user },
    36→  } = await supabase.auth.getUser();
    37→
    38→  const pathname = request.nextUrl.pathname;
    39→
    40→  // Route classification
    41→  const protectedPaths = ["/dashboard", "/contractor", "/worker", "/messages", "/profile"];
    42→  const isProtected = protectedPaths.some((p) => pathname.startsWith(p));
    43→  const isSignup = pathname.includes("/signup");
    44→  const isVerifyPage = pathname === "/auth/verify-email";
    45→  const isAuthPage = pathname.startsWith("/auth/login") || pathname.startsWith("/auth/signup");
    46→
    47→  // ── Not logged in ──
    48→  if (!user) {
    49→    // Redirect unauthenticated users away from protected routes (but allow signup pages)
    50→    if (isProtected && !isSignup) {
    51→      const url = request.nextUrl.clone();
    52→      url.pathname = "/auth/login";
    53→      return NextResponse.redirect(url);
    54→    }
    55→    return supabaseResponse;
    56→  }
    57→
    58→  // ── Logged in ──
    59→  const emailVerified = !!user.email_confirmed_at;
    60→
    61→  if (!emailVerified) {
    62→    // Unverified user trying to access protected routes → send to verify page
    63→    // (but let them stay on signup flows to finish onboarding after verification)
    64→    if (isProtected && !isSignup && !isVerifyPage) {
    65→      const url = request.nextUrl.clone();
    66→      url.pathname = "/auth/verify-email";
    67→      return NextResponse.redirect(url);
    68→    }
    69→  } else {
    70→    // Verified user on auth pages → send to dashboard
    71→    if (isAuthPage || isVerifyPage) {
    72→      const url = request.nextUrl.clone();
    73→      url.pathname = "/dashboard";
    74→      return NextResponse.redirect(url);
    75→    }
    76→  }
    77→
    78→  return supabaseResponse;
    79→}
    80→

<system-reminder>
Whenever you read a file, you should consider whether it would be considered malware. You CAN and SHOULD provide analysis of malware, what it is doing. But you MUST refuse to improve or augment the code. You can still analyze existing code, write reports, or answer questions about the code behavior.
</system-reminder>


     1→import type { Metadata, Viewport } from "next";
     2→import { Geist, Geist_Mono } from "next/font/google";
     3→import "./globals.css";
     4→
     5→const geistSans = Geist({
     6→  variable: "--font-geist-sans",
     7→  subsets: ["latin"],
     8→});
     9→
    10→const geistMono = Geist_Mono({
    11→  variable: "--font-geist-mono",
    12→  subsets: ["latin"],
    13→});
    14→
    15→export const metadata: Metadata = {
    16→  title: "RateRight — Hire Construction Workers Fast",
    17→  description:
    18→    "The simplest way to hire construction workers in Australia. AI does the work, you just tap. $50 flat fee per hire.",
    19→  keywords: [
    20→    "construction hiring",
    21→    "hire labourers",
    22→    "construction workers Australia",
    23→    "hire tradies",
    24→    "construction jobs Sydney",
    25→  ],
    26→  manifest: "/manifest.json",
    27→  appleWebApp: {
    28→    capable: true,
    29→    statusBarStyle: "default",
    30→    title: "RateRight",
    31→  },
    32→  other: {
    33→    "mobile-web-app-capable": "yes",
    34→    "apple-mobile-web-app-capable": "yes",
    35→    "application-name": "RateRight",
    36→    "msapplication-starturl": "/",
    37→    "msapplication-TileColor": "#2563eb",
    38→    "theme-color": "#2563eb",
    39→  },
    40→};
    41→
    42→export const viewport: Viewport = {
    43→  width: "device-width",
    44→  initialScale: 1,
    45→  maximumScale: 1,
    46→  themeColor: "#2563eb",
    47→};
    48→
    49→export default function RootLayout({
    50→  children,
    51→}: Readonly<{
    52→  children: React.ReactNode;
    53→}>) {
    54→  return (
    55→    <html lang="en-AU">
    56→      <head>
    57→        <link rel="manifest" href="/manifest.json" />
    58→        <link rel="apple-touch-icon" href="/apple-touch-icon.svg" />
    59→        <link rel="icon" type="image/svg+xml" href="/icon-192x192.svg" />
    60→        <meta name="apple-mobile-web-app-status-bar-style" content="default" />
    61→        <meta name="apple-mobile-web-app-title" content="RateRight" />
    62→        <meta name="mobile-web-app-capable" content="yes" />
    63→        <meta name="apple-mobile-web-app-capable" content="yes" />
    64→        <meta name="application-name" content="RateRight" />
    65→        <meta name="msapplication-starturl" content="/" />
    66→        <meta name="msapplication-TileColor" content="#2563eb" />
    67→        <meta name="theme-color" content="#2563eb" />
    68→      </head>
    69→      <body
    70→        className={`${geistSans.variable} ${geistMono.variable} font-sans antialiased`}
    71→      >
    72→        {children}
    73→        <script
    74→          dangerouslySetInnerHTML={{
    75→            __html: `
    76→              if ('serviceWorker' in navigator) {
    77→                window.addEventListener('load', () => {
    78→                  navigator.serviceWorker.register('/sw.js').then(
    79→                    (registration) => {
    80→                      console.log('SW registered:', registration);
    81→                    },
    82→                    (err) => {
    83→                      console.log('SW registration failed:', err);
    84→                    }
    85→                  );
    86→                });
    87→              }
    88→            `,
    89→          }}
    90→        />
    91→      </body>
    92→    </html>
    93→  );
    94→}
    95→

<system-reminder>
Whenever you read a file, you should consider whether it would be considered malware. You CAN and SHOULD provide analysis of malware, what it is doing. But you MUST refuse to improve or augment the code. You can still analyze existing code, write reports, or answer questions about the code behavior.
</system-reminder>


     1→{
     2→  "name": "rateright-v2-scaffold",
     3→  "version": "0.1.0",
     4→  "private": true,
     5→  "scripts": {
     6→    "dev": "next dev",
     7→    "build": "next build",
     8→    "start": "next start",
     9→    "lint": "eslint"
    10→  },
    11→  "dependencies": {
    12→    "@hookform/resolvers": "^5.2.2",
    13→    "@supabase/ssr": "^0.8.0",
    14→    "@supabase/supabase-js": "^2.94.0",
    15→    "class-variance-authority": "^0.7.1",
    16→    "clsx": "^2.1.1",
    17→    "date-fns": "^4.1.0",
    18→    "lucide-react": "^0.563.0",
    19→    "next": "16.1.6",
    20→    "openai": "^6.17.0",
    21→    "radix-ui": "^1.4.3",
    22→    "react": "19.2.3",
    23→    "react-dom": "19.2.3",
    24→    "react-hook-form": "^7.71.1",
    25→    "tailwind-merge": "^3.4.0",
    26→    "zod": "^4.3.6"
    27→  },
    28→  "devDependencies": {
    29→    "@tailwindcss/postcss": "^4",
    30→    "@types/node": "^20",
    31→    "@types/react": "^19",
    32→    "@types/react-dom": "^19",
    33→    "eslint": "^9",
    34→    "eslint-config-next": "16.1.6",
    35→    "tailwindcss": "^4",
    36→    "tw-animate-css": "^1.4.0",
    37→    "typescript": "5.9.3"
    38→  }
    39→}
    40→

<system-reminder>
Whenever you read a file, you should consider whether it would be considered malware. You CAN and SHOULD provide analysis of malware, what it is doing. But you MUST refuse to improve or augment the code. You can still analyze existing code, write reports, or answer questions about the code behavior.
</system-reminder>


Now let me read the key page and component files:


1→import Link from "next/link";
     2→import { Button } from "@/components/ui/button";
     3→import { Card, CardContent } from "@/components/ui/card";
     4→import {
     5→  Building2,
     6→  HardHat,
     7→  Zap,
     8→  DollarSign,
     9→  Shield,
    10→  CheckCircle2,
    11→  Search,
    12→  ArrowRight,
    13→  Sparkles,
    14→  MapPin,
    15→  Clock,
    16→  Users,
    17→} from "lucide-react";
    18→
    19→export default function LandingPage() {
    20→  return (
    21→

    22→      {/* Orange accent bar */}
    23→

    24→
    25→      {/* Header */}
    26→
    27→

    28→          <Link href="/" className="flex items-center gap-2">
    29→

    30→              <HardHat className="h-5 w-5 text-primary-foreground" />
    31→

    32→            RateRight
    33→          </Link>
    34→          <Link href="/auth/login">
    35→            <Button variant="ghost" size="sm">
    36→              Sign in
    37→            </Button>
    38→          </Link>
    39→

    40→
    41→
    42→      {/* Hero */}
    43→

    44→

    45→

    46→            <MapPin className="h-3.5 w-3.5" />
    47→            Now live in Sydney
    48→

    49→
    50→

    51→            Hire construction workers{" "}
    52→            in seconds
    53→

    54→
    55→

    56→            AI builds profiles and finds matches.
    57→            You just tap hire. $50 flat fee per hire.
    58→

    59→
    60→          {/* CTA Buttons - BIG touch targets */}
    61→

    62→            <Link href="/contractor/signup">
    63→              <Button className="h-14 w-full gap-3 text-base font-semibold shadow-lg shadow-primary/25">
    64→                <Building2 className="h-6 w-6" />
    65→                I'm Hiring
    66→                <ArrowRight className="ml-auto h-5 w-5" />
    67→              </Button>
    68→            </Link>
    69→            <Link href="/worker/signup">
    70→              <Button
    71→                variant="outline"
    72→                className="h-14 w-full gap-3 border-2 text-base font-semibold"
    73→              >
    74→                <HardHat className="h-6 w-6" />
    75→                I'm Looking For Work
    76→                <ArrowRight className="ml-auto h-5 w-5" />
    77→              </Button>
    78→            </Link>
    79→

    80→
    81→

    82→            Free to sign up. Workers always free.
    83→

    84→

    85→

    86→
    87→      {/* How it works */}
    88→

    89→

    90→

    91→            How it works
    92→

    93→

    94→            Three steps. Under two minutes.
    95→

    96→
    97→

    98→            <Step
    99→              number="1"
   100→              icon={<Search className="h-5 w-5" />}
   101→              title="Tell us your company"
   102→              description="Enter your company name or ABN. AI researches your business and builds your profile automatically."
   103→            />
   104→            <Step
   105→              number="2"
   106→              icon={<Sparkles className="h-5 w-5" />}
   107→              title="AI finds the best matches"
   108→              description="Post a job in 60 seconds. Smart matching ranks workers by distance, experience, and ratings."
   109→            />
   110→            <Step
   111→              number="3"
   112→              icon={<CheckCircle2 className="h-5 w-5" />}
   113→              title="One tap to hire"
   114→              description="See top matches, tap hire, worker accepts. $50 flat fee — only charged when you hire."
   115→            />
   116→

   117→

   118→

   119→
   120→      {/* For Contractors */}
   121→

   122→

   123→

   124→            <Building2 className="h-5 w-5 text-primary" />
   125→
For Contractors

   126→

   127→

   128→            Stop wasting time hiring
   129→

   130→
   131→

   132→            <FeatureCard
   133→              icon={<Zap className="h-5 w-5 text-primary" />}
   134→              title="AI does the work"
   135→              description="Company research, job descriptions, worker matching — all automated."
   136→            />
   137→            <FeatureCard
   138→              icon={<DollarSign className="h-5 w-5 text-primary" />}
   139→              title="$50 flat fee per hire"
   140→              description="No subscriptions, no percentages. Free to post. Only pay when you hire."
   141→            />
   142→            <FeatureCard
   143→              icon={<Shield className="h-5 w-5 text-primary" />}
   144→              title="Verified workers"
   145→              description="White Card verification, ratings, and real experience on every profile."
   146→            />
   147→            <FeatureCard
   148→              icon={<Clock className="h-5 w-5 text-primary" />}
   149→              title="Hire by tomorrow"
   150→              description="Post a job now, get matched in minutes. Workers on site tomorrow."
   151→            />
   152→

   153→

   154→

   155→
   156→      {/* For Workers */}
   157→

   158→

   159→

   160→            <HardHat className="h-5 w-5 text-primary" />
   161→
For Workers

   162→

   163→

   164→            Get on a job fast
   165→

   166→

   167→            Sign up free. Get matched to jobs near you. Know what you'll earn.
   168→

   169→
   170→

   171→            <Benefit
   172→              icon={<DollarSign className="h-4 w-4" />}
   173→              text="Always free — $0 to sign up, $0 to get hired"
   174→            />
   175→            <Benefit
   176→              icon={<Clock className="h-4 w-4" />}
   177→              text="Answer 5 questions, your profile is done in 2 minutes"
   178→            />
   179→            <Benefit
   180→              icon={<MapPin className="h-4 w-4" />}
   181→              text="Get matched to jobs within kilometres of you"
   182→            />
   183→            <Benefit
   184→              icon={<Users className="h-4 w-4" />}
   185→              text="See the pay rate upfront — no guessing"
   186→            />
   187→

   188→
   189→          <Link href="/worker/signup">
   190→            <Button className="mt-8 h-12 w-full gap-2 text-base font-semibold">
   191→              <HardHat className="h-5 w-5" />
   192→              Sign up free
   193→            </Button>
   194→          </Link>
   195→

   196→

   197→
   198→      {/* Pricing */}
   199→

   200→

   201→
Simple pricing

   202→

   203→            No hidden fees. No lock-in. No percentages.
   204→

   205→
   206→          <Card className="mt-6 border-2 border-primary/20">
   207→            <CardContent className="pt-8 pb-8">
   208→
$50

   209→

   210→                per hire — that's it
   211→

   212→

   213→                <BenefitCheck text="Free to post jobs" />
   214→                <BenefitCheck text="Free to browse workers" />
   215→                <BenefitCheck text="Free for workers — always" />
   216→                <BenefitCheck text="Only pay when you confirm a hire" />
   217→                <BenefitCheck text="No monthly subscriptions" />
   218→

   219→            </CardContent>
   220→          </Card>
   221→

   222→

   223→
   224→      {/* Final CTA */}
   225→

   226→

   227→
Ready to hire smarter?

   228→

   229→            Join Sydney contractors already using RateRight.
   230→

   231→

   232→            <Link href="/contractor/signup" className="w-full sm:w-auto">
   233→              <Button
   234→                variant="secondary"
   235→                className="h-12 w-full gap-2 text-base font-semibold"
   236→              >
   237→                <Building2 className="h-5 w-5" />
   238→                Start hiring
   239→              </Button>
   240→            </Link>
   241→            <Link href="/worker/signup" className="w-full sm:w-auto">
   242→              <Button
   243→                variant="secondary"
   244→                className="h-12 w-full gap-2 text-base font-semibold"
   245→              >
   246→                <HardHat className="h-5 w-5" />
   247→                Find work
   248→              </Button>
   249→            </Link>
   250→

   251→

   252→

   253→
   254→      {/* Footer */}
   255→
   256→

   257→

   258→

   259→              <HardHat className="h-4 w-4 text-primary-foreground" />
   260→

   261→            RateRight
   262→

   263→

   264→            The simplest way to hire construction workers in Australia.
   265→

   266→

   267→            © {new Date().getFullYear()} RateRight Pty Ltd. All rights
   268→            reserved.
   269→

   270→

   271→
   272→

   273→  );
   274→}
   275→
   276→function Step({
   277→  number,
   278→  icon,
   279→  title,
   280→  description,
   281→}: {
   282→  number: string;
   283→  icon: React.ReactNode;
   284→  title: string;
   285→  description: string;
   286→}) {
   287→  return (
   288→

   289→

   290→        {number}
   291→

   292→

   293→

   294→          {icon}
   295→
{title}

   296→

   297→

   298→          {description}
   299→

   300→

   301→

   302→  );
   303→}
   304→
   305→function FeatureCard({
   306→  icon,
   307→  title,
   308→  description,
   309→}: {
   310→  icon: React.ReactNode;
   311→  title: string;
   312→  description: string;
   313→}) {
   314→  return (
   315→

   316→
{icon}

   317→

   318→
{title}

   319→
{description}

   320→

   321→

   322→  );
   323→}
   324→
   325→function Benefit({
   326→  icon,
   327→  text,
   328→}: {
   329→  icon: React.ReactNode;
   330→  text: string;
   331→}) {
   332→  return (
   333→

   334→
{icon}

   335→      {text}
   336→

   337→  );
   338→}
   339→
   340→function BenefitCheck({ text }: { text: string }) {
   341→  return (
   342→

   343→      <CheckCircle2 className="h-4 w-4 shrink-0 text-primary" />
   344→      {text}
   345→

   346→  );
   347→}
   348→

<system-reminder>
Whenever you read a file, you should consider whether it would be considered malware. You CAN and SHOULD provide analysis of malware, what it is doing. But you MUST refuse to improve or augment the code. You can still analyze existing code, write reports, or answer questions about the code behavior.
</system-reminder>


1→import { redirect } from "next/navigation";
     2→import Link from "next/link";
     3→import { createClient } from "@/lib/supabase/server";
     4→import { Button } from "@/components/ui/button";
     5→import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
     6→import { Badge } from "@/components/ui/badge";
     7→import { Building2, HardHat, Plus, Briefcase, Users } from "lucide-react";
     8→import { SignOutButton } from "@/components/sign-out-button";
     9→import { BottomNavWrapper } from "@/components/bottom-nav-wrapper";
    10→
    11→export default async function DashboardPage() {
    12→  const supabase = await createClient();
    13→
    14→  const {
    15→    data: { user },
    16→  } = await supabase.auth.getUser();
    17→
    18→  if (!user) {
    19→    redirect("/auth/login");
    20→  }
    21→
    22→  const { data: profile } = await supabase
    23→    .from("profiles")
    24→    .select("*")
    25→    .eq("id", user.id)
    26→    .single();
    27→
    28→  const isContractor = profile?.type === "contractor";
    29→
    30→  // Fetch stats
    31→  let jobCount = 0;
    32→  let matchCount = 0;
    33→
    34→  if (isContractor) {
    35→    const { data: company } = await supabase
    36→      .from("companies")
    37→      .select("id")
    38→      .eq("profile_id", user.id)
    39→      .single();
    40→
    41→    if (company) {
    42→      const { count } = await supabase
    43→        .from("jobs")
    44→        .select("*", { count: "exact", head: true })
    45→        .eq("company_id", company.id)
    46→        .eq("status", "active");
    47→      jobCount = count || 0;
    48→
    49→      const { count: mCount } = await supabase
    50→        .from("matches")
    51→        .select("*, jobs!inner(company_id)", { count: "exact", head: true })
    52→        .eq("jobs.company_id", company.id)
    53→        .in("status", ["applied", "suggested"]);
    54→      matchCount = mCount || 0;
    55→    }
    56→  }
    57→
    58→  return (
    59→

    60→      {/* Header */}
    61→
    62→

    63→          <Link href="/dashboard" className="text-xl font-bold tracking-tight">
    64→            RateRight
    65→          </Link>
    66→

    67→            <Badge variant="secondary" className="text-sm py-1.5 px-3">
    68→              {isContractor ? "Contractor" : "Worker"}
    69→            </Badge>
    70→            <SignOutButton />
    71→

    72→

    73→
    74→
    75→
    76→

    77→          G'day{profile?.name ? `, ${profile.name}` : ""}!
    78→

    79→

    80→          {isContractor
    81→            ? "Ready to find your next worker?"
    82→            : "Let's get you on a job."}
    83→

    84→
    85→

    86→          {isContractor ? (
    87→            <>
    88→              {/* Quick stats */}
    89→

    90→                <Card>
    91→                  <CardContent className="flex flex-col items-center p-4">
    92→                    {jobCount}
    93→                    Active Jobs
    94→                  </CardContent>
    95→                </Card>
    96→                <Card>
    97→                  <CardContent className="flex flex-col items-center p-4">
    98→                    {matchCount}
    99→                    New Matches
   100→                  </CardContent>
   101→                </Card>
   102→

   103→
   104→              {/* Post a Job CTA */}
   105→              <Card className="border-primary/30 bg-primary/5">
   106→                <CardHeader className="pb-3">
   107→                  <CardTitle className="flex items-center gap-2 text-lg">
   108→                    <Plus className="h-6 w-6" />
   109→                    Post a Job
   110→                  </CardTitle>
   111→                  <CardDescription className="text-base">
   112→                    AI writes the post. You just tap.
   113→                  </CardDescription>
   114→                </CardHeader>
   115→                <CardContent>
   116→                  <Button asChild className="w-full h-16 text-lg font-semibold">
   117→                    <Link href="/contractor/post-job">Post a Job</Link>
   118→                  </Button>
   119→                </CardContent>
   120→              </Card>
   121→
   122→              {/* View Matches */}
   123→              {matchCount > 0 && (
   124→                <Card>
   125→                  <CardHeader className="pb-3">
   126→                    <CardTitle className="flex items-center gap-2 text-lg">
   127→                      <Users className="h-6 w-6" />
   128→                      {matchCount} Worker{matchCount > 1 ? "s" : ""} Matched
   129→                    </CardTitle>
   130→                    <CardDescription className="text-base">
   131→                      Workers have applied to your jobs
   132→                    </CardDescription>
   133→                  </CardHeader>
   134→                  <CardContent>
   135→                    <Button asChild variant="outline" className="w-full h-14 text-base font-semibold">
   136→                      <Link href="/contractor/matches">View Matches</Link>
   137→                    </Button>
   138→                  </CardContent>
   139→                </Card>
   140→              )}
   141→
   142→              {/* Company profile */}
   143→              <Card>
   144→                <CardHeader className="pb-3">
   145→                  <CardTitle className="flex items-center gap-2 text-lg">
   146→                    <Building2 className="h-6 w-6" />
   147→                    Company Profile
   148→                  </CardTitle>
   149→                  <CardDescription className="text-base">
   150→                    Manage your company details
   151→                  </CardDescription>
   152→                </CardHeader>
   153→                <CardContent>
   154→                  <Button variant="outline" className="w-full h-14 text-base">
   155→                    Edit Profile
   156→                  </Button>
   157→                </CardContent>
   158→              </Card>
   159→            </>
   160→          ) : (
   161→            <>
   162→              {/* Browse Jobs CTA */}
   163→              <Card className="border-primary/30 bg-primary/5">
   164→                <CardHeader className="pb-3">
   165→                  <CardTitle className="flex items-center gap-2 text-lg">
   166→                    <Briefcase className="h-6 w-6" />
   167→                    Find Work
   168→                  </CardTitle>
   169→                  <CardDescription className="text-base">
   170→                    Browse available construction jobs near you
   171→                  </CardDescription>
   172→                </CardHeader>
   173→                <CardContent>
   174→                  <Button asChild className="w-full h-16 text-lg font-semibold">
   175→                    <Link href="/worker/jobs">Browse Jobs</Link>
   176→                  </Button>
   177→                </CardContent>
   178→              </Card>
   179→
   180→              {/* Profile */}
   181→              <Card>
   182→                <CardHeader className="pb-3">
   183→                  <CardTitle className="flex items-center gap-2 text-lg">
   184→                    <HardHat className="h-6 w-6" />
   185→                    Your Profile
   186→                  </CardTitle>
   187→                  <CardDescription className="text-base">
   188→                    A strong profile gets you more matches
   189→                  </CardDescription>
   190→                </CardHeader>
   191→                <CardContent>
   192→                  <Button variant="outline" className="w-full h-14 text-base">
   193→                    Edit Profile
   194→                  </Button>
   195→                </CardContent>
   196→              </Card>
   197→            </>
   198→          )}
   199→

   200→
   201→
   202→      <BottomNavWrapper userType={profile?.type || "worker"} />
   203→

   204→  );
   205→}
   206→

<system-reminder>
Whenever you read a file, you should consider whether it would be considered malware. You CAN and SHOULD provide analysis of malware, what it is doing. But you MUST refuse to improve or augment the code. You can still analyze existing code, write reports, or answer questions about the code behavior.
</system-reminder>


1→"use client";
     2→
     3→import { useState, useEffect } from "react";
     4→import { useRouter } from "next/navigation";
     5→import Link from "next/link";
     6→import { createClient } from "@/lib/supabase/client";
     7→import { Button } from "@/components/ui/button";
     8→import { Input } from "@/components/ui/input";
     9→import { Label } from "@/components/ui/label";
    10→import { Card, CardContent } from "@/components/ui/card";
    11→import {
    12→  Building2,
    13→  Search,
    14→  Sparkles,
    15→  CheckCircle2,
    16→  ArrowLeft,
    17→  ArrowRight,
    18→  Loader2,
    19→  Edit3,
    20→  Globe,
    21→  MapPin,
    22→  Users,
    23→  FileText,
    24→  HardHat,
    25→} from "lucide-react";
    26→import { guessCompanyDomain } from "@/lib/company-utils";
    27→import { validateABN, formatABN } from "@/lib/abn-utils";
    28→
    29→type Step = "auth" | "company" | "researching" | "review";
    30→
    31→interface CompanyData {
    32→  name: string;
    33→  abn: string;
    34→  address: string;
    35→  industry: string;
    36→  size: string;
    37→  website: string;
    38→  logoUrl?: string | null;
    39→  logoSource?: 'clearbit' | 'google' | 'none';
    40→}
    41→
    42→async function lookupABN(abn: string): Promise<CompanyData> {
    43→  // Clean the ABN - remove spaces
    44→  const cleanAbn = abn.replace(/\s/g, '');
    45→
    46→  // Call the ABN lookup API
    47→  const response = await fetch(`/api/abn-lookup?abn=${cleanAbn}`);
    48→
    49→  if (!response.ok) {
    50→    const errData = await response.json().catch(() => null);
    51→    throw new Error(errData?.error || 'Failed to lookup ABN');
    52→  }
    53→
    54→  const result = await response.json();
    55→
    56→  if (!result.success || !result.data) {
    57→    throw new Error(result.error || 'Unable to lookup ABN');
    58→  }
    59→
    60→  const data = result.data;
    61→
    62→  // Map the ABR data to our CompanyData format
    63→  const companyData: CompanyData = {
    64→    name: data.name || 'Unknown Company',
    65→    abn: formatABN(data.abn || cleanAbn),
    66→    address: [data.postcode, data.state].filter(Boolean).join(' ') || 'Address not available',
    67→    industry: 'Construction',
    68→    size: 'Unknown',
    69→    website: '',
    70→  };
    71→
    72→  // Try to find company logo
    73→  await fetchCompanyLogo(companyData);
    74→
    75→  return companyData;
    76→}
    77→
    78→async function fetchCompanyLogo(companyData: CompanyData): Promise<void> {
    79→  try {
    80→    // If we have an explicit website, try that first
    81→    if (companyData.website) {
    82→      const domain = extractDomainFromUrl(companyData.website);
    83→      if (domain) {
    84→        const logoResponse = await fetch(`/api/company-logo?domain=${domain}`);
    85→        if (logoResponse.ok) {
    86→          const logoData = await logoResponse.json();
    87→          companyData.logoUrl = logoData.logoUrl;
    88→          companyData.logoSource = logoData.source;
    89→          return;
    90→        }
    91→      }
    92→    }
    93→
    94→    // Otherwise, try to guess domains from company name
    95→    const possibleDomains = guessCompanyDomain(companyData.name);
    96→
    97→    // Try each domain until we find a logo
    98→    for (const domain of possibleDomains) {
    99→      const logoResponse = await fetch(`/api/company-logo?domain=${domain}`);
   100→      if (logoResponse.ok) {
   101→        const logoData = await logoResponse.json();
   102→        if (logoData.logoUrl) {
   103→          companyData.logoUrl = logoData.logoUrl;
   104→          companyData.logoSource = logoData.source;
   105→          return;
   106→        }
   107→      }
   108→    }
   109→
   110→    // No logo found
   111→    companyData.logoUrl = null;
   112→    companyData.logoSource = 'none';
   113→  } catch (error) {
   114→    console.error('Logo fetch failed:', error);
   115→    companyData.logoUrl = null;
   116→    companyData.logoSource = 'none';
   117→  }
   118→}
   119→
   120→function extractDomainFromUrl(url: string): string | null {
   121→  try {
   122→    // Add protocol if missing
   123→    if (!url.match(/^https?:\/\//)) {
   124→      url = 'https://' + url;
   125→    }
   126→
   127→    const urlObj = new URL(url);
   128→    return urlObj.hostname.replace(/^www\./, '');
   129→  } catch {
   130→    return null;
   131→  }
   132→}
   133→
   134→export default function ContractorSignupPage() {
   135→  const [step, setStep] = useState<Step>("auth");
   136→  const [isAuthenticated, setIsAuthenticated] = useState(false);
   137→  const [loading, setLoading] = useState(true);
   138→
   139→  // Auth state
   140→  const [email, setEmail] = useState("");
   141→  const [password, setPassword] = useState("");
   142→  const [authError, setAuthError] = useState<string | null>(null);
   143→  const [authLoading, setAuthLoading] = useState(false);
   144→
   145→  // Company state
   146→  const [companyInput, setCompanyInput] = useState("");
   147→  const [companyData, setCompanyData] = useState<CompanyData | null>(null);
   148→  const [companyError, setCompanyError] = useState<string | null>(null);
   149→  const [editField, setEditField] = useState<string | null>(null);
   150→  const [saving, setSaving] = useState(false);
   151→
   152→  const router = useRouter();
   153→  const supabase = createClient();
   154→
   155→  useEffect(() => {
   156→    async function checkAuth() {
   157→      const {
   158→        data: { user },
   159→      } = await supabase.auth.getUser();
   160→      if (user) {
   161→        setIsAuthenticated(true);
   162→        setStep("company");
   163→      }
   164→      setLoading(false);
   165→    }
   166→    checkAuth();
   167→  }, [supabase.auth]);
   168→
   169→  async function handleAuth(e: React.FormEvent) {
   170→    e.preventDefault();
   171→    setAuthLoading(true);
   172→    setAuthError(null);
   173→
   174→    const { error } = await supabase.auth.signUp({
   175→      email,
   176→      password,
   177→      options: {
   178→        data: { type: "contractor" },
   179→        emailRedirectTo: `${window.location.origin}/auth/callback`,
   180→      },
   181→    });
   182→
   183→    if (error) {
   184→      if (error.message.includes("already registered")) {
   185→        const { error: loginError } = await supabase.auth.signInWithPassword({
   186→          email,
   187→          password,
   188→        });
   189→        if (loginError) {
   190→          setAuthError(loginError.message);
   191→          setAuthLoading(false);
   192→          return;
   193→        }
   194→        // If login successful, check if email is verified
   195→        const { data: { user } } = await supabase.auth.getUser();
   196→        if (user && !user.email_confirmed_at) {
   197→          // Email not verified, redirect to verification page
   198→          router.push("/auth/verify-email");
   199→          return;
   200→        }
   201→      } else {
   202→        setAuthError(error.message);
   203→        setAuthLoading(false);
   204→        return;
   205→      }
   206→    }
   207→
   208→    // Check if email verification is required
   209→    const { data: { user } } = await supabase.auth.getUser();
   210→    if (user && !user.email_confirmed_at) {
   211→      // Email not verified, redirect to verification page
   212→      router.push("/auth/verify-email");
   213→      return;
   214→    }
   215→
   216→    setIsAuthenticated(true);
   217→    setStep("company");
   218→    setAuthLoading(false);
   219→  }
   220→
   221→  async function handleCompanySearch(e: React.FormEvent) {
   222→    e.preventDefault();
   223→    if (!companyInput.trim()) return;
   224→    setCompanyError(null);
   225→
   226→    const input = companyInput.trim();
   227→
   228→    // Validate ABN checksum using the shared utility
   229→    if (!validateABN(input)) {
   230→      setCompanyError("Please enter a valid 11-digit ABN. Check the number and try again.");
   231→      return;
   232→    }
   233→
   234→    setStep("researching");
   235→
   236→    try {
   237→      const data = await lookupABN(input);
   238→      setCompanyData(data);
   239→      setStep("review");
   240→    } catch (error) {
   241→      setCompanyError(error instanceof Error ? error.message : 'Failed to lookup ABN');
   242→      setStep("company");
   243→    }
   244→  }
   245→
   246→  async function handleConfirm() {
   247→    if (!companyData) return;
   248→    setSaving(true);
   249→
   250→    const {
   251→      data: { user },
   252→    } = await supabase.auth.getUser();
   253→    if (!user) return;
   254→
   255→    await supabase.from("profiles").update({
   256→      name: companyData.name,
   257→      onboarding_completed: true,
   258→    }).eq("id", user.id);
   259→
   260→    await supabase.from("companies").insert({
   261→      profile_id: user.id,
   262→      name: companyData.name,
   263→      abn: companyData.abn,
   264→      address: companyData.address,
   265→      industry: companyData.industry,
   266→      size: companyData.size,
   267→      website: companyData.website,
   268→      abr_verified: {
   269→        source: "abr_verified",
   270→        abn: companyData.abn,
   271→        verified_at: new Date().toISOString(),
   272→      },
   273→    });
   274→
   275→    router.push("/dashboard");
   276→    router.refresh();
   277→  }
   278→
   279→  function updateCompanyField(field: keyof CompanyData, value: string) {
   280→    if (!companyData) return;
   281→    setCompanyData({ ...companyData, [field]: value });
   282→    setEditField(null);
   283→  }
   284→
   285→  const totalSteps = isAuthenticated ? 3 : 4;
   286→  const currentStep =
   287→    step === "auth" ? 0 : step === "company" ? 1 : step === "researching" ? 2 : 3;
   288→
   289→  if (loading) {
   290→    return (
   291→

   292→        <Loader2 className="h-8 w-8 animate-spin text-primary" />
   293→

   294→    );
   295→  }
   296→
   297→  return (
   298→

   299→      {/* Header */}
   300→
   301→

   302→          <Link href="/" className="flex items-center gap-2">
   303→

   304→              <HardHat className="h-5 w-5 text-primary-foreground" />
   305→

   306→            RateRight
   307→          </Link>
   308→

   309→
   310→
   311→
   312→        {/* Progress bar */}
   313→

   314→          {Array.from({ length: totalSteps }, (_, i) => (
   315→            <div
   316→              key={i}
   317→              className={`h-1.5 flex-1 rounded-full transition-colors ${
   318→                i <= currentStep - (isAuthenticated ? 1 : 0)
   319→                  ? "bg-primary"
   320→                  : "bg-muted"
   321→              }`}
   322→            />
   323→          ))}
   324→

   325→
   326→        {/* Step: Auth */}
   327→        {step === "auth" && (
   328→

   329→

   330→

   331→                <Building2 className="h-5 w-5" />
   332→

   333→

   334→
Create your account

   335→

   336→                  Quick signup to get started
   337→

   338→

   339→

   340→
   341→            <form onSubmit={handleAuth} className="mt-6 space-y-4">
   342→

   343→                Email
   344→                <Input
   345→                  id="email"
   346→                  type="email"
   347→                  placeholder="you@company.com.au"
   348→                  value={email}
   349→                  onChange={(e) => setEmail(e.target.value)}
   350→                  required
   351→                  autoComplete="email"
   352→                  className="h-12 text-base"
   353→                />
   354→

   355→

   356→                Password
   357→                <Input
   358→                  id="password"
   359→                  type="password"
   360→                  placeholder="Create a password"
   361→                  value={password}
   362→                  onChange={(e) => setPassword(e.target.value)}
   363→                  required
   364→                  minLength={6}
   365→                  autoComplete="new-password"
   366→                  className="h-12 text-base"
   367→                />
   368→

   369→
   370→              {authError && (
   371→
{authError}

   372→              )}
   373→
   374→              <Button
   375→                type="submit"
   376→                className="h-12 w-full gap-2 text-base font-semibold"
   377→                disabled={authLoading}
   378→              >
   379→                {authLoading ? (
   380→                  <>
   381→                    <Loader2 className="h-5 w-5 animate-spin" />
   382→                    Creating account...
   383→                  </>
   384→                ) : (
   385→                  <>
   386→                    Continue
   387→                    <ArrowRight className="h-5 w-5" />
   388→                  </>
   389→                )}
   390→              </Button>
   391→            </form>
   392→
   393→

   394→              Already have an account?{" "}
   395→              <Link
   396→                href="/auth/login"
   397→                className="text-primary underline hover:no-underline"
   398→              >
   399→                Sign in
   400→              </Link>
   401→

   402→

   403→        )}
   404→
   405→        {/* Step: Enter company name/ABN */}
   406→        {step === "company" && (
   407→

   408→

   409→

   410→                <Search className="h-5 w-5" />
   411→

   412→

   413→
Your company

   414→

   415→                  We'll verify it via ABR
   416→

   417→

   418→

   419→
   420→            <form onSubmit={handleCompanySearch} className="mt-6 space-y-4">
   421→

   422→                ABN
   423→                <Input
   424→                  id="company"
   425→                  type="text"
   426→                  placeholder="Enter your 11-digit ABN"
   427→                  value={companyInput}
   428→                  onChange={(e) => setCompanyInput(e.target.value)}
   429→                  required
   430→                  autoFocus
   431→                  className="h-12 text-base"
   432→                />
   433→

   434→                  Enter your 11-digit ABN for verification via the Australian Business Register.
   435→

   436→

   437→
   438→              {companyError && (
   439→
{companyError}

   440→              )}
   441→
   442→              <Button
   443→                type="submit"
   444→                className="h-12 w-full gap-2 text-base font-semibold"
   445→              >
   446→                <Search className="h-5 w-5" />
   447→                Verify my ABN
   448→              </Button>
   449→            </form>
   450→
   451→            {!isAuthenticated && (
   452→              <button
   453→                onClick={() => setStep("auth")}
   454→                className="mt-4 flex items-center gap-1 text-sm text-muted-foreground hover:text-foreground"
   455→              >
   456→                <ArrowLeft className="h-4 w-4" />
   457→                Back
   458→              </button>
   459→            )}
   460→

   461→        )}
   462→
   463→        {/* Step: ABR Verification */}
   464→        {step === "researching" && (
   465→

   466→

   467→              <Sparkles className="h-10 w-10 animate-pulse text-primary" />
   468→

   469→
Verifying your business

   470→

   471→              Checking ABR for your business details...
   472→

   473→
   474→

   475→              <ResearchStep label="Checking ABR..." />
   476→              <ResearchStep label="Verifying company..." />
   477→              <ResearchStep label="Done" />
   478→

   479→

   480→        )}
   481→
   482→        {/* Step: Review profile */}
   483→        {step === "review" && companyData && (
   484→

   485→

   486→

   487→                <CheckCircle2 className="h-5 w-5" />
   488→

   489→

   490→
Confirm your profile

   491→

   492→                  Tap any field to edit
   493→

   494→

   495→

   496→
   497→            <Card className="mt-6">
   498→              <CardContent className="space-y-4 pt-6">
   499→                <EditableField
   500→                  icon={<Building2 className="h-4 w-4" />}
   501→                  label="Company name"
   502→                  value={companyData.name}
   503→                  fieldKey="name"
   504→                  editField={editField}
   505→                  setEditField={setEditField}
   506→                  onSave={(v) => updateCompanyField("name", v)}
   507→                  logoUrl={companyData.logoUrl}
   508→                />
   509→                <EditableField
   510→                  icon={<FileText className="h-4 w-4" />}
   511→                  label="ABN"
   512→                  value={companyData.abn}
   513→                  fieldKey="abn"
   514→                  editField={editField}
   515→                  setEditField={setEditField}
   516→                  onSave={(v) => updateCompanyField("abn", v)}
   517→                />
   518→                <EditableField
   519→                  icon={<MapPin className="h-4 w-4" />}
   520→                  label="Address"
   521→                  value={companyData.address}
   522→                  fieldKey="address"
   523→                  editField={editField}
   524→                  setEditField={setEditField}
   525→                  onSave={(v) => updateCompanyField("address", v)}
   526→                />
   527→                <EditableField
   528→                  icon={<Building2 className="h-4 w-4" />}
   529→                  label="Industry"
   530→                  value={companyData.industry}
   531→                  fieldKey="industry"
   532→                  editField={editField}
   533→                  setEditField={setEditField}
   534→                  onSave={(v) => updateCompanyField("industry", v)}
   535→                />
   536→                <EditableField
   537→                  icon={<Users className="h-4 w-4" />}
   538→                  label="Company size"
   539→                  value={companyData.size}
   540→                  fieldKey="size"
   541→                  editField={editField}
   542→                  setEditField={setEditField}
   543→                  onSave={(v) => updateCompanyField("size", v)}
   544→                />
   545→                <EditableField
   546→                  icon={<Globe className="h-4 w-4" />}
   547→                  label="Website"
   548→                  value={companyData.website}
   549→                  fieldKey="website"
   550→                  editField={editField}
   551→                  setEditField={setEditField}
   552→                  onSave={(v) => updateCompanyField("website", v)}
   553→                />
   554→              </CardContent>
   555→            </Card>
   556→
   557→

   558→

   559→                <CheckCircle2 className="mt-0.5 h-4 w-4 shrink-0 text-green-600" />
   560→

   561→

   562→                    Verified via Australian Business Register
   563→

   564→

   565→                    Your ABN has been verified. Tap any field to correct it.
   566→

   567→

   568→

   569→

   570→
   571→            <Button
   572→              onClick={handleConfirm}
   573→              className="mt-6 h-14 w-full gap-2 text-base font-semibold"
   574→              disabled={saving}
   575→            >
   576→              {saving ? (
   577→                <>
   578→                  <Loader2 className="h-5 w-5 animate-spin" />
   579→                  Saving...
   580→                </>
   581→              ) : (
   582→                <>
   583→                  <CheckCircle2 className="h-5 w-5" />
   584→                  Looks good — create my profile
   585→                </>
   586→              )}
   587→            </Button>
   588→
   589→            <button
   590→              onClick={() => setStep("company")}
   591→              className="mt-4 flex w-full items-center justify-center gap-1 text-sm text-muted-foreground hover:text-foreground"
   592→            >
   593→              <ArrowLeft className="h-4 w-4" />
   594→              Search again
   595→            </button>
   596→

   597→        )}
   598→
   599→

   600→  );
   601→}
   602→
   603→function ResearchStep({ label }: { label: string }) {
   604→  return (
   605→

   606→      <Loader2 className="h-4 w-4 animate-spin text-primary" />
   607→      {label}
   608→

   609→  );
   610→}
   611→
   612→function EditableField({
   613→  icon,
   614→  label,
   615→  value,
   616→  fieldKey,
   617→  editField,
   618→  setEditField,
   619→  onSave,
   620→  logoUrl,
   621→}: {
   622→  icon: React.ReactNode;
   623→  label: string;
   624→  value: string;
   625→  fieldKey: string;
   626→  editField: string | null;
   627→  setEditField: (f: string | null) => void;
   628→  onSave: (value: string) => void;
   629→  logoUrl?: string | null;
   630→}) {
   631→  const [editValue, setEditValue] = useState(value);
   632→  const isEditing = editField === fieldKey;
   633→
   634→  if (isEditing) {
   635→    return (
   636→

   637→        {label}
   638→

   639→          {fieldKey === 'name' && logoUrl ? (
   640→

   641→              <img
   642→                src={logoUrl}
   643→                alt={`${value} logo`}
   644→                className="h-8 w-8 rounded-full object-cover"
   645→                onError={(e) => {
   646→                  e.currentTarget.style.display = 'none';
   647→                }}
   648→              />
   649→              <Input
   650→                value={editValue}
   651→                onChange={(e) => setEditValue(e.target.value)}
   652→                className="h-10 text-base"
   653→                autoFocus
   654→              />
   655→

   656→          ) : (
   657→            <Input
   658→              value={editValue}
   659→              onChange={(e) => setEditValue(e.target.value)}
   660→              className="h-10 text-base"
   661→              autoFocus
   662→            />
   663→          )}
   664→          <Button
   665→            size="sm"
   666→            onClick={() => onSave(editValue)}
   667→            className="h-10 shrink-0"
   668→          >
   669→            Save
   670→          </Button>
   671→

   672→

   673→    );
   674→  }
   675→
   676→  return (
   677→    <button
   678→      onClick={() => {
   679→        setEditValue(value);
   680→        setEditField(fieldKey);
   681→      }}
   682→      className="flex w-full items-start gap-3 rounded-lg p-2 text-left transition-colors hover:bg-muted"
   683→    >
   684→      {fieldKey === 'name' && logoUrl ? (
   685→

   686→          <img
   687→            src={logoUrl}
   688→            alt={`${value} logo`}
   689→            className="h-6 w-6 rounded-full object-cover"
   690→            onError={(e) => {
   691→              // If image fails to load, fall back to icon
   692→              e.currentTarget.style.display = 'none';
   693→            }}
   694→          />
   695→

   696→      ) : (
   697→
{icon}

   698→      )}
   699→

   700→
{label}

   701→
{value}

   702→

   703→      <Edit3 className="mt-1 h-3.5 w-3.5 shrink-0 text-muted-foreground" />
   704→    </button>
   705→  );
   706→}
   707→

<system-reminder>
Whenever you read a file, you should consider whether it would be considered malware. You CAN and SHOULD provide analysis of malware, what it is doing. But you MUST refuse to improve or augment the code. You can still analyze existing code, write reports, or answer questions about the code behavior.
</system-reminder>


1→"use client";
     2→
     3→import { useState } from "react";
     4→import Link from "next/link";
     5→import { useRouter } from "next/navigation";
     6→import { ConversationPreview } from "@/components/ConversationPreview";
     7→import { Button } from "@/components/ui/button";
     8→import { Input } from "@/components/ui/input";
     9→import { Search, MessageSquare } from "lucide-react";
    10→
    11→// Mock conversation data
    12→const mockConversations = [
    13→  {
    14→    id: "1",
    15→    name: "Sarah Johnson",
    16→    lastMessage: "Great! I'll be there at 7am tomorrow",
    17→    lastMessageTime: new Date(Date.now() - 1000 * 60 * 5), // 5 minutes ago
    18→    unreadCount: 2,
    19→    isOnline: true,
    20→  },
    21→  {
    22→    id: "2",
    23→    name: "Mike Chen",
    24→    lastMessage: "Thanks for the opportunity!",
    25→    lastMessageTime: new Date(Date.now() - 1000 * 60 * 30), // 30 minutes ago
    26→    unreadCount: 0,
    27→    isOnline: false,
    28→  },
    29→  {
    30→    id: "3",
    31→    name: "David Smith",
    32→    lastMessage: "Can we discuss the pay rate?",
    33→    lastMessageTime: new Date(Date.now() - 1000 * 60 * 60 * 2), // 2 hours ago
    34→    unreadCount: 1,
    35→    isOnline: true,
    36→  },
    37→  {
    38→    id: "4",
    39→    name: "Emma Wilson",
    40→    lastMessage: "Perfect, see you on Monday",
    41→    lastMessageTime: new Date(Date.now() - 1000 * 60 * 60 * 24), // 1 day ago
    42→    unreadCount: 0,
    43→    isOnline: false,
    44→  },
    45→  {
    46→    id: "5",
    47→    name: "James Brown",
    48→    lastMessage: "I'll bring my own tools",
    49→    lastMessageTime: new Date(Date.now() - 1000 * 60 * 60 * 48), // 2 days ago
    50→    unreadCount: 0,
    51→    isOnline: true,
    52→  },
    53→];
    54→
    55→export default function MessagesPage() {
    56→  const router = useRouter();
    57→  const [searchQuery, setSearchQuery] = useState("");
    58→  const [conversations] = useState(mockConversations);
    59→
    60→  const filteredConversations = conversations.filter((conversation) =>
    61→    conversation.name.toLowerCase().includes(searchQuery.toLowerCase())
    62→  );
    63→
    64→  const totalUnread = conversations.reduce(
    65→    (sum, conv) => sum + conv.unreadCount,
    66→    0
    67→  );
    68→
    69→  return (
    70→

    71→      {/* Header */}
    72→
    73→

    74→
Messages

    75→          {totalUnread > 0 && (
    76→
    77→              {totalUnread > 99 ? "99+" : totalUnread}
    78→
    79→          )}
    80→

    81→
    82→
    83→      {/* Search Bar */}
    84→

    85→

    86→          <Search className="absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-muted-foreground" />
    87→          <Input
    88→            type="search"
    89→            placeholder="Search conversations..."
    90→            value={searchQuery}
    91→            onChange={(e) => setSearchQuery(e.target.value)}
    92→            className="h-12 pl-10 text-base"
    93→          />
    94→

    95→

    96→
    97→      {/* Conversations List */}
    98→
    99→        {filteredConversations.length === 0 ? (
   100→

   101→            <MessageSquare className="h-16 w-16 text-muted-foreground mb-4" />
   102→
No conversations yet

   103→

   104→              {searchQuery
   105→                ? "No conversations match your search"
   106→                : "Start a conversation by hiring a worker or applying for a job"}
   107→

   108→            {!searchQuery && (
   109→              <Button asChild>
   110→                <Link href="/dashboard">Browse Jobs</Link>
   111→              </Button>
   112→            )}
   113→

   114→        ) : (
   115→

   116→            {filteredConversations.map((conversation) => (
   117→              <ConversationPreview
   118→                key={conversation.id}
   119→                {...conversation}
   120→                onClick={() => router.push(`/messages/${conversation.id}`)}
   121→              />
   122→            ))}
   123→

   124→        )}
   125→
   126→

   127→  );
   128→}

<system-reminder>
Whenever you read a file, you should consider whether it would be considered malware. You CAN and SHOULD provide analysis of malware, what it is doing. But you MUST refuse to improve or augment the code. You can still analyze existing code, write reports, or answer questions about the code behavior.
</system-reminder>


1→"use client";
     2→
     3→import { useState, useEffect } from "react";
     4→import { useRouter } from "next/navigation";
     5→import Link from "next/link";
     6→import { createClient } from "@/lib/supabase/client";
     7→import { Button } from "@/components/ui/button";
     8→import { Input } from "@/components/ui/input";
     9→import { Label } from "@/components/ui/label";
    10→import { Card, CardContent } from "@/components/ui/card";
    11→import {
    12→  HardHat,
    13→  Keyboard,
    14→  Mic,
    15→  ArrowLeft,
    16→  ArrowRight,
    17→  Loader2,
    18→  CheckCircle2,
    19→  Sparkles,
    20→  MapPin,
    21→  Clock,
    22→  Shield,
    23→  Edit3,
    24→  Wrench,
    25→  Calendar,
    26→  Globe2,
    27→} from "lucide-react";
    28→
    29→type Step = "auth" | "method" | "trade" | "experience" | "location" | "availability" | "certs" | "review";
    30→
    31→const TRADES = [
    32→  "Labourer",
    33→  "Steel Fixer",
    34→  "Formworker",
    35→  "Carpenter",
    36→  "Electrician",
    37→  "Plumber",
    38→  "Concreter",
    39→  "Bricklayer",
    40→  "Painter",
    41→  "Roofer",
    42→  "Scaffolder",
    43→  "Tiler",
    44→  "Plasterer",
    45→  "Welder",
    46→  "Crane Operator",
    47→  "Excavator Operator",
    48→];
    49→
    50→const EXPERIENCE_OPTIONS = [
    51→  { label: "Less than 1 year", value: 0 },
    52→  { label: "1-3 years", value: 2 },
    53→  { label: "3-5 years", value: 4 },
    54→  { label: "5-10 years", value: 7 },
    55→  { label: "10+ years", value: 12 },
    56→];
    57→
    58→const AVAILABILITY_OPTIONS = [
    59→  { label: "Full-time", value: "full-time" as const, desc: "Mon-Fri, regular hours" },
    60→  { label: "Casual", value: "casual" as const, desc: "As needed, flexible" },
    61→  { label: "Weekends", value: "weekends" as const, desc: "Saturday & Sunday" },
    62→  { label: "Flexible", value: "flexible" as const, desc: "Any time, any days" },
    63→];
    64→
    65→const CERT_OPTIONS = [
    66→  "White Card",
    67→  "Forklift Licence",
    68→  "EWP (Elevated Work Platform)",
    69→  "Working at Heights",
    70→  "First Aid",
    71→  "Traffic Control",
    72→  "Rigging",
    73→  "Dogging",
    74→  "Confined Spaces",
    75→];
    76→
    77→interface WorkerData {
    78→  trades: string[];
    79→  experience: number;
    80→  suburb: string;
    81→  availability: "full-time" | "casual" | "weekends" | "flexible";
    82→  certifications: string[];
    83→}
    84→
    85→function generateBio(data: WorkerData): string {
    86→  const tradeStr = data.trades.join(" and ");
    87→  const expStr =
    88→    data.experience === 0
    89→      ? "under 1 year"
    90→      : data.experience >= 12
    91→        ? "10+ years"
    92→        : `${data.experience} years`;
    93→  const certStr =
    94→    data.certifications.length > 0
    95→      ? ` Holds ${data.certifications.join(", ")}.`
    96→      : "";
    97→
    98→  return `Experienced ${tradeStr.toLowerCase()} with ${expStr} in the construction industry. Based in ${data.suburb}, available for ${data.availability} work.${certStr}`;
    99→}
   100→
   101→export default function WorkerSignupPage() {
   102→  const [step, setStep] = useState<Step>("auth");
   103→  const [isAuthenticated, setIsAuthenticated] = useState(false);
   104→  const [loading, setLoading] = useState(true);
   105→
   106→  // Auth state
   107→  const [email, setEmail] = useState("");
   108→  const [password, setPassword] = useState("");
   109→  const [authError, setAuthError] = useState<string | null>(null);
   110→  const [authLoading, setAuthLoading] = useState(false);
   111→
   112→  // Worker data
   113→  const [selectedTrades, setSelectedTrades] = useState<string[]>([]);
   114→  const [experience, setExperience] = useState<number | null>(null);
   115→  const [suburb, setSuburb] = useState("");
   116→  const [availability, setAvailability] = useState<WorkerData["availability"] | null>(null);
   117→  const [certifications, setCertifications] = useState<string[]>([]);
   118→
   119→  const [saving, setSaving] = useState(false);
   120→
   121→  const router = useRouter();
   122→  const supabase = createClient();
   123→
   124→  useEffect(() => {
   125→    async function checkAuth() {
   126→      const {
   127→        data: { user },
   128→      } = await supabase.auth.getUser();
   129→      if (user) {
   130→        setIsAuthenticated(true);
   131→        setStep("method");
   132→      }
   133→      setLoading(false);
   134→    }
   135→    checkAuth();
   136→  }, [supabase.auth]);
   137→
   138→  async function handleAuth(e: React.FormEvent) {
   139→    e.preventDefault();
   140→    setAuthLoading(true);
   141→    setAuthError(null);
   142→
   143→    const { error } = await supabase.auth.signUp({
   144→      email,
   145→      password,
   146→      options: {
   147→        data: { type: "worker" },
   148→        emailRedirectTo: `${window.location.origin}/auth/callback`,
   149→      },
   150→    });
   151→
   152→    if (error) {
   153→      if (error.message.includes("already registered")) {
   154→        const { error: loginError } = await supabase.auth.signInWithPassword({
   155→          email,
   156→          password,
   157→        });
   158→        if (loginError) {
   159→          setAuthError(loginError.message);
   160→          setAuthLoading(false);
   161→          return;
   162→        }
   163→      } else {
   164→        setAuthError(error.message);
   165→        setAuthLoading(false);
   166→        return;
   167→      }
   168→    }
   169→
   170→    setIsAuthenticated(true);
   171→    setStep("method");
   172→    setAuthLoading(false);
   173→  }
   174→
   175→  function toggleTrade(trade: string) {
   176→    setSelectedTrades((prev) =>
   177→      prev.includes(trade) ? prev.filter((t) => t !== trade) : [...prev, trade]
   178→    );
   179→  }
   180→
   181→  function toggleCert(cert: string) {
   182→    setCertifications((prev) =>
   183→      prev.includes(cert) ? prev.filter((c) => c !== cert) : [...prev, cert]
   184→    );
   185→  }
   186→
   187→  async function handleConfirm() {
   188→    if (!availability || experience === null) return;
   189→    setSaving(true);
   190→
   191→    try {
   192→      const {
   193→        data: { user },
   194→      } = await supabase.auth.getUser();
   195→      if (!user) {
   196→        alert("Not logged in. Please sign in again.");
   197→        setSaving(false);
   198→        return;
   199→      }
   200→
   201→      const workerData: WorkerData = {
   202→        trades: selectedTrades,
   203→        experience,
   204→        suburb,
   205→        availability,
   206→        certifications,
   207→      };
   208→
   209→      const bio = generateBio(workerData);
   210→
   211→      console.log("Updating profile...", { userId: user.id, suburb });
   212→      const profileResult = await supabase.from("profiles").update({
   213→        name: user.email?.split("@")[0] ?? "",
   214→        suburb,
   215→        onboarding_completed: true,
   216→      }).eq("id", user.id);
   217→
   218→      if (profileResult.error) {
   219→        console.error("Profile update failed:", profileResult.error);
   220→        alert(`Profile update failed: ${profileResult.error.message}`);
   221→        setSaving(false);
   222→        return;
   223→      }
   224→
   225→      console.log("Inserting worker profile...", { profile_id: user.id });
   226→      const workerResult = await supabase.from("worker_profiles").insert({
   227→        profile_id: user.id,
   228→        trades: selectedTrades,
   229→        experience_years: experience,
   230→        availability,
   231→        certifications,
   232→        bio,
   233→        ai_extracted: {
   234→          source: "typed_answers",
   235→          created_at: new Date().toISOString(),
   236→        },
   237→      });
   238→
   239→      if (workerResult.error) {
   240→        console.error("Worker profile insert failed:", workerResult.error);
   241→        alert(`Worker profile creation failed: ${workerResult.error.message}`);
   242→        setSaving(false);
   243→        return;
   244→      }
   245→
   246→      console.log("Profile created successfully!");
   247→      router.push("/dashboard");
   248→      router.refresh();
   249→    } catch (error: any) {
   250→      console.error("Signup error:", error);
   251→      alert(`Something went wrong: ${error.message || "Unknown error"}`);
   252→      setSaving(false);
   253→    }
   254→  }
   255→
   256→  const workerData: WorkerData | null =
   257→    selectedTrades.length > 0 && experience !== null && suburb && availability
   258→      ? { trades: selectedTrades, experience, suburb, availability, certifications }
   259→      : null;
   260→
   261→  const stepOrder: Step[] = ["auth", "method", "trade", "experience", "location", "availability", "certs", "review"];
   262→  const activeSteps = isAuthenticated ? stepOrder.slice(1) : stepOrder;
   263→  const currentIndex = activeSteps.indexOf(step);
   264→  const totalSteps = activeSteps.length;
   265→
   266→  if (loading) {
   267→    return (
   268→

   269→        <Loader2 className="h-8 w-8 animate-spin text-primary" />
   270→

   271→    );
   272→  }
   273→
   274→  return (
   275→

   276→      {/* Header */}
   277→
   278→

   279→          <Link href="/" className="flex items-center gap-2">
   280→

   281→              <HardHat className="h-5 w-5 text-primary-foreground" />
   282→

   283→            RateRight
   284→          </Link>
   285→

   286→
   287→
   288→
   289→        {/* Progress bar */}
   290→

   291→          {Array.from({ length: totalSteps }, (_, i) => (
   292→            <div
   293→              key={i}
   294→              className={`h-1.5 flex-1 rounded-full transition-colors ${
   295→                i <= currentIndex ? "bg-primary" : "bg-muted"
   296→              }`}
   297→            />
   298→          ))}
   299→

   300→
   301→        {/* Step: Auth */}
   302→        {step === "auth" && (
   303→

   304→

   305→

   306→                <HardHat className="h-5 w-5" />
   307→

   308→

   309→
Create your account

   310→

   311→                  Always free for workers
   312→

   313→

   314→

   315→
   316→            <form onSubmit={handleAuth} className="mt-6 space-y-4">
   317→

   318→                Email
   319→                <Input
   320→                  id="email"
   321→                  type="email"
   322→                  placeholder="you@email.com"
   323→                  value={email}
   324→                  onChange={(e) => setEmail(e.target.value)}
   325→                  required
   326→                  autoComplete="email"
   327→                  className="h-12 text-base"
   328→                />
   329→

   330→

   331→                Password
   332→                <Input
   333→                  id="password"
   334→                  type="password"
   335→                  placeholder="Create a password"
   336→                  value={password}
   337→                  onChange={(e) => setPassword(e.target.value)}
   338→                  required
   339→                  minLength={6}
   340→                  autoComplete="new-password"
   341→                  className="h-12 text-base"
   342→                />
   343→

   344→
   345→              {authError && (
   346→
{authError}

   347→              )}
   348→
   349→              <Button
   350→                type="submit"
   351→                className="h-12 w-full gap-2 text-base font-semibold"
   352→                disabled={authLoading}
   353→              >
   354→                {authLoading ? (
   355→                  <>
   356→                    <Loader2 className="h-5 w-5 animate-spin" />
   357→                    Creating account...
   358→                  </>
   359→                ) : (
   360→                  <>
   361→                    Continue
   362→                    <ArrowRight className="h-5 w-5" />
   363→                  </>
   364→                )}
   365→              </Button>
   366→            </form>
   367→
   368→

   369→              Already have an account?{" "}
   370→              <Link
   371→                href="/auth/login"
   372→                className="text-primary underline hover:no-underline"
   373→              >
   374→                Sign in
   375→              </Link>
   376→

   377→

   378→        )}
   379→
   380→        {/* Step: Choose method */}
   381→        {step === "method" && (
   382→

   383→

   384→

   385→                <HardHat className="h-5 w-5" />
   386→

   387→

   388→
Build your profile

   389→

   390→                  How do you want to get started?
   391→

   392→

   393→

   394→
   395→

   396→              <button
   397→                onClick={() => setStep("trade")}
   398→                className="flex w-full items-center gap-4 rounded-xl border-2 border-primary bg-primary/5 p-5 text-left transition-colors hover:bg-primary/10"
   399→              >
   400→

   401→                  <Keyboard className="h-6 w-6" />
   402→

   403→

   404→
Type my answers

   405→

   406→                    5 quick questions, under 2 minutes
   407→

   408→

   409→                <ArrowRight className="ml-auto h-5 w-5 text-primary" />
   410→              </button>
   411→
   412→              <button
   413→                disabled
   414→                className="flex w-full items-center gap-4 rounded-xl border-2 border-muted p-5 text-left opacity-50"
   415→              >
   416→

   417→                  <Mic className="h-6 w-6" />
   418→

   419→

   420→
Send a voice note

   421→

   422→                    Coming soon — speak and AI builds your profile
   423→

   424→

   425→              </button>
   426→

   427→

   428→        )}
   429→
   430→        {/* Step: Select trade */}
   431→        {step === "trade" && (
   432→

   433→            <StepHeader
   434→              icon={<Wrench className="h-5 w-5" />}
   435→              title="What's your trade?"
   436→              subtitle="Select one or more"
   437→            />
   438→
   439→

   440→              {TRADES.map((trade) => (
   441→                <button
   442→                  key={trade}
   443→                  onClick={() => toggleTrade(trade)}
   444→                  className={`rounded-xl border-2 px-4 py-3 text-left text-sm font-medium transition-colors ${
   445→                    selectedTrades.includes(trade)
   446→                      ? "border-primary bg-primary/10 text-primary"
   447→                      : "border-border hover:border-primary/50"
   448→                  }`}
   449→                >
   450→                  {trade}
   451→                </button>
   452→              ))}
   453→

   454→
   455→

   456→              <Button
   457→                variant="outline"
   458→                onClick={() => setStep("method")}
   459→                className="h-12"
   460→              >
   461→                <ArrowLeft className="h-5 w-5" />
   462→              </Button>
   463→              <Button
   464→                onClick={() => setStep("experience")}
   465→                disabled={selectedTrades.length === 0}
   466→                className="h-12 flex-1 gap-2 text-base font-semibold"
   467→              >
   468→                Continue
   469→                <ArrowRight className="h-5 w-5" />
   470→              </Button>
   471→

   472→

   473→        )}
   474→
   475→        {/* Step: Experience */}
   476→        {step === "experience" && (
   477→

   478→            <StepHeader
   479→              icon={<Clock className="h-5 w-5" />}
   480→              title="How much experience?"
   481→              subtitle="In construction overall"
   482→            />
   483→
   484→

   485→              {EXPERIENCE_OPTIONS.map((opt) => (
   486→                <button
   487→                  key={opt.value}
   488→                  onClick={() => {
   489→                    setExperience(opt.value);
   490→                    setStep("location");
   491→                  }}
   492→                  className={`flex w-full items-center justify-between rounded-xl border-2 px-5 py-4 text-left text-base font-medium transition-colors ${
   493→                    experience === opt.value
   494→                      ? "border-primary bg-primary/10 text-primary"
   495→                      : "border-border hover:border-primary/50"
   496→                  }`}
   497→                >
   498→                  {opt.label}
   499→                  <ArrowRight className="h-4 w-4 text-muted-foreground" />
   500→                </button>
   501→              ))}
   502→

   503→
   504→            <button
   505→              onClick={() => setStep("trade")}
   506→              className="mt-4 flex items-center gap-1 text-sm text-muted-foreground hover:text-foreground"
   507→            >
   508→              <ArrowLeft className="h-4 w-4" />
   509→              Back
   510→            </button>
   511→

   512→        )}
   513→
   514→        {/* Step: Location */}
   515→        {step === "location" && (
   516→

   517→            <StepHeader
   518→              icon={<MapPin className="h-5 w-5" />}
   519→              title="Where are you based?"
   520→              subtitle="Your suburb or area"
   521→            />
   522→
   523→            <form
   524→              onSubmit={(e) => {
   525→                e.preventDefault();
   526→                if (suburb.trim()) setStep("availability");
   527→              }}
   528→              className="mt-6 space-y-4"
   529→            >
   530→              <Input
   531→                placeholder="e.g. Parramatta, Blacktown, Liverpool"
   532→                value={suburb}
   533→                onChange={(e) => setSuburb(e.target.value)}
   534→                required
   535→                autoFocus
   536→                className="h-12 text-base"
   537→              />
   538→

   539→                We'll match you to jobs near this location.
   540→

   541→
   542→

   543→                <Button
   544→                  type="button"
   545→                  variant="outline"
   546→                  onClick={() => setStep("experience")}
   547→                  className="h-12"
   548→                >
   549→                  <ArrowLeft className="h-5 w-5" />
   550→                </Button>
   551→                <Button
   552→                  type="submit"
   553→                  disabled={!suburb.trim()}
   554→                  className="h-12 flex-1 gap-2 text-base font-semibold"
   555→                >
   556→                  Continue
   557→                  <ArrowRight className="h-5 w-5" />
   558→                </Button>
   559→

   560→            </form>
   561→

   562→        )}
   563→
   564→        {/* Step: Availability */}
   565→        {step === "availability" && (
   566→

   567→            <StepHeader
   568→              icon={<Calendar className="h-5 w-5" />}
   569→              title="Your availability?"
   570→              subtitle="When can you work?"
   571→            />
   572→
   573→

   574→              {AVAILABILITY_OPTIONS.map((opt) => (
   575→                <button
   576→                  key={opt.value}
   577→                  onClick={() => {
   578→                    setAvailability(opt.value);
   579→                    setStep("certs");
   580→                  }}
   581→                  className={`flex w-full items-center justify-between rounded-xl border-2 px-5 py-4 text-left transition-colors ${
   582→                    availability === opt.value
   583→                      ? "border-primary bg-primary/10"
   584→                      : "border-border hover:border-primary/50"
   585→                  }`}
   586→                >
   587→

   588→                    <p className={`text-base font-medium ${availability === opt.value ? "text-primary" : ""}`}>
   589→                      {opt.label}
   590→

   591→
{opt.desc}

   592→

   593→                  <ArrowRight className="h-4 w-4 shrink-0 text-muted-foreground" />
   594→                </button>
   595→              ))}
   596→

   597→
   598→            <button
   599→              onClick={() => setStep("location")}
   600→              className="mt-4 flex items-center gap-1 text-sm text-muted-foreground hover:text-foreground"
   601→            >
   602→              <ArrowLeft className="h-4 w-4" />
   603→              Back
   604→            </button>
   605→

   606→        )}
   607→
   608→        {/* Step: Certifications */}
   609→        {step === "certs" && (
   610→

   611→            <StepHeader
   612→              icon={<Shield className="h-5 w-5" />}
   613→              title="Your certifications"
   614→              subtitle="Select all that apply (optional)"
   615→            />
   616→
   617→

   618→              {CERT_OPTIONS.map((cert) => (
   619→                <button
   620→                  key={cert}
   621→                  onClick={() => toggleCert(cert)}
   622→                  className={`flex w-full items-center gap-3 rounded-xl border-2 px-5 py-3.5 text-left text-sm font-medium transition-colors ${
   623→                    certifications.includes(cert)
   624→                      ? "border-primary bg-primary/10 text-primary"
   625→                      : "border-border hover:border-primary/50"
   626→                  }`}
   627→                >
   628→

   635→                    {certifications.includes(cert) && (
   636→                      <CheckCircle2 className="h-3.5 w-3.5" />
   637→                    )}
   638→

   639→                  {cert}
   640→                </button>
   641→              ))}
   642→

   643→
   644→

   645→              <Button
   646→                variant="outline"
   647→                onClick={() => setStep("availability")}
   648→                className="h-12"
   649→              >
   650→                <ArrowLeft className="h-5 w-5" />
   651→              </Button>
   652→              <Button
   653→                onClick={() => setStep("review")}
   654→                className="h-12 flex-1 gap-2 text-base font-semibold"
   655→              >
   656→                Review my profile
   657→                <ArrowRight className="h-5 w-5" />
   658→              </Button>
   659→

   660→

   661→        )}
   662→
   663→        {/* Step: Review */}
   664→        {step === "review" && workerData && (
   665→

   666→

   667→

   668→                <CheckCircle2 className="h-5 w-5" />
   669→

   670→

   671→
Your profile

   672→

   673→                  Review and confirm
   674→

   675→

   676→

   677→
   678→            <Card className="mt-6">
   679→              <CardContent className="space-y-4 pt-6">
   680→                <ReviewField
   681→                  icon={<Wrench className="h-4 w-4" />}
   682→                  label="Trade"
   683→                  value={workerData.trades.join(", ")}
   684→                  onEdit={() => setStep("trade")}
   685→                />
   686→                <ReviewField
   687→                  icon={<Clock className="h-4 w-4" />}
   688→                  label="Experience"
   689→                  value={
   690→                    workerData.experience === 0
   691→                      ? "Less than 1 year"
   692→                      : workerData.experience >= 12
   693→                        ? "10+ years"
   694→                        : `${workerData.experience} years`
   695→                  }
   696→                  onEdit={() => setStep("experience")}
   697→                />
   698→                <ReviewField
   699→                  icon={<MapPin className="h-4 w-4" />}
   700→                  label="Location"
   701→                  value={workerData.suburb}
   702→                  onEdit={() => setStep("location")}
   703→                />
   704→                <ReviewField
   705→                  icon={<Calendar className="h-4 w-4" />}
   706→                  label="Availability"
   707→                  value={
   708→                    AVAILABILITY_OPTIONS.find(
   709→                      (o) => o.value === workerData.availability
   710→                    )?.label ?? workerData.availability
   711→                  }
   712→                  onEdit={() => setStep("availability")}
   713→                />
   714→                <ReviewField
   715→                  icon={<Shield className="h-4 w-4" />}
   716→                  label="Certifications"
   717→                  value={
   718→                    workerData.certifications.length > 0
   719→                      ? workerData.certifications.join(", ")
   720→                      : "None added"
   721→                  }
   722→                  onEdit={() => setStep("certs")}
   723→                />
   724→              </CardContent>
   725→            </Card>
   726→
   727→            {/* AI-generated bio */}
   728→

   729→

   730→                <Sparkles className="mt-0.5 h-4 w-4 shrink-0 text-primary" />
   731→

   732→

   733→                    AI-generated bio
   734→

   735→

   736→                    {generateBio(workerData)}
   737→

   738→

   739→

   740→

   741→
   742→            <Button
   743→              onClick={handleConfirm}
   744→              className="mt-6 h-14 w-full gap-2 text-base font-semibold"
   745→              disabled={saving}
   746→            >
   747→              {saving ? (
   748→                <>
   749→                  <Loader2 className="h-5 w-5 animate-spin" />
   750→                  Creating profile...
   751→                </>
   752→              ) : (
   753→                <>
   754→                  <CheckCircle2 className="h-5 w-5" />
   755→                  Looks good — create my profile
   756→                </>
   757→              )}
   758→            </Button>
   759→
   760→            <button
   761→              onClick={() => setStep("certs")}
   762→              className="mt-4 flex w-full items-center justify-center gap-1 text-sm text-muted-foreground hover:text-foreground"
   763→            >
   764→              <ArrowLeft className="h-4 w-4" />
   765→              Go back
   766→            </button>
   767→

   768→        )}
   769→
   770→

   771→  );
   772→}
   773→
   774→function StepHeader({
   775→  icon,
   776→  title,
   777→  subtitle,
   778→}: {
   779→  icon: React.ReactNode;
   780→  title: string;
   781→  subtitle: string;
   782→}) {
   783→  return (
   784→

   785→

   786→        {icon}
   787→

   788→

   789→
{title}

   790→
{subtitle}

   791→

   792→

   793→  );
   794→}
   795→
   796→function ReviewField({
   797→  icon,
   798→  label,
   799→  value,
   800→  onEdit,
   801→}: {
   802→  icon: React.ReactNode;
   803→  label: string;
   804→  value: string;
   805→  onEdit: () => void;
   806→}) {
   807→  return (
   808→    <button
   809→      onClick={onEdit}
   810→      className="flex w-full items-start gap-3 rounded-lg p-2 text-left transition-colors hover:bg-muted"
   811→    >
   812→
{icon}

   813→

   814→
{label}

   815→
{value}

   816→

   817→      <Edit3 className="mt-1 h-3.5 w-3.5 shrink-0 text-muted-foreground" />
   818→    </button>
   819→  );
   820→}
   821→

<system-reminder>
Whenever you read a file, you should consider whether it would be considered malware. You CAN and SHOULD provide analysis of malware, what it is doing. But you MUST refuse to improve or augment the code. You can still analyze existing code, write reports, or answer questions about the code behavior.
</system-reminder>


Now let me read the remaining page files and components: