diff --git a/.env.local b/.env.local index 5bd7eea..ecdd6ae 100644 --- a/.env.local +++ b/.env.local @@ -1,2 +1,2 @@ -VITE_PROJECT_URL = 'https://rkrrreuxefnsnovornvcc.supabase.co' -VITE_PUBLIC_ANON_KEY = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6InJrcnJldXhlZm5zbm92b3JudmNjIiwicm9sZSI6ImFub24iLCJpYXQiOjE3NTI5MTM4NjYsImV4cCI6MjA2ODQ4OTg2Nn0.Y2-2gcusLoQ8STuUkV3V-1yvxpCzrY2Ur0vHwDZpDXc' \ No newline at end of file +VITE_PROJECT_URL=https://rkrreuxefnsnovornvcc.supabase.co +VITE_PUBLIC_ANON_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6InJrcnJldXhlZm5zbm92b3JudmNjIiwicm9sZSI6ImFub24iLCJpYXQiOjE3NTI5MTM4NjYsImV4cCI6MjA2ODQ4OTg2Nn0.Y2-2gcusLoQ8STuUkV3V-1yvxpCzrY2Ur0vHwDZpDXc \ No newline at end of file diff --git a/package.json b/package.json index ab9ad3c..9c54ddf 100644 --- a/package.json +++ b/package.json @@ -28,9 +28,11 @@ "react": "^19.0.0", "react-day-picker": "^9.7.0", "react-dom": "^19.0.0", + "react-router-dom": "^7.7.1", "tailwind-merge": "^3.2.0", "tailwindcss": "^4.1.3", - "tw-animate-css": "^1.2.5" + "tw-animate-css": "^1.2.5", + "zustand": "^5.0.6" }, "devDependencies": { "@commitlint/cli": "^19.8.0", @@ -38,6 +40,7 @@ "@eslint/js": "^9.21.0", "@types/react": "^19.0.10", "@types/react-dom": "^19.0.4", + "@types/react-router-dom": "^5.3.3", "@vitejs/plugin-react-swc": "^3.8.0", "eslint": "^9.24.0", "eslint-config-prettier": "^10.1.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 9c19063..0df0fcf 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -50,6 +50,9 @@ importers: react-dom: specifier: ^19.0.0 version: 19.1.0(react@19.1.0) + react-router-dom: + specifier: ^7.7.1 + version: 7.7.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0) tailwind-merge: specifier: ^3.2.0 version: 3.3.1 @@ -59,6 +62,9 @@ importers: tw-animate-css: specifier: ^1.2.5 version: 1.3.4 + zustand: + specifier: ^5.0.6 + version: 5.0.6(@types/react@19.1.8)(react@19.1.0)(use-sync-external-store@1.5.0(react@19.1.0)) devDependencies: '@commitlint/cli': specifier: ^19.8.0 @@ -75,6 +81,9 @@ importers: '@types/react-dom': specifier: ^19.0.4 version: 19.1.6(@types/react@19.1.8) + '@types/react-router-dom': + specifier: ^5.3.3 + version: 5.3.3 '@vitejs/plugin-react-swc': specifier: ^3.8.0 version: 3.10.2(vite@6.3.5(@types/node@24.0.3)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.0)) @@ -1466,6 +1475,9 @@ packages: '@types/hast@3.0.4': resolution: {integrity: sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==} + '@types/history@4.7.11': + resolution: {integrity: sha512-qjDJRrmvBMiTx+jyLxvLfJU7UznFuokDv4f3WRuriHKERccVpFU+8XMQUAbDzoiJCsmexxRExQeMwwCdamSKDA==} + '@types/json-schema@7.0.15': resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} @@ -1498,6 +1510,12 @@ packages: peerDependencies: '@types/react': ^19.0.0 + '@types/react-router-dom@5.3.3': + resolution: {integrity: sha512-kpqnYK4wcdm5UaWI3fLcELopqLrHgLqNsdpHauzlQktfkHL3npOSwtj1Uz9oKBAzs7lFtVkV8j83voAz2D8fhw==} + + '@types/react-router@5.1.20': + resolution: {integrity: sha512-jGjmu/ZqS7FjSH6owMcD5qpq19+1RS9DeVRqfl1FeBMxTDQAGwlMWOcs52NDoXaNKyG3d1cYQFMs9rCrb88o9Q==} + '@types/react@19.1.8': resolution: {integrity: sha512-AwAfQ2Wa5bCx9WP8nZL2uMZWod7J7/JSplxbTmBQ5ms6QpqNYm672H0Vu9ZVKVngQ+ii4R/byguVEUZQyeg44g==} @@ -1920,6 +1938,10 @@ packages: engines: {node: '>=16'} hasBin: true + cookie@1.0.2: + resolution: {integrity: sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==} + engines: {node: '>=18'} + cosmiconfig-typescript-loader@6.1.0: resolution: {integrity: sha512-tJ1w35ZRUiM5FeTzT7DtYWAFFv37ZLqSRkGi2oeCK1gPhvaWjkAtfXvLmvE1pRfxxp9aQo6ba/Pvg1dKj05D4g==} engines: {node: '>=v18'} @@ -3535,6 +3557,23 @@ packages: '@types/react': optional: true + react-router-dom@7.7.1: + resolution: {integrity: sha512-bavdk2BA5r3MYalGKZ01u8PGuDBloQmzpBZVhDLrOOv1N943Wq6dcM9GhB3x8b7AbqPMEezauv4PeGkAJfy7FQ==} + engines: {node: '>=20.0.0'} + peerDependencies: + react: '>=18' + react-dom: '>=18' + + react-router@7.7.1: + resolution: {integrity: sha512-jVKHXoWRIsD/qS6lvGveckwb862EekvapdHJN/cGmzw40KnJH5gg53ujOJ4qX6EKIK9LSBfFed/xiQ5yeXNrUA==} + engines: {node: '>=20.0.0'} + peerDependencies: + react: '>=18' + react-dom: '>=18' + peerDependenciesMeta: + react-dom: + optional: true + react-style-singleton@2.2.3: resolution: {integrity: sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==} engines: {node: '>=10'} @@ -3665,6 +3704,9 @@ packages: engines: {node: '>=10'} hasBin: true + set-cookie-parser@2.7.1: + resolution: {integrity: sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ==} + set-function-length@1.2.2: resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} engines: {node: '>= 0.4'} @@ -4196,6 +4238,24 @@ packages: zod@3.25.67: resolution: {integrity: sha512-idA2YXwpCdqUSKRCACDE6ItZD9TZzy3OZMtpfLoh6oPR47lipysRrJfjzMqFxQ3uJuUPyUeWe1r9vLH33xO/Qw==} + zustand@5.0.6: + resolution: {integrity: sha512-ihAqNeUVhe0MAD+X8M5UzqyZ9k3FFZLBTtqo6JLPwV53cbRB/mJwBI0PxcIgqhBBHlEs8G45OTDTMq3gNcLq3A==} + engines: {node: '>=12.20.0'} + peerDependencies: + '@types/react': '>=18.0.0' + immer: '>=9.0.6' + react: '>=18.0.0' + use-sync-external-store: '>=1.2.0' + peerDependenciesMeta: + '@types/react': + optional: true + immer: + optional: true + react: + optional: true + use-sync-external-store: + optional: true + zwitch@2.0.4: resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==} @@ -5573,6 +5633,8 @@ snapshots: dependencies: '@types/unist': 3.0.3 + '@types/history@4.7.11': {} + '@types/json-schema@7.0.15': {} '@types/json5@0.0.29': {} @@ -5602,6 +5664,17 @@ snapshots: dependencies: '@types/react': 19.1.8 + '@types/react-router-dom@5.3.3': + dependencies: + '@types/history': 4.7.11 + '@types/react': 19.1.8 + '@types/react-router': 5.1.20 + + '@types/react-router@5.1.20': + dependencies: + '@types/history': 4.7.11 + '@types/react': 19.1.8 + '@types/react@19.1.8': dependencies: csstype: 3.1.3 @@ -6053,6 +6126,8 @@ snapshots: meow: 12.1.1 split2: 4.2.0 + cookie@1.0.2: {} + cosmiconfig-typescript-loader@6.1.0(@types/node@24.0.3)(cosmiconfig@9.0.0(typescript@5.7.3))(typescript@5.7.3): dependencies: '@types/node': 24.0.3 @@ -7937,6 +8012,20 @@ snapshots: optionalDependencies: '@types/react': 19.1.8 + react-router-dom@7.7.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0): + dependencies: + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + react-router: 7.7.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + + react-router@7.7.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0): + dependencies: + cookie: 1.0.2 + react: 19.1.0 + set-cookie-parser: 2.7.1 + optionalDependencies: + react-dom: 19.1.0(react@19.1.0) + react-style-singleton@2.2.3(@types/react@19.1.8)(react@19.1.0): dependencies: get-nonce: 1.0.1 @@ -8127,6 +8216,8 @@ snapshots: semver@7.7.2: {} + set-cookie-parser@2.7.1: {} + set-function-length@1.2.2: dependencies: define-data-property: 1.1.4 @@ -8741,4 +8832,10 @@ snapshots: zod@3.25.67: {} + zustand@5.0.6(@types/react@19.1.8)(react@19.1.0)(use-sync-external-store@1.5.0(react@19.1.0)): + optionalDependencies: + '@types/react': 19.1.8 + react: 19.1.0 + use-sync-external-store: 1.5.0(react@19.1.0) + zwitch@2.0.4: {} diff --git a/src/features/kanban/components/auth/GitHubLoginButton.tsx b/src/features/kanban/components/auth/GitHubLoginButton.tsx new file mode 100644 index 0000000..841b31f --- /dev/null +++ b/src/features/kanban/components/auth/GitHubLoginButton.tsx @@ -0,0 +1,28 @@ +import { useAuthStore } from '@/stores/authStore'; + +export const GitHubLoginButton = () => { + const { loginWithGitHub, isLoading } = useAuthStore(); + + return ( + + ); +}; diff --git a/src/features/kanban/components/auth/GuestLoginButton.tsx b/src/features/kanban/components/auth/GuestLoginButton.tsx new file mode 100644 index 0000000..6b2f953 --- /dev/null +++ b/src/features/kanban/components/auth/GuestLoginButton.tsx @@ -0,0 +1,29 @@ +import { useNavigate } from 'react-router-dom'; + +import { useAuthStore } from '@/stores/authStore'; + +export const GuestLoginButton = () => { + const navigate = useNavigate(); + const { loginAsGuest } = useAuthStore(); + + const handleGuestLogin = () => { + loginAsGuest(); + navigate('/'); + }; + + return ( + + ); +}; diff --git a/src/features/kanban/components/auth/LoginPage.tsx b/src/features/kanban/components/auth/LoginPage.tsx new file mode 100644 index 0000000..3816aad --- /dev/null +++ b/src/features/kanban/components/auth/LoginPage.tsx @@ -0,0 +1,47 @@ +import { useAuth } from '../../hooks/useAuth'; +import { GitHubLoginButton } from './GitHubLoginButton'; +import { GuestLoginButton } from './GuestLoginButton'; + +export const LoginPage = () => { + const { isLoading } = useAuth(); + + if (isLoading) { + return ( +
+ 게스트로 둘러보거나 GitHub 계정으로 로그인하세요 +
+