diff --git a/web/index.html b/web/index.html index 9429e77..2b58362 100644 --- a/web/index.html +++ b/web/index.html @@ -1,18 +1,3 @@ - - - - - - Smart Agenda - - - - - -
- - - - + Smart Agenda
diff --git a/web/package-lock.json b/web/package-lock.json index 9003946..c400260 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -8,6 +8,7 @@ "name": "smart-agenda-web", "version": "0.1.0", "dependencies": { + "@supabase/supabase-js": "^2.91.0", "classnames": "^2.5.1", "date-fns": "^4.1.0", "lucide-react": "^0.473.0", @@ -1138,6 +1139,86 @@ "win32" ] }, + "node_modules/@supabase/auth-js": { + "version": "2.91.0", + "resolved": "https://registry.npmjs.org/@supabase/auth-js/-/auth-js-2.91.0.tgz", + "integrity": "sha512-9ywvsKLsxTwv7fvN5fXzP3UfRreqrX2waylTBDu0lkmeHXa8WtSQS9e0WV9FBduiazYqQbgfBQXBNPRPsRgWOQ==", + "license": "MIT", + "dependencies": { + "tslib": "2.8.1" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@supabase/functions-js": { + "version": "2.91.0", + "resolved": "https://registry.npmjs.org/@supabase/functions-js/-/functions-js-2.91.0.tgz", + "integrity": "sha512-WaakXOqLK1mLtBNFXp5o5T+LlI6KZuADSeXz+9ofPRG5OpVSvW148LVJB1DRZ16Phck1a0YqIUswOUgxCz6vMw==", + "license": "MIT", + "dependencies": { + "tslib": "2.8.1" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@supabase/postgrest-js": { + "version": "2.91.0", + "resolved": "https://registry.npmjs.org/@supabase/postgrest-js/-/postgrest-js-2.91.0.tgz", + "integrity": "sha512-5S41zv2euNpGucvtM4Wy+xOmLznqt/XO+Lh823LOFEQ00ov7QJfvqb6VzIxufvzhooZpmGR0BxvMcJtWxCIFdQ==", + "license": "MIT", + "dependencies": { + "tslib": "2.8.1" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@supabase/realtime-js": { + "version": "2.91.0", + "resolved": "https://registry.npmjs.org/@supabase/realtime-js/-/realtime-js-2.91.0.tgz", + "integrity": "sha512-u2YuJFG35umw8DO9beC27L/jYXm3KhF+73WQwbynMpV0tXsFIA0DOGRM0NgRyy03hJIdO6mxTTwe8efW3yx3Tg==", + "license": "MIT", + "dependencies": { + "@types/phoenix": "^1.6.6", + "@types/ws": "^8.18.1", + "tslib": "2.8.1", + "ws": "^8.18.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@supabase/storage-js": { + "version": "2.91.0", + "resolved": "https://registry.npmjs.org/@supabase/storage-js/-/storage-js-2.91.0.tgz", + "integrity": "sha512-CI7fsVIBQHfNObqU9kmyQ1GWr+Ug44y4rSpvxT4LdQB9tlhg1NTBov6z7Dlmt8d6lGi/8a9lf/epCDxyWI792g==", + "license": "MIT", + "dependencies": { + "iceberg-js": "^0.8.1", + "tslib": "2.8.1" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@supabase/supabase-js": { + "version": "2.91.0", + "resolved": "https://registry.npmjs.org/@supabase/supabase-js/-/supabase-js-2.91.0.tgz", + "integrity": "sha512-Rjb0QqkKrmXMVwUOdEqysPBZ0ZDZakeptTkUa6k2d8r3strBdbWVDqjOdkCjAmvvZMtXecBeyTyMEXD1Zzjfvg==", + "license": "MIT", + "dependencies": { + "@supabase/auth-js": "2.91.0", + "@supabase/functions-js": "2.91.0", + "@supabase/postgrest-js": "2.91.0", + "@supabase/realtime-js": "2.91.0", + "@supabase/storage-js": "2.91.0" + }, + "engines": { + "node": ">=20.0.0" + } + }, "node_modules/@types/babel__core": { "version": "7.20.5", "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", @@ -1257,13 +1338,17 @@ "version": "22.19.2", "resolved": "https://registry.npmjs.org/@types/node/-/node-22.19.2.tgz", "integrity": "sha512-LPM2G3Syo1GLzXLGJAKdqoU35XvrWzGJ21/7sgZTUpbkBaOasTj8tjwn6w+hCkqaa1TfJ/w67rJSwYItlJ2mYw==", - "dev": true, "license": "MIT", - "peer": true, "dependencies": { "undici-types": "~6.21.0" } }, + "node_modules/@types/phoenix": { + "version": "1.6.7", + "resolved": "https://registry.npmjs.org/@types/phoenix/-/phoenix-1.6.7.tgz", + "integrity": "sha512-oN9ive//QSBkf19rfDv45M7eZPi0eEXylht2OLEXicu5b4KoQ1OzXIw+xDSGWxSxe1JmepRR/ZH283vsu518/Q==", + "license": "MIT" + }, "node_modules/@types/prop-types": { "version": "15.7.15", "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.15.tgz", @@ -1293,6 +1378,15 @@ "@types/react": "^18.0.0" } }, + "node_modules/@types/ws": { + "version": "8.18.1", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.1.tgz", + "integrity": "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@vitejs/plugin-react": { "version": "4.7.0", "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.7.0.tgz", @@ -1949,6 +2043,15 @@ "node": ">= 0.4" } }, + "node_modules/iceberg-js": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/iceberg-js/-/iceberg-js-0.8.1.tgz", + "integrity": "sha512-1dhVQZXhcHje7798IVM+xoo/1ZdVfzOMIc8/rgVSijRK38EDqOJoGula9N/8ZI5RD8QTxNQtK/Gozpr+qUqRRA==", + "license": "MIT", + "engines": { + "node": ">=20.0.0" + } + }, "node_modules/internmap": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz", @@ -2955,6 +3058,12 @@ "dev": true, "license": "Apache-2.0" }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, "node_modules/typescript": { "version": "5.9.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", @@ -2973,7 +3082,6 @@ "version": "6.21.0", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", - "dev": true, "license": "MIT" }, "node_modules/update-browserslist-db": { @@ -3106,6 +3214,27 @@ } } }, + "node_modules/ws": { + "version": "8.19.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.19.0.tgz", + "integrity": "sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, "node_modules/yallist": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", diff --git a/web/package.json b/web/package.json index 000c013..64c0ee8 100644 --- a/web/package.json +++ b/web/package.json @@ -10,6 +10,7 @@ "lint": "tsc --noEmit" }, "dependencies": { + "@supabase/supabase-js": "^2.91.0", "classnames": "^2.5.1", "date-fns": "^4.1.0", "lucide-react": "^0.473.0", @@ -32,6 +33,3 @@ "vite": "^5.4.10" } } - - - diff --git a/web/src/App.tsx b/web/src/App.tsx index ded4c23..cad4db6 100644 --- a/web/src/App.tsx +++ b/web/src/App.tsx @@ -2,6 +2,20 @@ import { RouterProvider } from 'react-router-dom'; import { router } from './routes'; const App = () => ; +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; diff --git a/web/src/components/layout/Header.tsx b/web/src/components/layout/Header.tsx index c1807b6..2b0972d 100644 --- a/web/src/components/layout/Header.tsx +++ b/web/src/components/layout/Header.tsx @@ -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 (
- + setMobileMenuOpen(false)} + > Smart Agenda - + {/* Desktop Navigation */} @@ -70,6 +81,7 @@ export const Header = () => { @@ -87,6 +99,7 @@ export const Header = () => { Barbearias + setMobileMenuOpen(false)} @@ -100,39 +113,42 @@ export const Header = () => { )} + {user ? ( <> + ) : ( - + 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 + )}
)}
- ); -}; - - - - - + ) +} diff --git a/web/src/lib/auth.ts b/web/src/lib/auth.ts new file mode 100644 index 0000000..d61383e --- /dev/null +++ b/web/src/lib/auth.ts @@ -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 +} diff --git a/web/src/lib/supabase.ts b/web/src/lib/supabase.ts new file mode 100644 index 0000000..d9c3c58 --- /dev/null +++ b/web/src/lib/supabase.ts @@ -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)