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

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13,502 changes: 0 additions & 13,502 deletions frontend/package-lock.json

This file was deleted.

1 change: 1 addition & 0 deletions frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
"@radix-ui/react-toggle-group": "^1.1.11",
"@radix-ui/react-tooltip": "^1.2.8",
"@radix-ui/react-use-controllable-state": "^1.2.2",
"@supabase/ssr": "^0.7.0",
"@supabase/supabase-js": "^2.75.0",
"@tanstack/react-table": "^8.21.3",
"ai": "^5.0.68",
Expand Down
29 changes: 21 additions & 8 deletions frontend/pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

73 changes: 51 additions & 22 deletions frontend/src/app/auth/callback/page.tsx
Original file line number Diff line number Diff line change
@@ -1,32 +1,61 @@
"use client";

import { useEffect } from "react";
import { useRouter } from "next/navigation";
import { createSupabaseServerClient } from "@/integrations/supabase/server";
import { Loader2 } from "lucide-react";
import { redirect } from "next/navigation";
import { Suspense } from "react";

async function AuthCallbackHandler({ code }: { code: string | null }) {
if (code) {
const supabase = createSupabaseServerClient();
const { error } = await supabase.auth.exchangeCodeForSession(code);
if (error) {
console.error("Auth callback error:", error.message);
redirect(`/login?error=${encodeURIComponent(error.message)}`);
} else {
redirect("/onboarding");
}
}

export default function AuthCallbackPage() {
const router = useRouter();
redirect("/login?error=Invalid_callback_request");

useEffect(() => {
// Simulate auth processing
const timer = setTimeout(() => {
router.push("/onboarding");
}, 2000);
return null;
Comment on lines +18 to +20
Copy link

Copilot AI Oct 25, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unreachable code: the return null; statement on line 20 will never execute because redirect() throws and transfers control.

Copilot uses AI. Check for mistakes.
}

return () => clearTimeout(timer);
}, [router]);
export default function AuthCallbackPage({
searchParams,
}: {
searchParams: { code?: string; error?: string; error_description?: string };
}) {
const { code, error, error_description } = searchParams;

if (error) {
console.error("OAuth Error:", error, error_description);
redirect(
`/login?error=${encodeURIComponent(
error_description || "An error occurred during authentication."
)}`
);
}

return (
<div className="flex min-h-svh flex-col items-center justify-center gap-6 bg-muted p-6">
<div className="flex flex-col items-center gap-4">
<Loader2 className="h-12 w-12 animate-spin text-primary" />
<div className="text-center">
<h1 className="text-xl font-semibold">Connecting your account...</h1>
<p className="mt-2 text-sm text-muted-foreground">
Just a moment while we set things up
</p>
</div>
</div>
<Suspense
fallback={
<div className="flex flex-col items-center gap-4">
<Loader2 className="h-12 w-12 animate-spin text-primary" />
<div className="text-center">
<h1 className="text-xl font-semibold">
Connecting your account...
</h1>
<p className="mt-2 text-sm text-muted-foreground">
Just a moment while we set things up
</p>
</div>
</div>
}
>
<AuthCallbackHandler code={code || null} />
</Suspense>
</div>
);
}

65 changes: 48 additions & 17 deletions frontend/src/components/login-form.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
"use client";

import { useRouter } from "next/navigation";
import { useTheme } from "next-themes";
import { useEffect, useState } from "react";
import { cn } from "@/lib/utils";
Expand All @@ -14,14 +13,28 @@ import {
} from "@/components/ui/card";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { Loader2 } from "lucide-react"
import { supabase } from "@/integrations/supabase/client";

const getURL = () => {
let url =
process?.env?.NEXT_PUBLIC_SITE_URL ??
process?.env?.NEXT_PUBLIC_VERCEL_URL ??
"http://localhost:3000/";
url = url.includes("http") ? url : `https://${url}`;
url = url.charAt(url.length - 1) === "/" ? url : `${url}/`;
return `${url}auth/callback`;
};

export function LoginForm({
className,
...props
}: React.ComponentPropsWithoutRef<"div">) {
const router = useRouter();
const { theme, resolvedTheme } = useTheme();
const [mounted, setMounted] = useState(false);
const [loading, setLoading] = useState(false);
const [error, setError] = useState<string | null>(null);


useEffect(() => {
setMounted(true);
Expand All @@ -32,9 +45,20 @@ export function LoginForm({
? '/branding/gradient_logo_dark_theme.svg'
: '/branding/gradient_logo_light_theme.svg';

const handleGitHubLogin = () => {
// Simula redirect para GitHub OAuth
router.push("/auth/callback");
const handleGitHubLogin = async () => {
setLoading(true);

const { error } = await supabase.auth.signInWithOAuth({
provider: "github",
options: {
redirectTo: "http://localhost:3000/auth/callback",
Copy link

Copilot AI Oct 25, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hardcoded localhost URL should use the getURL() helper function defined above (lines 19-27) to support different environments.

Suggested change
redirectTo: "http://localhost:3000/auth/callback",
redirectTo: getURL(),

Copilot uses AI. Check for mistakes.
},
});

if (error) {
setError(error.message);
setLoading(false);
}
};

return (
Expand Down Expand Up @@ -98,23 +122,30 @@ export function LoginForm({
Or continue with
</span>
</div>
<Button
<Button
variant="outline"
className="group h-10 w-full gap-2.5 rounded-lg border-2 border-border text-base font-medium text-[hsl(var(--secondary-accent))] dark:bg-white dark:text-[hsl(var(--secondary-accent))] transition-all duration-300 hover:border-[hsl(var(--secondary-accent))] hover:!bg-[hsl(var(--secondary-accent))] hover:!text-white hover:shadow-lg"
type="button"
onClick={handleGitHubLogin}
disabled={loading}
>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
className="h-[18px] w-[18px] text-[hsl(var(--secondary-accent))] transition-all duration-300 group-hover:!text-white"
>
<path
fill="currentColor"
d="M12 2C6.477 2 2 6.477 2 12c0 4.42 2.865 8.17 6.839 9.49.5.092.682-.217.682-.482 0-.237-.008-.866-.013-1.7-2.782.603-3.369-1.34-3.369-1.34-.454-1.156-1.11-1.463-1.11-1.463-.908-.62.069-.608.069-.608 1.003.07 1.531 1.03 1.531 1.03.892 1.529 2.341 1.087 2.91.831.092-.646.35-1.086.636-1.336-2.22-.253-4.555-1.11-4.555-4.943 0-1.091.39-1.984 1.029-2.683-.103-.253-.446-1.27.098-2.647 0 0 .84-.269 2.75 1.025A9.578 9.578 0 0 1 12 6.836c.85.004 1.705.114 2.504.336 1.909-1.294 2.747-1.025 2.747-1.025.546 1.377.203 2.394.1 2.647.64.699 1.028 1.592 1.028 2.683 0 3.842-2.339 4.687-4.566 4.935.359.309.678.919.678 1.852 0 1.336-.012 2.415-.012 2.743 0 .267.18.578.688.48C19.138 20.167 22 16.418 22 12c0-5.523-4.477-10-10-10z"
/>
</svg>
Connect with GitHub
{loading ? (
<Loader2 className="h-5 w-5 animate-spin" />
) : (
<>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
className="h-[18px] w-[18px] text-[hsl(var(--secondary-accent))] transition-all duration-300 group-hover:!text-white"
>
<path
fill="currentColor"
d="M12 2C6.477 2 2 6.477 2 12c0 4.42 2.865 8.17 6.839 9.49.5.092.682-.217.682-.482 0-.237-.008-.866-.013-1.7-2.782.603-3.369-1.34-3.369-1.34-.454-1.156-1.11-1.463-1.11-1.463-.908-.62.069-.608.069-.608 1.003.07 1.531 1.03 1.531 1.03.892 1.529 2.341 1.087 2.91.831.092-.646.35-1.086.636-1.336-2.22-.253-4.555-1.11-4.555-4.943 0-1.091.39-1.984 1.029-2.683-.103-.253-.446-1.27.098-2.647 0 0 .84-.269 2.75 1.025A9.578 9.578 0 0 1 12 6.836c.85.004 1.705.114 2.504.336 1.909-1.294 2.747-1.025 2.747-1.025.546 1.377.203 2.394.1 2.647.64.699 1.028 1.592 1.028 2.683 0 3.842-2.339 4.687-4.566 4.935.359.309.678.919.678 1.852 0 1.336-.012 2.415-.012 2.743 0 .267.18.578.688.48C19.138 20.167 22 16.418 22 12c0-5.523-4.477-10-10-10z"
/>
</svg>
Connect with GitHub
</>
)}
</Button>
<div className="text-center text-sm">
Don&apos;t have an account?{" "}
Expand Down
42 changes: 26 additions & 16 deletions frontend/src/integrations/supabase/client.ts
Original file line number Diff line number Diff line change
@@ -1,37 +1,47 @@
// This file is automatically generated. Do not edit it directly.
import { createClient } from '@supabase/supabase-js';
import type { Database } from './types';
import { createBrowserClient } from "@supabase/ssr";
import type { Database } from "./types";

// Toggle between local and remote via environment variable
const USE_LOCAL = process.env.NEXT_PUBLIC_USE_LOCAL_SUPABASE === 'true';
const USE_LOCAL = process.env.NEXT_PUBLIC_USE_LOCAL_SUPABASE === "true";

// Local Supabase (when running `supabase start`)
const LOCAL_SUPABASE_URL = "http://127.0.0.1:54321";
const LOCAL_SUPABASE_ANON_KEY = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZS1kZW1vIiwicm9sZSI6ImFub24iLCJleHAiOjE5ODM4MTI5OTZ9.CRXP1A7WOeoJeXxjNni43kdQwgnWNReilDMblYTn_I0";
const LOCAL_SUPABASE_ANON_KEY =
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZS1kZW1vIiwicm9sZSI6ImFub24iLCJleHAiOjE5ODM4MTI5OTZ9.CRXP1A7WOeoJeXxjNni43kdQwgnWNReilDMblYTn_I0";

// Remote Supabase (from environment variables)
const REMOTE_SUPABASE_URL = process.env.NEXT_PUBLIC_SUPABASE_URL;
const REMOTE_SUPABASE_ANON_KEY = process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY;

const SUPABASE_URL = USE_LOCAL
? LOCAL_SUPABASE_URL
: REMOTE_SUPABASE_URL;
const SUPABASE_URL = USE_LOCAL ? LOCAL_SUPABASE_URL : REMOTE_SUPABASE_URL;

const SUPABASE_ANON_KEY = USE_LOCAL
? LOCAL_SUPABASE_ANON_KEY
: REMOTE_SUPABASE_ANON_KEY;

if (!SUPABASE_URL || !SUPABASE_ANON_KEY) {
throw new Error('Missing Supabase configuration. Check your .env.local file.');
throw new Error(
"Missing Supabase configuration. Check your .env.local file.",
);
}

// Import the supabase client like this:
// import { supabase } from "@/integrations/supabase/client";

export const supabase = createClient<Database>(SUPABASE_URL, SUPABASE_ANON_KEY, {
auth: {
autoRefreshToken: true,
persistSession: true,
detectSessionInUrl: true,
// import { supabase } from ":/integrations/supabase/client";
Copy link

Copilot AI Oct 25, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Corrected malformed import path prefix from ':' to '@'.

Suggested change
// import { supabase } from ":/integrations/supabase/client";
// import { supabase } from "@/integrations/supabase/client";

Copilot uses AI. Check for mistakes.

const NORMALIZED_URL = SUPABASE_URL.endsWith("/")
? SUPABASE_URL.slice(0, -1)
: SUPABASE_URL;

export const supabase = createBrowserClient<Database>(
NORMALIZED_URL,
SUPABASE_ANON_KEY,
{
auth: {
autoRefreshToken: true,
persistSession: true,
flowType: "pkce",
detectSessionInUrl: false,
},
},
});
);
Loading