Appwrite auth

This commit is contained in:
ATUL GUNJAL 2025-04-21 08:50:19 +05:30
commit 24a979b364
16 changed files with 13157 additions and 0 deletions

24
frontend/.gitignore vendored Normal file
View File

@ -0,0 +1,24 @@
# Nuxt dev/build outputs
.output
.data
.nuxt
.nitro
.cache
dist
# Node dependencies
node_modules
# Logs
logs
*.log
# Misc
.DS_Store
.fleet
.idea
# Local env files
.env
.env.*
!.env.example

75
frontend/README.md Normal file
View File

@ -0,0 +1,75 @@
# Nuxt Minimal Starter
Look at the [Nuxt documentation](https://nuxt.com/docs/getting-started/introduction) to learn more.
## Setup
Make sure to install dependencies:
```bash
# npm
npm install
# pnpm
pnpm install
# yarn
yarn install
# bun
bun install
```
## Development Server
Start the development server on `http://localhost:3000`:
```bash
# npm
npm run dev
# pnpm
pnpm dev
# yarn
yarn dev
# bun
bun run dev
```
## Production
Build the application for production:
```bash
# npm
npm run build
# pnpm
pnpm build
# yarn
yarn build
# bun
bun run build
```
Locally preview production build:
```bash
# npm
npm run preview
# pnpm
pnpm preview
# yarn
yarn preview
# bun
bun run preview
```
Check out the [deployment documentation](https://nuxt.com/docs/getting-started/deployment) for more information.

30
frontend/app.vue Normal file
View File

@ -0,0 +1,30 @@
<template>
<div class="flex min-h-screen bg-gray-100 text-gray-900">
<!-- Sidebar and Navbar only for authenticated & non-public routes -->
<Sidebar v-if="!isPublicPage" />
<div v-if="!isPublicPage" class="flex flex-col flex-1 ml-64">
<Navbar />
<main class="p-6">
<NuxtPage />
</main>
</div>
<!-- Auth pages like SignIn or SignUp show full page -->
<div v-else class="w-full">
<NuxtPage />
</div>
</div>
</template>
<script setup>
import { useRoute } from 'vue-router'
import { computed } from 'vue'
import Sidebar from '~/app/components/Sidebar.vue'
import Navbar from '~/app/components/Navbar.vue'
const route = useRoute()
const publicRoutes = ['/', '/SignIn', '/SignUp'] // Add more if needed
const isPublicPage = computed(() => publicRoutes.includes(route.path))
</script>

View File

@ -0,0 +1 @@
@import "tailwindcss";

View File

@ -0,0 +1,35 @@
<template>
<header class="bg-white shadow p-4 flex justify-between items-center">
<h2 class="text-xl font-semibold">Welcome, Atul</h2>
<div class="flex items-center space-x-4">
<span class="text-gray-700">🔔 Notifications</span>
<span class="text-gray-700">👤 Profile</span>
<button @click="logout" class="bg-red-600 text-white px-4 py-2 rounded-md hover:bg-red-400">
Logout
</button>
</div>
</header>
</template>
<script setup>
import { useRouter } from 'vue-router'
import { Client, Account } from 'appwrite'
// Appwrite client setup
const client = new Client()
client.setEndpoint('https://cloud.appwrite.io/v1').setProject('67e1445400053dca1d9b')
const account = new Account(client)
// Router
const router = useRouter()
// Logout function
const logout = async () => {
try {
await account.deleteSession('current')
router.push('/') // Redirect to index.vue
} catch (error) {
console.error('Logout failed:', error.message)
}
}
</script>

View File

@ -0,0 +1,16 @@
<template>
<aside class="w-64 h-screen fixed bg-gray-900 text-white">
<div class="p-4 text-xl font-bold border-b border-gray-700">
🎓 StudentMS
</div>
<nav class="flex flex-col p-4 space-y-2">
<NuxtLink to="/" class="p-2 rounded hover:bg-gray-800">Dashboard</NuxtLink>
<NuxtLink to="/students" class="p-2 rounded hover:bg-gray-800">Students</NuxtLink>
<NuxtLink to="/about" class="p-2 rounded hover:bg-gray-800">About</NuxtLink>
</nav>
<div class="p-4 border-t border-gray-700 text-sm mt-auto">
&copy; 2025 Atul Gunjal
</div>
</aside>
</template>

11
frontend/nuxt.config.ts Normal file
View File

@ -0,0 +1,11 @@
import tailwindcss from "@tailwindcss/vite";
export default defineNuxtConfig({
compatibilityDate: "2024-11-01",
devtools: { enabled: true },
css: ['~/app/assets/style.css'],
vite: {
plugins: [
tailwindcss(),
],
},
});

12689
frontend/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

22
frontend/package.json Normal file
View File

@ -0,0 +1,22 @@
{
"name": "nuxt-app",
"private": true,
"type": "module",
"scripts": {
"build": "nuxt build",
"dev": "nuxt dev",
"generate": "nuxt generate",
"preview": "nuxt preview",
"postinstall": "nuxt prepare"
},
"dependencies": {
"@nuxtjs/auth-next": "^5.0.0-1667386184.dfbbb54",
"@tailwindcss/vite": "^4.1.4",
"appwrite": "^17.0.2",
"chart.js": "^4.4.9",
"nuxt": "^3.16.2",
"tailwindcss": "^4.1.4",
"vue": "^3.5.13",
"vue-router": "^4.5.0"
}
}

View File

@ -0,0 +1,34 @@
<template>
<div class="min-h-screen bg-gray-100 p-6">
<h1 class="text-3xl font-bold text-gray-800 mb-6">Welcome to Your Dashboard</h1>
<div class="flex flex-wrap gap-6">
<!-- Card 1 -->
<div class="flex-1 min-w-[250px] bg-white p-6 rounded-2xl shadow hover:shadow-md transition">
<h2 class="text-xl font-semibold text-gray-700 mb-2">Profile</h2>
<p class="text-gray-500">View and edit your profile info.</p>
</div>
<!-- Card 2 -->
<div class="flex-1 min-w-[250px] bg-white p-6 rounded-2xl shadow hover:shadow-md transition">
<h2 class="text-xl font-semibold text-gray-700 mb-2">Notifications</h2>
<p class="text-gray-500">Check latest alerts and messages.</p>
</div>
<!-- Card 3 -->
<div class="flex-1 min-w-[250px] bg-white p-6 rounded-2xl shadow hover:shadow-md transition">
<h2 class="text-xl font-semibold text-gray-700 mb-2">Settings</h2>
<p class="text-gray-500">Manage account preferences.</p>
</div>
<!-- Card 4 -->
<div class="flex-1 min-w-[250px] bg-white p-6 rounded-2xl shadow hover:shadow-md transition">
<h2 class="text-xl font-semibold text-gray-700 mb-2">Analytics</h2>
<p class="text-gray-500">Track your app usage stats.</p>
</div>
</div>
</div>
</template>

118
frontend/pages/SignIn.vue Normal file
View File

@ -0,0 +1,118 @@
<template>
<div class="min-h-screen flex items-center justify-center bg-gray-100">
<div class="w-full max-w-md bg-white p-8 rounded-2xl shadow-xl">
<h1 class="text-2xl font-bold text-center mb-6">Login to Your Account</h1>
<form @submit.prevent="loginWithEmail" class="space-y-4">
<input
v-model="email"
type="email"
placeholder="Email"
class="w-full px-4 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
required
/>
<input
v-model="password"
type="password"
placeholder="Password"
class="w-full px-4 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
required
/>
<button
type="submit"
:disabled="loading"
class="w-full bg-blue-600 text-white py-2 rounded-md hover:bg-blue-700 transition disabled:opacity-50"
>
{{ loading ? 'Logging in...' : 'Login with Email' }}
</button>
</form>
<div class="mt-6 border-t pt-4">
<p class="text-center text-gray-500 mb-4">or login with</p>
<div class="space-y-3">
<button
@click="loginWithOAuth('google')"
class="w-full flex items-center justify-center bg-red-500 text-white py-2 rounded-md hover:bg-red-600 transition"
>
Google
</button>
<button
@click="loginWithOAuth('github')"
class="w-full flex items-center justify-center bg-gray-800 text-white py-2 rounded-md hover:bg-gray-900 transition"
>
GitHub
</button>
<button
@click="loginWithOAuth('facebook')"
class="w-full flex items-center justify-center bg-blue-700 text-white py-2 rounded-md hover:bg-blue-800 transition"
>
Facebook
</button>
</div>
</div>
</div>
</div>
</template>
<script setup>
import { ref } from 'vue'
import { useRouter } from 'vue-router'
import { Client, Account } from 'appwrite'
const router = useRouter()
const email = ref('')
const password = ref('')
const loading = ref(false)
// Appwrite config
const client = new Client()
client
.setEndpoint('https://cloud.appwrite.io/v1') // Fixed typo (removed double https)
.setProject('67e1445400053dca1d9b') // Replace with your real project ID
const account = new Account(client)
// Login handler
const loginWithEmail = async () => {
loading.value = true
try {
const session = await account.createEmailPasswordSession(email.value, password.value)
console.log('Session:', session)
alert('Login successful!')
router.push('/Dashboard') // route to Dashboard
} catch (error) {
console.error('Login Error:', error.message)
alert(error.message || 'Login failed. Please try again.')
} finally {
loading.value = false
}
}
// ----------------if user already logged in-------------
onMounted(async () => {
try {
const session = await account.getSession('current') // Check if session exists
if (session) {
router.push('/Dashboard') // Redirect to Dashboard if session exists
}
} catch (error) {
console.log('No active session found.')
}
})
// ----------------------------------------------------------
// OAuth login
const loginWithOAuth = async (provider) => {
try {
account.createOAuth2Session(
provider,
'http://localhost:3000/Dashboard', // success redirect
'http://localhost:3000/SignIn' // failure redirect
)
} catch (error) {
console.error(`OAuth login failed: ${error.message}`)
alert('OAuth login failed.')
}
}
</script>

93
frontend/pages/index.vue Normal file
View File

@ -0,0 +1,93 @@
<template>
<div class="min-h-screen flex items-center justify-center bg-gray-100">
<div class="w-full max-w-md bg-white p-8 rounded-2xl shadow-xl">
<h1 class="text-2xl font-bold text-center mb-6">Create Your Account</h1>
<form @submit.prevent="signUpWithEmail" class="space-y-4">
<input
v-model="name"
type="text"
placeholder="Name"
class="w-full px-4 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
required
/>
<input
v-model="email"
type="email"
placeholder="Email"
class="w-full px-4 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
required
/>
<input
v-model="password"
type="password"
placeholder="Password"
class="w-full px-4 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
required
/>
<button
type="submit"
class="w-full bg-green-600 text-white py-2 rounded-md hover:bg-green-700 transition"
>
Sign Up
</button>
</form>
<div class="mt-6 border-t pt-4">
<p class="text-center text-gray-500 mb-4">or sign up with</p>
<div class="space-y-3">
<button
@click="signUpWithOAuth('github')"
class="w-full flex items-center justify-center bg-gray-800 text-white py-2 rounded-md hover:bg-gray-900 transition"
>
GitHub
</button>
<button
@click="signUpWithOAuth('facebook')"
class="w-full flex items-center justify-center bg-blue-700 text-white py-2 rounded-md hover:bg-blue-800 transition"
>
Facebook
</button>
</div>
</div>
<p class="text-center mt-6 text-gray-500">
Already have an account?
<NuxtLink to="SignIn" class="text-blue-600 hover:underline">Login</NuxtLink>
</p>
</div>
</div>
</template>
<script setup>
import { ref } from 'vue'
import { Client, Account, ID } from 'appwrite'
const client = new Client()
client.setEndpoint('https://cloud.appwrite.io/v1').setProject('67e1445400053dca1d9b')
const account = new Account(client)
const name = ref('')
const email = ref('')
const password = ref('')
const signUpWithEmail = async () => {
try {
await account.create(ID.unique(), email.value, password.value, name.value)
alert('Account created successfully! Redirecting to login...')
navigateTo('/SignIn')
} catch (error) {
alert('Signup failed: ' + error.message)
}
}
const signUpWithOAuth = (provider) => {
account.createOAuth2Session(
provider,
'http://localhost:3000', // success redirect
'http://localhost:3000/SignUp' // failure redirect (back to signup)
)
}
</script>

BIN
frontend/public/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

View File

@ -0,0 +1,2 @@
User-Agent: *
Disallow:

View File

@ -0,0 +1,3 @@
{
"extends": "../.nuxt/tsconfig.server.json"
}

4
frontend/tsconfig.json Normal file
View File

@ -0,0 +1,4 @@
{
// https://nuxt.com/docs/guide/concepts/typescript
"extends": "./.nuxt/tsconfig.json"
}