Skip to content
Snippets Groups Projects
Commit af24b234 authored by Nallani, Abhishikth (UG - Comp Sci & Elec Eng)'s avatar Nallani, Abhishikth (UG - Comp Sci & Elec Eng)
Browse files

Merge branch 'top-rated' into 'movie-details'

Profile view implemented, watchlist view and component implemented with a...

See merge request !1
parents b16f2665 f845e43b
No related branches found
No related tags found
1 merge request!1Profile view implemented, watchlist view and component implemented with a...
VITE_TMDB_API_KEY=42259df77843511296d8096fa29e08a8
VITE_TMDB_BASE=https://api.themoviedb.org/3
<script setup>
import { ref, onMounted, watch } from 'vue'
import addToWatchlist from '@/views/Watchlist.vue'
const year = ref(2000)
const genre = ref('')
......@@ -58,6 +59,7 @@ watch([year, genre], async () => {
/>
<p class="title">{{ movie.title }}</p>
<p class="rating">{{ movie.vote_average }}</p>
<button @click="addToWatchlist(movie)">Add to Watchlist</button>
</div>
</div>
</template>
......
<template>
<div class="watchlist">
<h1>Your Watchlist</h1>
<div class="filters">
<select v-model="filter">
<option value="">All</option>
<option value="planned">Plan To Watch</option>
<option value="watched">Watched</option>
</select>
</div>
<div class="movie-grid">
<div
v-for="movie in filteredWatchlist"
:key="movie.id"
class="movie-card"
>
<img :src="'https://image.tmdb.org/t/p/w342' + movie.poster_path" alt="poster" />
<p class="title">{{ movie.title }}</p>
<p class="rating">{{ movie.vote_average }}</p>
<p class="status">📌 {{ movie.status }}</p>
</div>
</div>
</div>
</template>
<script setup>
import { ref, computed, onMounted } from 'vue'
import { getFirestore, collection, getDocs } from 'firebase/firestore'
import { getAuth } from 'firebase/auth'
const db = getFirestore()
const auth = getAuth()
const watchlist = ref([])
const filter = ref('')
const fetchWatchlist = async () => {
const user = auth.currentUser
if (!user) return
const snapshot = await getDocs(collection(db, 'users', user.uid, 'watchlist'))
watchlist.value = snapshot.docs.map(doc => ({ id: doc.id, ...doc.data() }))
}
const filteredWatchlist = computed(() => {
if (!filter.value) return watchlist.value
return watchlist.value.filter(movie => movie.status === filter.value)
})
onMounted(() => {
fetchWatchlist()
})
</script>
<style scoped>
/* Reuse your styles or tweak as needed */
.watchlist {
padding: 2rem;
text-align: center;
}
.filters {
margin-bottom: 1rem;
}
.movie-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
gap: 1.2rem;
}
</style>
\ No newline at end of file
......@@ -103,4 +103,4 @@ onMounted(fetchPopular)
margin: 1rem 0;
font-weight: bold;
}
</style>
\ No newline at end of file
</style>
<template>Profile</template>
\ No newline at end of file
<template>
<div class="flex items-center justify-center min-h-screen bg-gray-100 dark:bg-neutral-900">
<div class="mt-7 bg-white border border-gray-200 rounded-xl shadow-2xs dark:bg-neutral-900 dark:border-neutral-700 min-w-96">
<div class="p-4 sm:p-7">
<div class="text-center">
<h1 class="block text-2xl font-bold text-gray-800 dark:text-white">Profile</h1>
<p class="mt-2 text-sm text-gray-600 dark:text-neutral-400">
Manage your account information
</p>
</div>
<div class="mt-5">
<form @submit.prevent="updateProfile">
<div class="grid gap-y-4">
<div>
<label class="block text-sm mb-2 dark:text-white">Email</label>
<input type="email" :value="userEmail" disabled class="w-full border border-gray-400 rounded-lg p-2 bg-gray-100 dark:bg-neutral-800 dark:text-white" />
</div>
<div>
<label class="block text-sm mb-2 dark:text-white">Display Name</label>
<input type="text" v-model="displayName" class="w-full border border-gray-400 rounded-lg p-2 dark:text-white" required />
</div>
<div>
<label class="block text-sm mb-2 dark:text-white">New Password</label>
<input type="password" v-model="newPassword" class="w-full border border-gray-400 rounded-lg p-2 dark:text-white" />
<p v-if="newPassword && passwordError" class="text-red-500 text-sm mt-1">{{ passwordError }}</p>
</div>
<button
type="submit"
:disabled="loading || !!passwordError"
class="w-full py-3 bg-blue-600 text-white rounded-lg flex justify-center items-center gap-2 hover:bg-blue-700 transition duration-300 disabled:opacity-50 disabled:pointer-events-none"
>
<span v-if="!loading">Update Profile</span>
<span v-else>Saving...</span>
</button>
</div>
</form>
</div>
</div>
</div>
</div>
</template>
<script setup>
import { ref, computed, onMounted } from 'vue';
import { getAuth, updateProfile, updatePassword } from 'firebase/auth';
const auth = getAuth();
const user = auth.currentUser;
const loading = ref(false);
const userEmail = ref('');
const displayName = ref('');
const newPassword = ref('');
// Load current profile info
onMounted(() => {
if (user) {
userEmail.value = user.email;
displayName.value = user.displayName || '';
}
});
// Password validation
const passwordError = computed(() => {
if (!newPassword.value) return '';
if (newPassword.value.length < 8) return "Password must be at least 8 characters.";
if (!/[A-Z]/.test(newPassword.value)) return "Must include at least 1 uppercase letter.";
if (!/[0-9]/.test(newPassword.value)) return "Must include at least 1 number.";
if (!/[@$!%*?&]/.test(newPassword.value)) return "Must include at least 1 special character (@$!%*?&).";
return '';
});
// Update function
const updateProfile = async () => {
if (passwordError.value) return;
loading.value = true;
try {
if (user) {
// Update display name
await updateProfile(user, {
displayName: displayName.value,
});
// Update password if provided
if (newPassword.value) {
await updatePassword(user, newPassword.value);
}
alert('Profile updated successfully!');
}
} catch (error) {
alert(error.message);
} finally {
loading.value = false;
}
};
</script>
\ No newline at end of file
<template>Watchlist</template>
\ No newline at end of file
<template>
<Watchlist />
</template>
<script setup>
import Watchlist from '@/components/Watchlist.vue'
import { getFirestore, doc, setDoc } from 'firebase/firestore'
import { getAuth } from 'firebase/auth'
const addToWatchlist = async (movie) => {
const user = getAuth().currentUser
if (!user) return alert('You need to log in.')
const db = getFirestore()
const movieRef = doc(db, 'users', user.uid, 'watchlist', String(movie.id))
await setDoc(movieRef, {
title: movie.title,
poster_path: movie.poster_path,
vote_average: movie.vote_average,
status: 'planned'
})
alert('Movie added to watchlist!')
}
</script>
\ No newline at end of file
......@@ -15,4 +15,4 @@ export default defineConfig({
},
},
})
\ No newline at end of file
})
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment