Read the FULL contents of every page.tsx, layout.tsx, loading.tsx, error.tsx, and not-found.tsx file under /home/ccuser/the-50-dollar-app/src/app/. I need to see the complete code for each file to audit UI consistency.

Start by finding all these files, then read each one completely. Focus on:
- CSS classes used (Tailwind classes)
- Components imported and used
- Color classes (text-*, bg-*, border-*)
- Typography classes (text-sm, text-lg, font-bold, etc.)
- Spacing classes (p-*, m-*, gap-*, space-*)
- Layout patterns (flex, grid, etc.)
- Any inline styles

List each file with its full content.


I'll find and read all the page.tsx, layout.tsx, loading.tsx, error.tsx, and not-found.tsx files under /home/ccuser/the-50-dollar-app/src/app/. Let me start by locating them.


Now let me read all of these files completely:


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

<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 Link from "next/link";
     2→import Image from "next/image";
     3→import { Button } from "@/components/ui/button";
     4→import { Card, CardContent } from "@/components/ui/card";
     5→import {
     6→  Building2,
     7→  HardHat,
     8→  Zap,
     9→  DollarSign,
    10→  Shield,
    11→  CheckCircle2,
    12→  Search,
    13→  ArrowRight,
    14→  Sparkles,
    15→  MapPin,
    16→  Clock,
    17→  Users,
    18→} from "lucide-react";
    19→
    20→// Force static generation
    21→export const dynamic = 'force-static';
    22→
    23→export default function LandingPage() {
    24→  return (
    25→

    26→      {/* Orange accent bar */}
    27→

    28→
    29→      {/* Header */}
    30→
    31→

    32→          <Link href="/" className="flex items-center gap-2">
    33→            <Image src="/logo_black.svg" alt="RateRight" width={140} height={40} className="h-8 w-auto" priority />
    34→          </Link>
    35→          <Link href="/auth/login">
    36→            <Button variant="ghost" size="sm">
    37→              Sign in
    38→            </Button>
    39→          </Link>
    40→

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

    45→

    46→

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

    50→
    51→

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

    55→
    56→

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

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

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

    81→
    82→

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

    85→

    86→

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

    90→

    91→

    92→            How it works
    93→

    94→

    95→            Three steps. Under two minutes.
    96→

    97→
    98→

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

   118→

   119→

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

   123→

   124→

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

   127→

   128→

   129→            Stop wasting time hiring
   130→

   131→
   132→

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

   154→

   155→

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

   159→

   160→

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

   163→

   164→

   165→            Get on a job fast
   166→

   167→

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

   170→
   171→

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

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

   197→

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

   201→

   202→
Simple pricing

   203→

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

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

   210→

   211→                per hire — that's it
   212→

   213→

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

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

   223→

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

   227→

   228→
Ready to hire smarter?

   229→

   230→            Join Sydney contractors already using RateRight.
   231→

   232→

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

   252→

   253→

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

   258→

   259→

   260→              <Image src="/logo_black.svg" alt="RateRight" width={110} height={32} className="h-6 w-auto" />
   261→

   262→

   263→              <Link href="/faq" className="hover:text-foreground">
   264→                FAQ
   265→              </Link>
   266→
   270→                Contact
   271→
   272→

   273→

   274→

   275→            The simplest way to hire construction workers in Australia.
   276→

   277→

   278→            © {new Date().getFullYear()} RateRight Pty Ltd. All rights
   279→            reserved.
   280→

   281→

   282→
   283→

   284→  );
   285→}
   286→
   287→function Step({
   288→  number,
   289→  icon,
   290→  title,
   291→  description,
   292→}: {
   293→  number: string;
   294→  icon: React.ReactNode;
   295→  title: string;
   296→  description: string;
   297→}) {
   298→  return (
   299→

   300→

   301→        {number}
   302→

   303→

   304→

   305→          {icon}
   306→
{title}

   307→

   308→

   309→          {description}
   310→

   311→

   312→

   313→  );
   314→}
   315→
   316→function FeatureCard({
   317→  icon,
   318→  title,
   319→  description,
   320→}: {
   321→  icon: React.ReactNode;
   322→  title: string;
   323→  description: string;
   324→}) {
   325→  return (
   326→

   327→
{icon}

   328→

   329→
{title}

   330→
{description}

   331→

   332→

   333→  );
   334→}
   335→
   336→function Benefit({
   337→  icon,
   338→  text,
   339→}: {
   340→  icon: React.ReactNode;
   341→  text: string;
   342→}) {
   343→  return (
   344→

   345→
{icon}

   346→      {text}
   347→

   348→  );
   349→}
   350→
   351→function BenefitCheck({ text }: { text: string }) {
   352→  return (
   353→

   354→      <CheckCircle2 className="h-4 w-4 shrink-0 text-primary" />
   355→      {text}
   356→

   357→  );
   358→}
   359→

<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 { useEffect } from 'react';
     4→import { ErrorDisplay } from '@/components/error-display';
     5→
     6→export default function Error({
     7→  error,
     8→  reset,
     9→}: {
    10→  error: Error & { digest?: string };
    11→  reset: () => void;
    12→}) {
    13→  useEffect(() => {
    14→    // Log the error to an error reporting service
    15→    console.error('Root error boundary caught:', error);
    16→  }, [error]);
    17→
    18→  return (
    19→    <div className="min-h-screen bg-background flex items-center justify-center p-4">
    20→      <ErrorDisplay
    21→        title="Something went wrong"
    22→        message="We encountered an unexpected error. Don't worry, we're on it."
    23→        error={error}
    24→        onRetry={reset}
    25→        showContactSupport={true}
    26→      />
    27→    </div>
    28→  );
    29→}

<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 Link from 'next/link';
     4→import { Home, Hammer, ArrowLeft } from 'lucide-react';
     5→import { Button } from '@/components/ui/button';
     6→import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from '@/components/ui/card';
     7→
     8→export default function NotFound() {
     9→  return (
    10→
    11→
    12→

    13→          <Card className="border-muted-foreground/20">
    14→            <CardHeader className="text-center">
    15→

    16→                <Hammer className="h-10 w-10 text-primary" />
    17→

    18→              <CardTitle className="text-2xl">Page not found</CardTitle>
    19→              <CardDescription className="mt-2">
    20→                Sorry, we couldn't find the page you're looking for.
    21→              </CardDescription>
    22→            </CardHeader>
    23→
    24→            <CardContent className="space-y-4">
    25→

    26→

    27→                  The link you followed may be broken, or the page may have been moved.
    28→

    29→

    30→
    31→

    32→

    33→                  Looking to hire construction workers?

    34→                  Head to your dashboard to post a job or browse available workers.
    35→

    36→

    37→            </CardContent>
    38→
    39→            <CardFooter className="flex flex-col gap-3">
    40→              <Button asChild className="w-full">
    41→                <Link href="/">
    42→                  <Home className="mr-2 h-4 w-4" />
    43→                  Go to homepage
    44→                </Link>
    45→              </Button>
    46→
    47→              <Button
    48→                onClick={() => window.history.back()}
    49→                className="w-full"
    50→                variant="outline"
    51→              >
    52→                <ArrowLeft className="mr-2 h-4 w-4" />
    53→                Go back
    54→              </Button>
    55→            </CardFooter>
    56→          </Card>
    57→
    58→
    59→

    60→              RateRight — Hire Construction Workers Fast
    61→

    62→
    63→

    64→
    65→
    66→  );
    67→}

<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 { createClient } from '@/lib/supabase/server'
     3→import Link from 'next/link'
     4→import Image from 'next/image'
     5→import { Home, Briefcase, MessageSquare, User } from 'lucide-react'
     6→
     7→export default async function AuthenticatedLayout({
     8→  children,
     9→}: {
    10→  children: React.ReactNode
    11→}) {
    12→  const supabase = await createClient()
    13→  const { data: { user } } = await supabase.auth.getUser()
    14→
    15→  if (!user) {
    16→    redirect('/auth/login')
    17→  }
    18→
    19→  return (
    20→

    21→      {/* Header */}
    22→
    23→

    24→          <Link href="/dashboard">
    25→            <Image src="/logo_black.svg" alt="RateRight" width={120} height={34} className="h-7 w-auto" />
    26→          </Link>
    27→          {user.email}
    28→

    29→
    30→
    31→      {/* Main Content */}
    32→
    33→        {children}
    34→
    35→
    36→      {/* Bottom Navigation */}
    37→
    38→

    39→          <Link href="/dashboard" className="flex flex-col items-center p-2 text-muted-foreground hover:text-primary">
    40→            <Home className="w-6 h-6" />
    41→            Home
    42→          </Link>
    43→          <Link href="/contractor/post-job" className="flex flex-col items-center p-2 text-muted-foreground hover:text-primary">
    44→            <Briefcase className="w-6 h-6" />
    45→            Jobs
    46→          </Link>
    47→          <Link href="/messages" className="flex flex-col items-center p-2 text-muted-foreground hover:text-primary">
    48→            <MessageSquare className="w-6 h-6" />
    49→            Messages
    50→          </Link>
    51→          <Link href="/worker/profile/build" className="flex flex-col items-center p-2 text-muted-foreground hover:text-primary">
    52→            <User className="w-6 h-6" />
    53→            Profile
    54→          </Link>
    55→

    56→
    57→

    58→  )
    59→}
    60→

<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 { useEffect } from 'react';
     4→import { ErrorDisplay } from '@/components/error-display';
     5→
     6→export default function AuthenticatedError({
     7→  error,
     8→  reset,
     9→}: {
    10→  error: Error & { digest?: string };
    11→  reset: () => void;
    12→}) {
    13→  useEffect(() => {
    14→    // Log the error to an error reporting service
    15→    console.error('Authenticated route error boundary caught:', error);
    16→  }, [error]);
    17→
    18→  // Check if it's an authentication error
    19→  const isAuthError = error.message?.includes('authentication') ||
    20→                      error.message?.includes('unauthorized') ||
    21→                      error.message?.includes('login');
    22→
    23→  return (
    24→    <div className="min-h-screen bg-background flex items-center justify-center p-4">
    25→      <ErrorDisplay
    26→        error={error}
    27→        onRetry={isAuthError ? undefined : reset}
    28→        showContactSupport={true}
    29→        variant={isAuthError ? 'authentication' : 'default'}
    30→      />
    31→    </div>
    32→  );
    33→}

<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→
    61→

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

    64→

    65→          {isContractor
    66→            ? "Ready to find your next worker?"
    67→            : "Let's get you on a job."}
    68→

    69→
    70→

    71→          {isContractor ? (
    72→            <>
    73→              {/* Quick stats */}
    74→

    75→                <Card>
    76→                  <CardContent className="flex flex-col items-center p-4">
    77→                    {jobCount}
    78→                    Active Jobs
    79→                  </CardContent>
    80→                </Card>
    81→                <Card>
    82→                  <CardContent className="flex flex-col items-center p-4">
    83→                    {matchCount}
    84→                    New Matches
    85→                  </CardContent>
    86→                </Card>
    87→

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

   185→
   186→
   187→      <BottomNavWrapper userType={profile?.type || "worker"} />
   188→

   189→  );
   190→}
   191→

<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 { Card, CardContent, CardHeader } from '@/components/ui/card';
     2→import { Skeleton } from '@/components/ui/skeleton';
     3→
     4→export default function DashboardLoading() {
     5→  return (
     6→

     7→      {/* Page header skeleton */}
     8→

     9→        <Skeleton className="h-10 w-64" />
    10→        <Skeleton className="h-5 w-96" />
    11→

    12→
    13→      {/* Stats cards skeleton */}
    14→

    15→        {[...Array(4)].map((_, i) => (
    16→          <Card key={i}>
    17→            <CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
    18→              <Skeleton className="h-4 w-24" />
    19→              <Skeleton className="h-4 w-4" />
    20→            </CardHeader>
    21→            <CardContent>
    22→              <Skeleton className="h-7 w-20" />
    23→              <Skeleton className="h-4 w-32 mt-1" />
    24→            </CardContent>
    25→          </Card>
    26→        ))}
    27→

    28→
    29→      {/* Main content skeleton */}
    30→

    31→        <Card>
    32→          <CardHeader>
    33→            <Skeleton className="h-6 w-32" />
    34→            <Skeleton className="h-4 w-48" />
    35→          </CardHeader>
    36→          <CardContent className="space-y-4">
    37→            {[...Array(3)].map((_, i) => (
    38→

    39→                <Skeleton className="h-12 w-12 rounded-full" />
    40→

    41→                  <Skeleton className="h-4 w-full" />
    42→                  <Skeleton className="h-3 w-32" />
    43→

    44→

    45→            ))}
    46→          </CardContent>
    47→        </Card>
    48→
    49→        <Card>
    50→          <CardHeader>
    51→            <Skeleton className="h-6 w-32" />
    52→            <Skeleton className="h-4 w-48" />
    53→          </CardHeader>
    54→          <CardContent className="space-y-4">
    55→            {[...Array(3)].map((_, i) => (
    56→

    57→

    58→                  <Skeleton className="h-4 w-24" />
    59→                  <Skeleton className="h-4 w-16" />
    60→

    61→                <Skeleton className="h-2 w-full" />
    62→

    63→            ))}
    64→          </CardContent>
    65→        </Card>
    66→

    67→

    68→  );
    69→}

<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 continue reading the remaining files:


1→import Link from "next/link";
     2→import Image from "next/image";
     3→import type { Metadata } from "next";
     4→import { HelpCircle, Building2, Wrench, Users } from "lucide-react";
     5→import { Button } from "@/components/ui/button";
     6→import {
     7→  Accordion,
     8→  AccordionContent,
     9→  AccordionItem,
    10→  AccordionTrigger,
    11→} from "@/components/ui/accordion";
    12→
    13→export const metadata: Metadata = {
    14→  title: "FAQ — RateRight",
    15→  description:
    16→    "Frequently asked questions about RateRight, the simplest way to hire construction workers in Australia.",
    17→};
    18→
    19→export const dynamic = "force-static";
    20→
    21→const workerFaqs = [
    22→  {
    23→    q: "How does RateRight work for workers?",
    24→    a: "RateRight connects qualified construction workers with contractors who need skilled labour. Simply create your profile, verify your qualifications, and get matched with jobs that fit your skills and schedule.",
    25→  },
    26→  {
    27→    q: "Is RateRight free for workers?",
    28→    a: "Yes! It is completely free for workers to join, create a profile, and get matched with jobs. We do not charge any subscription fees or take a percentage of your earnings.",
    29→  },
    30→  {
    31→    q: "How do I get hired through RateRight?",
    32→    a: "Complete your profile with accurate information about your skills, experience, and certifications. Upload your White Card and any trade-specific licences. Contractors search our database and contact workers directly.",
    33→  },
    34→  {
    35→    q: "What trades does RateRight cover?",
    36→    a: "We cover all major construction trades including carpentry, plumbing, electrical, bricklaying, concreting, tiling, plastering, painting, landscaping, and general labour.",
    37→  },
    38→  {
    39→    q: "Do I need a White Card to join?",
    40→    a: "Yes, all workers must have a valid White Card (General Construction Induction Card) to work on Australian construction sites.",
    41→  },
    42→  {
    43→    q: "How quickly can I find work?",
    44→    a: "Many workers receive their first job invitation within 24\u201348 hours of profile approval.",
    45→  },
    46→  {
    47→    q: "How and when do I get paid?",
    48→    a: "Payment terms are agreed directly with the contractor before starting work. Most contractors pay weekly or fortnightly. RateRight does not handle payments.",
    49→  },
    50→  {
    51→    q: "Can I choose when and where I work?",
    52→    a: "Absolutely! You set your availability and preferred work locations in your profile.",
    53→  },
    54→];
    55→
    56→const contractorFaqs = [
    57→  {
    58→    q: "How does RateRight work for contractors?",
    59→    a: "RateRight gives you instant access to pre-verified construction workers. Search our database by trade, location, availability, and ratings.",
    60→  },
    61→  {
    62→    q: "What is the $50 fee about?",
    63→    a: "We charge a flat $50 fee per successful job placement. No subscriptions, no hidden costs, no percentage cuts.",
    64→  },
    65→  {
    66→    q: "How fast can I find workers?",
    67→    a: "Most contractors find suitable workers within hours. Many jobs are filled the same day they are posted.",
    68→  },
    69→  {
    70→    q: "What if the worker does not show up?",
    71→    a: "We take reliability seriously. Workers with no-shows are removed from the platform. Contact us immediately and we will help you find a replacement quickly.",
    72→  },
    73→  {
    74→    q: "Are workers verified?",
    75→    a: "Yes, all workers go through our verification process. We check White Cards, trade licences, and conduct identity verification.",
    76→  },
    77→  {
    78→    q: "How many workers can I contact?",
    79→    a: "As many as you need! There is no limit to how many workers you can view or contact.",
    80→  },
    81→  {
    82→    q: "Do I have to use RateRight for payment?",
    83→    a: "No, you handle payment directly with the worker according to your normal payroll processes.",
    84→  },
    85→  {
    86→    q: "What areas does RateRight cover?",
    87→    a: "We currently operate in Sydney, Melbourne, Brisbane, Perth, and Adelaide metropolitan areas.",
    88→  },
    89→];
    90→
    91→const generalFaqs = [
    92→  {
    93→    q: "Is RateRight a labour hire company?",
    94→    a: "No, RateRight is a marketplace platform that connects contractors directly with workers. We are not a labour hire company.",
    95→  },
    96→  {
    97→    q: "How is payment handled?",
    98→    a: "Payment is arranged directly between the contractor and worker. RateRight does not process payments or take a percentage of wages.",
    99→  },
   100→  {
   101→    q: "What areas do you cover?",
   102→    a: "RateRight currently operates in major Australian cities: Sydney, Melbourne, Brisbane, Perth, and Adelaide.",
   103→  },
   104→  {
   105→    q: "Is there a rating system?",
   106→    a: "Yes, both workers and contractors can rate each other after completing a job.",
   107→  },
   108→  {
   109→    q: "How do I get started?",
   110→    a: "Simply visit our website and click Sign Up. Workers create a profile with their skills and qualifications. Contractors can start searching immediately.",
   111→  },
   112→  {
   113→    q: "What makes RateRight different?",
   114→    a: "Unlike traditional labour hire companies, we charge contractors a simple flat fee with no ongoing subscriptions. Workers keep 100% of their wages.",
   115→  },
   116→];
   117→
   118→function FAQSection({
   119→  title,
   120→  icon,
   121→  faqs,
   122→  idPrefix,
   123→}: {
   124→  title: string;
   125→  icon: React.ReactNode;
   126→  faqs: { q: string; a: string }[];
   127→  idPrefix: string;
   128→}) {
   129→  return (
   130→

   131→

   132→

   133→          {icon}
   134→

   135→
{title}

   136→

   137→      <Accordion type="single" collapsible className="w-full">
   138→        {faqs.map((faq, i) => (
   139→          <AccordionItem key={i} value={`${idPrefix}-${i}`}>
   140→            <AccordionTrigger>{faq.q}</AccordionTrigger>
   141→            <AccordionContent>
   142→
{faq.a}

   143→            </AccordionContent>
   144→          </AccordionItem>
   145→        ))}
   146→      </Accordion>
   147→

   148→  );
   149→}
   150→
   151→export default function FAQPage() {
   152→  return (
   153→

   154→      {/* Orange accent bar */}
   155→

   156→
   157→      {/* Header */}
   158→
   159→

   160→          <Link href="/" className="flex items-center gap-2">
   161→            <Image src="/logo_black.svg" alt="RateRight" width={140} height={40} className="h-8 w-auto" priority />
   162→          </Link>
   163→          <Link href="/auth/login">
   164→            <Button variant="ghost" size="sm">
   165→              Sign in
   166→            </Button>
   167→          </Link>
   168→

   169→
   170→
   171→      {/* Hero */}
   172→

   173→

   174→

   175→            <HelpCircle className="h-6 w-6 text-primary" />
   176→

   177→

   178→            Frequently Asked Questions
   179→

   180→

   181→            Everything you need to know about hiring and finding work on
   182→            RateRight.
   183→

   184→

   185→

   186→
   187→      {/* FAQ Sections */}
   188→

   189→

   190→          <FAQSection
   191→            title="For Workers"
   192→            icon={<Wrench className="h-4 w-4 text-primary-foreground" />}
   193→            faqs={workerFaqs}
   194→            idPrefix="worker"
   195→          />
   196→
   197→          <FAQSection
   198→            title="For Contractors"
   199→            icon={<Building2 className="h-4 w-4 text-primary-foreground" />}
   200→            faqs={contractorFaqs}
   201→            idPrefix="contractor"
   202→          />
   203→
   204→          <FAQSection
   205→            title="General Questions"
   206→            icon={<Users className="h-4 w-4 text-primary-foreground" />}
   207→            faqs={generalFaqs}
   208→            idPrefix="general"
   209→          />
   210→

   211→

   212→
   213→      {/* CTA */}
   214→

   215→

   216→

   217→            Still have questions?
   218→

   219→

   220→            Get in touch and we'll get back to you as soon as we can.
   221→

   222→

   223→            <Link href="/auth/signup">
   224→              <Button className="w-full sm:w-auto h-12 gap-2 text-base font-semibold">
   225→                Get started
   226→              </Button>
   227→            </Link>
   228→

   229→

   230→

   231→
   232→      {/* Footer */}
   233→
   234→

   235→

   236→            <Image src="/logo_black.svg" alt="RateRight" width={110} height={32} className="h-6 w-auto" />
   237→

   238→

   239→            The simplest way to hire construction workers in Australia.
   240→

   241→

   242→            © {new Date().getFullYear()} RateRight Pty Ltd. All rights
   243→            reserved.
   244→

   245→

   246→
   247→

   248→  );
   249→}
   250→

<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→import { useState } from "react";
     3→import { useRouter } from "next/navigation";
     4→import Link from "next/link";
     5→import { createClient } from "@/lib/supabase/client";
     6→import { Button } from "@/components/ui/button";
     7→import { Input } from "@/components/ui/input";
     8→import { Label } from "@/components/ui/label";
     9→import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
    10→import { HardHat, Building2 } from "lucide-react";
    11→import type { UserType } from "@/lib/types";
    12→
    13→export default function SignupPage() {
    14→  const [email, setEmail] = useState("");
    15→  const [password, setPassword] = useState("");
    16→  const [userType, setUserType] = useState<UserType | null>(null);
    17→  const [error, setError] = useState<string | null>(null);
    18→  const [loading, setLoading] = useState(false);
    19→  const router = useRouter();
    20→  const supabase = createClient();
    21→
    22→  async function handleSignup(e: React.FormEvent) {
    23→    e.preventDefault();
    24→    if (!userType) {
    25→      setError("Please select whether you're hiring or looking for work");
    26→      return;
    27→    }
    28→
    29→    setLoading(true);
    30→    setError(null);
    31→
    32→    const { error } = await supabase.auth.signUp({
    33→      email,
    34→      password,
    35→      options: {
    36→        data: { type: userType },
    37→        emailRedirectTo: `${window.location.origin}/auth/callback`,
    38→      },
    39→    });
    40→
    41→    if (error) {
    42→      setError(error.message);
    43→      setLoading(false);
    44→      return;
    45→    }
    46→
    47→    // Redirect to email verification page instead of dashboard
    48→    router.push("/auth/verify-email");
    49→    router.refresh();
    50→  }
    51→
    52→  return (
    53→

    54→      <Card className="w-full max-w-md">
    55→        <CardHeader>
    56→          <CardTitle className="text-2xl font-bold text-center">Create your account</CardTitle>
    57→          <CardDescription className="text-center">
    58→            Sign up to find work or hire workers
    59→          </CardDescription>
    60→        </CardHeader>
    61→        <CardContent>
    62→          <form onSubmit={handleSignup} className="space-y-6">
    63→

    64→

    65→                Email address
    66→                <Input
    67→                  id="email"
    68→                  type="email"
    69→                  value={email}
    70→                  onChange={(e) => setEmail(e.target.value)}
    71→                  required
    72→                  placeholder="you@example.com"
    73→                />
    74→

    75→

    76→                Password
    77→                <Input
    78→                  id="password"
    79→                  type="password"
    80→                  value={password}
    81→                  onChange={(e) => setPassword(e.target.value)}
    82→                  required
    83→                  placeholder="••••••••"
    84→                  minLength={6}
    85→                />
    86→

    87→

    88→
    89→

    90→              I am a...
    91→

    92→                <Button
    93→                  type="button"
    94→                  variant={userType === "contractor" ? "default" : "outline"}
    95→                  onClick={() => setUserType("contractor")}
    96→                  className="h-24 flex-col gap-2"
    97→                >
    98→                  <Building2 className="h-6 w-6" />
    99→                  Contractor
   100→                  Hiring workers
   101→                </Button>
   102→                <Button
   103→                  type="button"
   104→                  variant={userType === "worker" ? "default" : "outline"}
   105→                  onClick={() => setUserType("worker")}
   106→                  className="h-24 flex-col gap-2"
   107→                >
   108→                  <HardHat className="h-6 w-6" />
   109→                  Worker
   110→                  Looking for work
   111→                </Button>
   112→

   113→

   114→
   115→            {error && (
   116→

   117→
{error}

   118→

   119→            )}
   120→
   121→            <Button type="submit" className="w-full" disabled={loading}>
   122→              {loading ? "Creating account..." : "Create account"}
   123→            </Button>
   124→
   125→

   126→              Already have an account?{" "}
   127→              <Link href="/auth/login" className="font-medium text-primary hover:text-primary/80">
   128→                Sign in
   129→              </Link>
   130→

   131→          </form>
   132→        </CardContent>
   133→      </Card>
   134→

   135→  );
   136→}
   137→

<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 { 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, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
    11→
    12→export default function LoginPage() {
    13→  const [email, setEmail] = useState("");
    14→  const [password, setPassword] = useState("");
    15→  const [error, setError] = useState<string | null>(null);
    16→  const [loading, setLoading] = useState(false);
    17→  const router = useRouter();
    18→  const supabase = createClient();
    19→
    20→  async function handleLogin(e: React.FormEvent) {
    21→    e.preventDefault();
    22→    setLoading(true);
    23→    setError(null);
    24→
    25→    const { data, error } = await supabase.auth.signInWithPassword({
    26→      email,
    27→      password,
    28→    });
    29→
    30→    if (error) {
    31→      setError(error.message);
    32→      setLoading(false);
    33→      return;
    34→    }
    35→
    36→    // Check if email is verified before allowing dashboard access
    37→    if (data.user && !data.user.email_confirmed_at) {
    38→      router.push("/auth/verify-email");
    39→      router.refresh();
    40→      return;
    41→    }
    42→
    43→    router.push("/dashboard");
    44→    router.refresh();
    45→  }
    46→
    47→  return (
    48→

    49→      <Card className="w-full max-w-sm">
    50→        <CardHeader className="text-center">
    51→          <CardTitle className="text-2xl font-bold">Welcome back</CardTitle>
    52→          <CardDescription>Sign in to your RateRight account</CardDescription>
    53→        </CardHeader>
    54→        <CardContent>
    55→          <form onSubmit={handleLogin} className="space-y-5">
    56→

    57→              Email
    58→              <Input
    59→                id="email"
    60→                type="email"
    61→                placeholder="you@example.com"
    62→                value={email}
    63→                onChange={(e) => setEmail(e.target.value)}
    64→                required
    65→                autoComplete="email"
    66→                className="h-14 text-base"
    67→              />
    68→

    69→

    70→              Password
    71→              <Input
    72→                id="password"
    73→                type="password"
    74→                placeholder="Your password"
    75→                value={password}
    76→                onChange={(e) => setPassword(e.target.value)}
    77→                required
    78→                autoComplete="current-password"
    79→                className="h-14 text-base"
    80→              />
    81→

    82→            {error && (
    83→
{error}

    84→            )}
    85→            <Button type="submit" className="w-full h-16 text-lg font-semibold" disabled={loading}>
    86→              {loading ? "Signing in..." : "Sign in"}
    87→            </Button>
    88→          </form>
    89→

    90→            Don't have an account?{" "}
    91→            <Link href="/auth/signup" className="text-primary underline hover:no-underline">
    92→              Sign up
    93→            </Link>
    94→

    95→        </CardContent>
    96→      </Card>
    97→

    98→  );
    99→}
   100→

<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 { createClient } from "@/lib/supabase/client";
     6→import { Button } from "@/components/ui/button";
     7→import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
     8→import { Mail, CheckCircle2, Clock } from "lucide-react";
     9→
    10→export default function VerifyEmailPage() {
    11→  const [emailSent, setEmailSent] = useState(false);
    12→  const [loading, setLoading] = useState(false);
    13→  const [error, setError] = useState<string | null>(null);
    14→  const router = useRouter();
    15→  const supabase = createClient();
    16→
    17→  useEffect(() => {
    18→    // Check if user is already logged in and email is verified
    19→    checkEmailStatus();
    20→  }, []);
    21→
    22→  async function checkEmailStatus() {
    23→    const { data: { user } } = await supabase.auth.getUser();
    24→
    25→    if (user?.email_confirmed_at) {
    26→      // Email is already verified, redirect to dashboard
    27→      router.push('/dashboard');
    28→    }
    29→  }
    30→
    31→  async function resendVerificationEmail() {
    32→    setLoading(true);
    33→    setError(null);
    34→
    35→    try {
    36→      const { data: { user } } = await supabase.auth.getUser();
    37→
    38→      if (!user) {
    39→        setError("No user found. Please log in again.");
    40→        setLoading(false);
    41→        return;
    42→      }
    43→
    44→      const { error } = await supabase.auth.resend({
    45→        type: 'signup',
    46→        email: user.email as string,
    47→      });
    48→
    49→      if (error) {
    50→        setError(error.message);
    51→      } else {
    52→        setEmailSent(true);
    53→      }
    54→    } catch (error) {
    55→      setError("Failed to resend verification email.");
    56→    } finally {
    57→      setLoading(false);
    58→    }
    59→  }
    60→
    61→  return (
    62→

    63→      <Card className="w-full max-w-md">
    64→        <CardHeader className="text-center">
    65→

    66→            <Mail className="h-6 w-6 text-primary" />
    67→

    68→          <CardTitle className="mt-6 text-3xl font-extrabold text-foreground">
    69→            Check your email
    70→          </CardTitle>
    71→          <CardDescription className="mt-2 text-sm text-muted-foreground">
    72→            We've sent a verification email to your address. Please check your inbox and click the link to verify your email.
    73→          </CardDescription>
    74→        </CardHeader>
    75→        <CardContent className="space-y-6">
    76→

    77→

    78→              <Clock className="h-5 w-5 text-primary/60 mt-0.5" />
    79→

    80→
Didn't receive the email?

    81→

    82→
Check your spam folder or click the button below to resend the verification email.

    83→

    84→

    85→

    86→

    87→
    88→          {error && (
    89→

    90→

    91→

    92→
Error

    93→

    94→
{error}

    95→

    96→

    97→

    98→

    99→          )}
   100→
   101→          {emailSent && (
   102→

   103→

   104→                <CheckCircle2 className="h-5 w-5 text-green-400" />
   105→

   106→
Email sent!

   107→

   108→
We've resent the verification email. Please check your inbox.

   109→

   110→

   111→

   112→

   113→          )}
   114→
   115→

   116→            <Button
   117→              onClick={resendVerificationEmail}
   118→              disabled={loading || emailSent}
   119→              className="w-full"
   120→              variant="outline"
   121→            >
   122→              {loading ? "Sending..." : emailSent ? "Email sent" : "Resend verification email"}
   123→            </Button>
   124→
   125→            <Button
   126→              onClick={() => router.push('/auth/login')}
   127→              variant="ghost"
   128→              className="w-full"
   129→            >
   130→              Back to login
   131→            </Button>
   132→

   133→        </CardContent>
   134→      </Card>
   135→

   136→  );
   137→}
   138→

<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 Link from "next/link";
     4→import Image from "next/image";
     5→import { Button } from "@/components/ui/button";
     6→import { WifiOff, RefreshCw, Home } from "lucide-react";
     7→
     8→export default function OfflinePage() {
     9→  return (
    10→

    11→      {/* Orange accent bar */}
    12→

    13→
    14→

    15→        {/* Logo */}
    16→

    17→          <Image src="/logo_black.svg" alt="RateRight" width={160} height={46} className="h-10 w-auto" />
    18→

    19→
    20→        {/* Offline Icon */}
    21→

    22→          <WifiOff className="h-10 w-10 text-muted-foreground" />
    23→

    24→
    25→        {/* Title */}
    26→

    27→

    28→            You're offline
    29→

    30→

    31→            It looks like you've lost your internet connection. Please check your connection and try again.
    32→

    33→

    34→
    35→        {/* Actions */}
    36→

    37→          <Button
    38→            onClick={() => window.location.reload()}
    39→            className="gap-2"
    40→          >
    41→            <RefreshCw className="h-4 w-4" />
    42→            Try Again
    43→          </Button>
    44→          <Link href="/" className="sm:w-auto">
    45→            <Button variant="outline" className="gap-2 w-full">
    46→              <Home className="h-4 w-4" />
    47→              Go Home
    48→            </Button>
    49→          </Link>
    50→

    51→
    52→        {/* Additional Info */}
    53→

    54→

    55→            RateRight works best with a stable internet connection. Some features may not be available while offline.
    56→

    57→

    58→

    59→

    60→  );
    61→}

<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→      ai_research: {
   269→        abr_verified: true,
   270→        abn: companyData.abn,
   271→        verified_at: new Date().toISOString(),
   272→        source: "abr",
   273→      },
   274→    });
   275→
   276→    router.push("/dashboard");
   277→    router.refresh();
   278→  }
   279→
   280→  function updateCompanyField(field: keyof CompanyData, value: string) {
   281→    if (!companyData) return;
   282→    setCompanyData({ ...companyData, [field]: value });
   283→    setEditField(null);
   284→  }
   285→
   286→  const totalSteps = isAuthenticated ? 3 : 4;
   287→  const currentStep =
   288→    step === "auth" ? 0 : step === "company" ? 1 : step === "researching" ? 2 : 3;
   289→
   290→  if (loading) {
   291→    return (
   292→

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

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

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

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

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

   307→            RateRight
   308→          </Link>
   309→

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

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

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

   330→

   331→

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

   334→

   335→
Create your account

   336→

   337→                  Quick signup to get started
   338→

   339→

   340→

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

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

   356→

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

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

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

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

   403→

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

   409→

   410→

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

   413→

   414→
Your company

   415→

   416→                  We'll verify it via ABR
   417→

   418→

   419→

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

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

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

   437→

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

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

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

   467→

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

   470→
Verifying your business

   471→

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

   474→
   475→

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

   480→

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

   486→

   487→

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

   490→

   491→
Confirm your profile

   492→

   493→                  Tap any field to edit
   494→

   495→

   496→

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

   559→

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

   562→

   563→                    Verified via Australian Business Register
   564→

   565→

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

   568→

   569→

   570→

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

   598→        )}
   599→
   600→

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

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

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

   638→        {label}
   639→

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

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

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

   673→

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

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

   697→      ) : (
   698→
{icon}

   699→      )}
   700→

   701→
{label}

   702→
{value}

   703→

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

<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>