diff --git a/src/core/settings.py b/src/core/settings.py index 19b0cd2..f750b56 100644 --- a/src/core/settings.py +++ b/src/core/settings.py @@ -42,11 +42,17 @@ class RefreshToken(BaseModel): expire_days: int +class CorsSettings(BaseModel): + production: str + local: list[str] = ["http://localhost:5173", "http://localhost:5174"] + + class Settings(BaseSettings): api: ApiPrefix = ApiPrefix() db: DbSettings = DbSettings() access_token: AccessToken refresh_token: RefreshToken + cors_settings: CorsSettings model_config = SettingsConfigDict( env_file=".env", env_file_encoding="utf-8", env_nested_delimiter="__" ) diff --git a/src/main.py b/src/main.py index 300d34e..f8c7dfb 100644 --- a/src/main.py +++ b/src/main.py @@ -5,10 +5,21 @@ import uvicorn from fastapi import FastAPI sys.path.append(str(Path(__file__).parent.parent)) +from fastapi.middleware.cors import CORSMiddleware + from src.api import router +from src.core.settings import settings app = FastAPI(title="Task&Coffee") app.include_router(router=router) +app.add_middleware( + CORSMiddleware, + allow_origins=settings.cors_settings.local + [settings.cors_settings.production], + allow_credentials=True, + allow_methods=["*"], + allow_headers=["*"], +) + if __name__ == "__main__": uvicorn.run("src.main:app", port=8000, log_level="info", reload=True) diff --git a/taskncoffee-app/package-lock.json b/taskncoffee-app/package-lock.json index 2b03a44..909161f 100644 --- a/taskncoffee-app/package-lock.json +++ b/taskncoffee-app/package-lock.json @@ -19,6 +19,7 @@ "motion": "^12.23.22", "react": "^19.1.1", "react-dom": "^19.1.1", + "react-router": "^7.9.4", "tailwind-merge": "^3.3.1", "tailwindcss": "^4.1.14" }, @@ -2221,6 +2222,15 @@ "dev": true, "license": "MIT" }, + "node_modules/cookie": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.0.2.tgz", + "integrity": "sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, "node_modules/cross-spawn": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", @@ -4686,6 +4696,28 @@ "node": ">=0.10.0" } }, + "node_modules/react-router": { + "version": "7.9.4", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.9.4.tgz", + "integrity": "sha512-SD3G8HKviFHg9xj7dNODUKDFgpG4xqD5nhyd0mYoB5iISepuZAvzSr8ywxgxKJ52yRzf/HWtVHc9AWwoTbljvA==", + "license": "MIT", + "dependencies": { + "cookie": "^1.0.1", + "set-cookie-parser": "^2.6.0" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "react": ">=18", + "react-dom": ">=18" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + } + } + }, "node_modules/reflect.getprototypeof": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz", @@ -4870,6 +4902,12 @@ "semver": "bin/semver.js" } }, + "node_modules/set-cookie-parser": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.1.tgz", + "integrity": "sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ==", + "license": "MIT" + }, "node_modules/set-function-length": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", diff --git a/taskncoffee-app/package.json b/taskncoffee-app/package.json index 5a49d48..657e29a 100644 --- a/taskncoffee-app/package.json +++ b/taskncoffee-app/package.json @@ -21,6 +21,7 @@ "motion": "^12.23.22", "react": "^19.1.1", "react-dom": "^19.1.1", + "react-router": "^7.9.4", "tailwind-merge": "^3.3.1", "tailwindcss": "^4.1.14" }, diff --git a/taskncoffee-app/src/layouts/AuthLayout.jsx b/taskncoffee-app/src/layouts/AuthLayout.jsx new file mode 100644 index 0000000..e69de29 diff --git a/taskncoffee-app/src/pages/Login.jsx b/taskncoffee-app/src/pages/Login.jsx index dbe1855..fb9149a 100644 --- a/taskncoffee-app/src/pages/Login.jsx +++ b/taskncoffee-app/src/pages/Login.jsx @@ -1,3 +1,4 @@ +import { useState } from "react" import { Button } from "@/components/ui/button" import { Card, @@ -10,8 +11,35 @@ import { } from "@/components/ui/card" import { Input } from "@/components/ui/input" import { Label } from "@/components/ui/label" +import { login } from "@/apiv1/auth.service" + export function LoginPage({ className }) { + const [username, setUsername] = useState("") + const [password, setPassword] = useState("") + const [isLoading, setIsLoading] = useState(false) + const [error, setError] = useState("") + const [success, setSuccess] = useState("") + + const handleSubmit = async (e) => { + e.preventDefault() + setError("") + setSuccess("") + setIsLoading(true) + + try { + const result = await login(username, password) + setSuccess("Login successful!") + console.log("Logged in:", result) + + } catch (err) { + setError(err.detail || "Login failed. Please check your credentials.") + console.error("Login error:", err) + } finally { + setIsLoading(false) + } + } + return (
@@ -25,15 +53,28 @@ export function LoginPage({ className }) { -
+
+ {error && ( +
+ {error} +
+ )} + {success && ( +
+ {success} +
+ )}
setUsername(e.target.value)} required + disabled={isLoading} />
@@ -46,14 +87,26 @@ export function LoginPage({ className }) { Forgot your password?
- + setPassword(e.target.value)} + required + disabled={isLoading} + />
- diff --git a/taskncoffee-app/src/pages/SignUp.jsx b/taskncoffee-app/src/pages/SignUp.jsx new file mode 100644 index 0000000..6d38b71 --- /dev/null +++ b/taskncoffee-app/src/pages/SignUp.jsx @@ -0,0 +1,68 @@ +import { Button } from "@/components/ui/button"; +import { Input } from "@/components/ui/input"; + +const Signup1 = ({ + heading = "Signup", + logo = { + url: "https://www.shadcnblocks.com", + src: "https://deifkwefumgah.cloudfront.net/shadcnblocks/block/logos/shadcnblockscom-wordmark.svg", + alt: "logo", + title: "shadcnblocks.com", + }, + buttonText = "Create Account", + signupText = "Already a user?", + signupUrl = "https://shadcnblocks.com", +}) => { + return ( +
+
+ {/* Logo */} +
+ + {logo.alt} + +
+ {heading &&

{heading}

} + + + + +
+
+

{signupText}

+ + Login + +
+
+
+
+ ); +}; + +export { Signup1 };