-
Notifications
You must be signed in to change notification settings - Fork 2
Feat/GitHub login #39
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: dev
Are you sure you want to change the base?
Changes from all commits
2fd5d16
842337b
8cd14cc
0dee241
0632479
02af65d
5411109
5c6d24a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
This file was deleted.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| 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; | ||
| } | ||
|
|
||
| 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> | ||
| ); | ||
| } | ||
|
|
||
| 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"; | ||||||
|
|
@@ -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); | ||||||
|
|
@@ -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", | ||||||
|
||||||
| redirectTo: "http://localhost:3000/auth/callback", | |
| redirectTo: getURL(), |
| 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"; | ||||||
|
||||||
| // import { supabase } from ":/integrations/supabase/client"; | |
| // import { supabase } from "@/integrations/supabase/client"; |
There was a problem hiding this comment.
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 becauseredirect()throws and transfers control.