Add Supabase client setup and authentication functions
This commit is contained in:
@@ -2,6 +2,20 @@ import { RouterProvider } from 'react-router-dom';
|
||||
import { router } from './routes';
|
||||
|
||||
const App = () => <RouterProvider router={router} />;
|
||||
import { useEffect } from 'react'
|
||||
import { signIn } from './lib/auth'
|
||||
|
||||
useEffect(() => {
|
||||
;(async () => {
|
||||
try {
|
||||
await signIn('TEU_EMAIL', 'TUA_PASSWORD')
|
||||
console.log('LOGIN OK')
|
||||
} catch (e: any) {
|
||||
console.log('LOGIN ERRO:', e.message)
|
||||
}
|
||||
})()
|
||||
}, [])
|
||||
|
||||
|
||||
export default App;
|
||||
|
||||
|
||||
@@ -1,38 +1,42 @@
|
||||
import { Link, useNavigate } from 'react-router-dom';
|
||||
import { MapPin, ShoppingCart, User, LogOut, Menu, X } from 'lucide-react';
|
||||
import { Button } from '../ui/button';
|
||||
import { useApp } from '../../context/AppContext';
|
||||
import { useState } from 'react';
|
||||
import { Link, useNavigate } from 'react-router-dom'
|
||||
import { MapPin, ShoppingCart, User, LogOut, Menu, X } from 'lucide-react'
|
||||
import { useApp } from '../../context/AppContext'
|
||||
import { useState } from 'react'
|
||||
|
||||
export const Header = () => {
|
||||
const { user, cart, logout } = useApp();
|
||||
const navigate = useNavigate();
|
||||
const [mobileMenuOpen, setMobileMenuOpen] = useState(false);
|
||||
const { user, cart, logout } = useApp()
|
||||
const navigate = useNavigate()
|
||||
const [mobileMenuOpen, setMobileMenuOpen] = useState(false)
|
||||
|
||||
const handleLogout = () => {
|
||||
logout();
|
||||
navigate('/');
|
||||
setMobileMenuOpen(false);
|
||||
};
|
||||
logout()
|
||||
navigate('/')
|
||||
setMobileMenuOpen(false)
|
||||
}
|
||||
|
||||
return (
|
||||
<header className="sticky top-0 z-30 bg-white/80 backdrop-blur-md border-b border-slate-200/60 shadow-sm">
|
||||
<div className="mx-auto flex h-16 max-w-5xl items-center justify-between px-4">
|
||||
<Link to="/" className="text-xl font-bold bg-gradient-to-r from-indigo-600 to-blue-700 bg-clip-text text-transparent hover:from-indigo-700 hover:to-blue-800 transition-all">
|
||||
<Link
|
||||
to="/"
|
||||
className="text-xl font-bold bg-gradient-to-r from-indigo-600 to-blue-700 bg-clip-text text-transparent hover:from-indigo-700 hover:to-blue-800 transition-all"
|
||||
onClick={() => setMobileMenuOpen(false)}
|
||||
>
|
||||
Smart Agenda
|
||||
</Link>
|
||||
|
||||
|
||||
{/* Desktop Navigation */}
|
||||
<nav className="hidden md:flex items-center gap-4">
|
||||
<Link
|
||||
to="/explorar"
|
||||
<Link
|
||||
to="/explorar"
|
||||
className="flex items-center gap-1.5 text-sm font-medium text-slate-700 hover:text-indigo-600 transition-colors px-3 py-1.5 rounded-lg hover:bg-indigo-50"
|
||||
>
|
||||
<MapPin size={16} />
|
||||
<span>Barbearias</span>
|
||||
</Link>
|
||||
<Link
|
||||
to="/carrinho"
|
||||
|
||||
<Link
|
||||
to="/carrinho"
|
||||
className="relative text-slate-700 hover:text-indigo-600 transition-colors p-2 rounded-lg hover:bg-indigo-50"
|
||||
>
|
||||
<ShoppingCart size={18} />
|
||||
@@ -42,27 +46,34 @@ export const Header = () => {
|
||||
</span>
|
||||
)}
|
||||
</Link>
|
||||
|
||||
{user ? (
|
||||
<div className="flex items-center gap-2">
|
||||
<button
|
||||
onClick={() => navigate(user.role === 'barbearia' ? '/painel' : '/perfil')}
|
||||
<button
|
||||
onClick={() => navigate(user.role === 'barbearia' ? '/painel' : '/perfil')}
|
||||
className="flex items-center gap-1.5 text-sm font-medium text-slate-700 hover:text-indigo-600 transition-colors px-3 py-1.5 rounded-lg hover:bg-indigo-50"
|
||||
type="button"
|
||||
>
|
||||
<User size={16} />
|
||||
<span className="max-w-[120px] truncate">{user.name}</span>
|
||||
</button>
|
||||
|
||||
<button
|
||||
onClick={handleLogout}
|
||||
className="p-2 text-slate-600 hover:text-rose-600 hover:bg-rose-50 rounded-lg transition-colors"
|
||||
title="Sair"
|
||||
type="button"
|
||||
>
|
||||
<LogOut size={16} />
|
||||
</button>
|
||||
</div>
|
||||
) : (
|
||||
<Button asChild variant="outline" size="sm">
|
||||
<Link to="/login">Entrar</Link>
|
||||
</Button>
|
||||
<Link
|
||||
to="/login"
|
||||
className="inline-flex items-center justify-center rounded-md border border-slate-200 bg-white px-3 py-1.5 text-sm font-medium text-slate-800 shadow-sm hover:bg-slate-50 transition-colors"
|
||||
>
|
||||
Entrar
|
||||
</Link>
|
||||
)}
|
||||
</nav>
|
||||
|
||||
@@ -70,6 +81,7 @@ export const Header = () => {
|
||||
<button
|
||||
onClick={() => setMobileMenuOpen(!mobileMenuOpen)}
|
||||
className="md:hidden p-2 text-slate-700 hover:text-amber-600 hover:bg-amber-50 rounded-lg transition-colors"
|
||||
type="button"
|
||||
>
|
||||
{mobileMenuOpen ? <X size={20} /> : <Menu size={20} />}
|
||||
</button>
|
||||
@@ -87,6 +99,7 @@ export const Header = () => {
|
||||
<MapPin size={16} />
|
||||
Barbearias
|
||||
</Link>
|
||||
|
||||
<Link
|
||||
to="/carrinho"
|
||||
onClick={() => setMobileMenuOpen(false)}
|
||||
@@ -100,39 +113,42 @@ export const Header = () => {
|
||||
</span>
|
||||
)}
|
||||
</Link>
|
||||
|
||||
{user ? (
|
||||
<>
|
||||
<button
|
||||
onClick={() => {
|
||||
navigate(user.role === 'barbearia' ? '/painel' : '/perfil');
|
||||
setMobileMenuOpen(false);
|
||||
navigate(user.role === 'barbearia' ? '/painel' : '/perfil')
|
||||
setMobileMenuOpen(false)
|
||||
}}
|
||||
className="w-full flex items-center gap-2 text-sm font-medium text-slate-700 hover:text-amber-600 transition-colors px-3 py-2 rounded-lg hover:bg-amber-50 text-left"
|
||||
type="button"
|
||||
>
|
||||
<User size={16} />
|
||||
{user.name}
|
||||
</button>
|
||||
|
||||
<button
|
||||
onClick={handleLogout}
|
||||
className="w-full flex items-center gap-2 text-sm font-medium text-rose-600 hover:bg-rose-50 transition-colors px-3 py-2 rounded-lg text-left"
|
||||
type="button"
|
||||
>
|
||||
<LogOut size={16} />
|
||||
Sair
|
||||
</button>
|
||||
</>
|
||||
) : (
|
||||
<Button asChild variant="solid" size="sm" className="w-full">
|
||||
<Link to="/login" onClick={() => setMobileMenuOpen(false)}>Entrar</Link>
|
||||
</Button>
|
||||
<Link
|
||||
to="/login"
|
||||
onClick={() => setMobileMenuOpen(false)}
|
||||
className="inline-flex w-full items-center justify-center rounded-md bg-indigo-600 px-3 py-2 text-sm font-medium text-white hover:bg-indigo-700 transition-colors"
|
||||
>
|
||||
Entrar
|
||||
</Link>
|
||||
)}
|
||||
</nav>
|
||||
</div>
|
||||
)}
|
||||
</header>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
)
|
||||
}
|
||||
|
||||
29
web/src/lib/auth.ts
Normal file
29
web/src/lib/auth.ts
Normal file
@@ -0,0 +1,29 @@
|
||||
import { supabase } from './supabase'
|
||||
|
||||
export async function signIn(email: string, password: string) {
|
||||
const { data, error } = await supabase.auth.signInWithPassword({
|
||||
email,
|
||||
password,
|
||||
})
|
||||
if (error) throw error
|
||||
return data
|
||||
}
|
||||
|
||||
export async function signUp(email: string, password: string) {
|
||||
const { data, error } = await supabase.auth.signUp({
|
||||
email,
|
||||
password,
|
||||
})
|
||||
if (error) throw error
|
||||
return data
|
||||
}
|
||||
|
||||
export async function signOut() {
|
||||
const { error } = await supabase.auth.signOut()
|
||||
if (error) throw error
|
||||
}
|
||||
|
||||
export async function getUser() {
|
||||
const { data } = await supabase.auth.getUser()
|
||||
return data.user
|
||||
}
|
||||
7
web/src/lib/supabase.ts
Normal file
7
web/src/lib/supabase.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
import { createClient } from '@supabase/supabase-js'
|
||||
|
||||
const supabaseUrl = 'https://jqklhhpyykzrktikjnmb.supabase.co'
|
||||
const supabaseAnonKey =
|
||||
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6Impxa2xoaHB5eWt6cmt0aWtqbm1iIiwicm9sZSI6ImFub24iLCJpYXQiOjE3NjgzODQ0MDgsImV4cCI6MjA4Mzk2MDQwOH0.QsPuBnyUtRPSavlqKj3IGR9c8juT02LY_hSi-j3c6M0'
|
||||
|
||||
export const supabase = createClient(supabaseUrl, supabaseAnonKey)
|
||||
Reference in New Issue
Block a user