Merge pull request 'added auth support' (#1) from add-auth-handling into main

Reviewed-on: tiradoe/movie-night-web-nuxt#1
This commit is contained in:
Edward Tirado Jr 2026-02-24 06:26:15 +00:00
commit 890df1ee51
7 changed files with 112 additions and 3 deletions

View file

@ -0,0 +1,31 @@
<script lang="ts" setup>
const email = ref("");
const password = ref("");
const {login} = useAuth();
const handleLogin = () => login(email.value, password.value)
</script>
<template>
<form class="password-form" @submit.prevent="handleLogin">
<div class="form-group">
<label for="email">Email</label>
<input id="email" v-model="email" type="email"/>
</div>
<div class="form-group">
<label for="password">Password</label>
<input id="password" v-model="password" type="password"/>
</div>
<button type="submit">Submit</button>
</form>
</template>
<style scoped>
.form-group {
display: flex;
flex-direction: column;
gap: 1rem;
}
</style>

View file

@ -2,11 +2,13 @@
const dropdownOpen = ref(false) const dropdownOpen = ref(false)
const profileMenu = ref<HTMLElement | null>(null) const profileMenu = ref<HTMLElement | null>(null)
function toggleDropdown() { const {logout} = useAuth()
const toggleDropdown = () => {
dropdownOpen.value = !dropdownOpen.value dropdownOpen.value = !dropdownOpen.value
} }
function onClickOutside(e: MouseEvent) { const onClickOutside = (e: MouseEvent) => {
if (profileMenu.value && !profileMenu.value.contains(e.target as Node)) { if (profileMenu.value && !profileMenu.value.contains(e.target as Node)) {
dropdownOpen.value = false dropdownOpen.value = false
} }
@ -26,7 +28,7 @@ onUnmounted(() => document.removeEventListener('click', onClickOutside))
<li> <li>
<NuxtLink to="/account" @click="dropdownOpen = false">Account</NuxtLink> <NuxtLink to="/account" @click="dropdownOpen = false">Account</NuxtLink>
</li> </li>
<li>Log Out</li> <li @click="logout">Log Out</li>
</ul> </ul>
</div> </div>
</template> </template>

17
app/composables/$api.ts Normal file
View file

@ -0,0 +1,17 @@
export const $api = <T>(
path: string,
options: Parameters<typeof $fetch<T>>[1] = {}
) => {
const config = useRuntimeConfig()
const xsrfToken = useCookie('XSRF-TOKEN')
return $fetch<T>(path, {
baseURL: config.public.apiBase,
credentials: 'include',
headers: {
Accept: 'application/json',
...(xsrfToken.value ? {'X-XSRF-TOKEN': xsrfToken.value} : {}),
},
...options,
})
}

View file

@ -0,0 +1,21 @@
export const useApiData = <T>(
url: string | Ref<string>,
options: Parameters<typeof useFetch<T>>[1] = {}
) => {
const config = useRuntimeConfig()
const xsrfToken = useCookie('XSRF-TOKEN')
const requestHeaders = useRequestHeaders(['cookie'])
return useFetch<T>(url, {
baseURL: config.public.apiBase,
credentials: 'include',
watch: false,
server: false,
headers: computed(() => ({
Accept: 'application/json',
...requestHeaders,
...(xsrfToken.value ? {'X-XSRF-TOKEN': xsrfToken.value} : {}),
})),
...options,
})
}

View file

@ -0,0 +1,20 @@
export const useAuth = () => {
const config = useRuntimeConfig()
const router = useRouter()
const login = async (email: string, password: string) => {
await $fetch('/sanctum/csrf-cookie', {
baseURL: config.public.apiBase,
credentials: 'include',
})
await $api('/api/login', {method: 'POST', body: {email, password}})
await router.push('/')
}
const logout = async () => {
await $api('/api/logout', {method: 'POST'})
await router.push('/')
}
return {login, logout}
}

13
app/pages/auth/login.vue Normal file
View file

@ -0,0 +1,13 @@
<script lang="ts" setup>
import LoginForm from "~/components/forms/auth/login-form.vue";
</script>
<template>
<login-form/>
</template>
<style scoped>
</style>

View file

@ -1,6 +1,11 @@
// https://nuxt.com/docs/api/configuration/nuxt-config // https://nuxt.com/docs/api/configuration/nuxt-config
export default defineNuxtConfig({ export default defineNuxtConfig({
compatibilityDate: '2025-07-15', compatibilityDate: '2025-07-15',
runtimeConfig: {
public: {
apiBase: '', // overridden by NUXT_PUBLIC_API_BASE
},
},
devtools: {enabled: true}, devtools: {enabled: true},
css: ['~/assets/css/reset.css'], css: ['~/assets/css/reset.css'],
modules: [ modules: [