diff --git a/.vscode/extensions.json b/.vscode/extensions.json index 06495e07..df71fc7e 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -1,4 +1,9 @@ { - "recommendations": ["astro-build.astro-vscode", "esbenp.prettier-vscode"], - "unwantedRecommendations": [] + "recommendations": [ + "astro-build.astro-vscode", + "Vue.volar" + ], + "unwantedRecommendations": [ + "esbenp.prettier-vscode" + ] } diff --git a/.vscode/settings.json b/.vscode/settings.json index ad1cf49f..63fe8c05 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,5 +1,55 @@ { "eslint.useFlatConfig": true, "editor.formatOnSave": true, - "eslint.codeActionsOnSave.mode": "all" + "eslint.codeActionsOnSave.mode": "all", + "eslint.enable": true, + "eslint.format.enable": true, + + // Disable the default formatter, use eslint instead + "prettier.enable": false, + + // Auto fix + "editor.codeActionsOnSave": { + "source.fixAll.eslint": "explicit", + "source.organizeImports": "never" + }, + + // Silent the stylistic rules in you IDE, but still auto fix them + "eslint.rules.customizations": [ + { "rule": "style/*", "severity": "off", "fixable": true }, + { "rule": "format/*", "severity": "off", "fixable": true }, + { "rule": "*-indent", "severity": "off", "fixable": true }, + { "rule": "*-spacing", "severity": "off", "fixable": true }, + { "rule": "*-spaces", "severity": "off", "fixable": true }, + { "rule": "*-order", "severity": "off", "fixable": true }, + { "rule": "*-dangle", "severity": "off", "fixable": true }, + { "rule": "*-newline", "severity": "off", "fixable": true }, + { "rule": "*quotes", "severity": "off", "fixable": true }, + { "rule": "*semi", "severity": "off", "fixable": true } + ], + + // Enable eslint for all supported languages + "eslint.validate": [ + "javascript", + "javascriptreact", + "typescript", + "typescriptreact", + "vue", + "html", + "markdown", + "json", + "jsonc", + "yaml", + "toml", + "xml", + "gql", + "graphql", + "astro", + "svelte", + "css", + "less", + "scss", + "pcss", + "postcss" + ] } \ No newline at end of file diff --git a/packages/frontendmu-nuxt/app.config.ts b/packages/frontendmu-nuxt/app.config.ts index 9a329951..d13c3b95 100644 --- a/packages/frontendmu-nuxt/app.config.ts +++ b/packages/frontendmu-nuxt/app.config.ts @@ -1,5 +1,5 @@ export default defineAppConfig({ - photoAlbumSource: - "https://raw.githubusercontent.com/Front-End-Coders-Mauritius/google-photos-sync/main/", - description: 'A community around front-end development based in Mauritius. We also organise monthly meetups free for anyone interested to attend.', -}) \ No newline at end of file + photoAlbumSource: + 'https://raw.githubusercontent.com/Front-End-Coders-Mauritius/google-photos-sync/main/', + description: 'A community around front-end development based in Mauritius. We also organise monthly meetups free for anyone interested to attend.', +}) diff --git a/packages/frontendmu-nuxt/auth-utils/useAuth.ts b/packages/frontendmu-nuxt/auth-utils/useAuth.ts index c4dc36ef..2f23313f 100644 --- a/packages/frontendmu-nuxt/auth-utils/useAuth.ts +++ b/packages/frontendmu-nuxt/auth-utils/useAuth.ts @@ -1,568 +1,561 @@ -import { ref, computed, type Ref } from "vue"; -import { getCookieValue, DIRECTUS_URL, mapToValidUser, base64Url } from '@/utils/helpers'; -import { createDirectus, rest, readMe, staticToken, authentication, updateItem, updateMe, readItems } from '@directus/sdk'; +import { type Ref, computed, ref } from 'vue' +import { authentication, createDirectus, readItems, readMe, rest, staticToken, updateItem, updateMe } from '@directus/sdk' -import type { Attendee, RSVPMetaData, RSVPResponse, SiteToast, User } from "../utils/types"; -import type { DirectusAstroUser } from './../utils/types'; -import type { AuthenticationData, DirectusClient, AuthenticationClient, RestClient } from '@directus/sdk'; +import type { AuthenticationClient, AuthenticationData, DirectusClient, RestClient } from '@directus/sdk' +import type { Attendee, RSVPMetaData, RSVPResponse, SiteToast, User } from '../utils/types' +import type { DirectusAstroUser } from './../utils/types' +import { DIRECTUS_URL, base64Url, getCookieValue, mapToValidUser } from '@/utils/helpers' const DIRECTUS_PROJECT_URL = DIRECTUS_URL() -const isAuth = ref(false); -const user = ref(null); -const rawUser = ref(null); -const responseFromServer = ref(null); -const isLoading = ref(false); -const meetupAttendees: Ref> = ref({}); +const isAuth = ref(false) +const user = ref(null) +const rawUser = ref(null) +const responseFromServer = ref(null) +const isLoading = ref(false) +const meetupAttendees: Ref> = ref({}) const toastMessage = ref({ - title: undefined, - message: undefined, - type: undefined, - visible: false, + title: undefined, + message: undefined, + type: undefined, + visible: false, }) export function getClient() { - return createDirectus(DIRECTUS_PROJECT_URL).with(authentication()).with(rest()); + return createDirectus(DIRECTUS_PROJECT_URL).with(authentication()).with(rest()) } export function useToast() { - function show(message: SiteToast) { - toastMessage.value = message - } - - function hide() { - toastMessage.value.visible = false - } - - const isVisible = computed(() => { - return toastMessage.value.visible - }) - - return { - toastMessage, - isVisible, - show, - hide - } + function show(message: SiteToast) { + toastMessage.value = message + } + + function hide() { + toastMessage.value.visible = false + } + + const isVisible = computed(() => { + return toastMessage.value.visible + }) + + return { + toastMessage, + isVisible, + show, + hide, + } } export default function useAuth(client: DirectusClient & AuthenticationClient & RestClient) { - - async function logout() { - logoutCookie() - user.value = null; - isAuth.value = false; - responseFromServer.value = null; + async function logout() { + logoutCookie() + user.value = null + isAuth.value = false + responseFromServer.value = null + } + + function handleError(error: any) { + responseFromServer.value = error + } + + function setCookie(authData: AuthenticationData) { + document.cookie = `access_token=${authData.access_token}; expires=${new Date(authData.expires_at ?? '').toUTCString()}; path=/` + } + + function setCurrentUser(data: User) { + user.value = data + } + + function logoutCookie() { + // set cookie logic + document.cookie = `access_token=; expires=${new Date().toUTCString()}; path=/` + } + + function filterAttendees(result: Attendee[]) { + return result.filter(attendee => attendee.name !== null).filter(attendee => attendee.is_public) + } + + async function loginWithUsernameAndPassword(email: string, password: string) { + try { + isLoading.value = true + const result = await client.login(email, password) + isLoading.value = false + responseFromServer.value = result + + if (result.access_token && result.expires_at) { + setCookie(result) + } + + getCurrentUser() + + setAuth(true) + + useToast().show({ + title: 'Success!', + message: 'User is logged in', + type: 'SUCCESS', + visible: true, + }) + + return result } - - function handleError(error: any) { - responseFromServer.value = error; + catch (error) { + console.log(error) } - - function setCookie(authData: AuthenticationData) { - document.cookie = `access_token=${authData.access_token}; expires=${new Date(authData.expires_at ?? '').toUTCString()}; path=/`; + } + + async function loginWithSSO() { + try { + const res = await fetch( + 'https://directus.frontend.mu/auth/refresh', + { + method: 'POST', + credentials: 'include', // this is required in order to send the refresh token cookie + body: JSON.stringify({ + refresh_token: getCookieValue('directus_session_token'), + }), + }, + ) + + const response: { data: AuthenticationData } = await res.json() + + setCookie(response.data) + await getCurrentUser() + setAuth(true) + if (!rawUser.value?.profile_picture) { + const picture = await cloudFunctionUpdateProfilePicture(rawUser.value?.id || '') + console.log(picture) + } + + return response.data } - - function setCurrentUser(data: User) { - user.value = data; + catch (error) { + console.error('Could not get access token from refresh token') + console.log(error) } + } - function logoutCookie() { - // set cookie logic - document.cookie = `access_token=; expires=${new Date().toUTCString()}; path=/`; - } + const isLoggedIn = computed(() => { + return !!isAuth.value + }) - function filterAttendees(result: Attendee[]) { - return result.filter(attendee => attendee.name !== null).filter(attendee => attendee.is_public); + function setAuth(value: boolean) { + if (value === false) { + isLoading.value = false } - async function loginWithUsernameAndPassword(email: string, password: string) { - try { - - isLoading.value = true; - const result = await client.login(email, password); - isLoading.value = false; - responseFromServer.value = result; - - if (result.access_token && result.expires_at) { - setCookie(result) - } - - getCurrentUser() - - setAuth(true) - - useToast().show({ - title: "Success!", - message: "User is logged in", - type: "SUCCESS", - visible: true - }) - - + isAuth.value = value + } - return result - - } catch (error) { - console.log(error) - } + async function checkIfLoggedIn() { + try { + await getCurrentUser() + return true } - - async function loginWithSSO() { - try { - const res = await fetch( - "https://directus.frontend.mu/auth/refresh", - { - method: "POST", - credentials: "include", // this is required in order to send the refresh token cookie - body: JSON.stringify({ - refresh_token: getCookieValue('directus_session_token'), - }), - }, - ); - - const response: { data: AuthenticationData } = await res.json(); - - setCookie(response.data); - await getCurrentUser() - setAuth(true) - if (!rawUser.value?.profile_picture) { - const picture = await cloudFunctionUpdateProfilePicture(rawUser.value?.id || '') - console.log(picture) - } - - return response.data; - } catch (error) { - console.error('Could not get access token from refresh token') - console.log(error) - } + catch (error) { + setAuth(false) + handleError(error) } - - const isLoggedIn = computed(() => { - return !!isAuth.value; - }) - - function setAuth(value: boolean) { - if (value === false) { - isLoading.value = false; - } - - isAuth.value = value; + } + + async function getCurrentUser() { + const ACCOUNT_SETTINGS_FIELDS = [ + 'id', + 'first_name', + 'last_name', + 'full_name', + 'email', + 'phone', + 'transport', + 'meal', + 'occupation', + 'github_username', + 'Events.Events_id.id', + 'Events.Events_id.title', + 'profile_picture', + 'role.name', + ] + + try { + const token = getCookieValue('access_token') + + if (!token) { + throw new Error('User is not logged in') + } + + client = await client.with(staticToken(token)) + + const result = await client.request(readMe({ + fields: ACCOUNT_SETTINGS_FIELDS, + })) + + setAuth(true) + rawUser.value = result + + setCurrentUser(mapToValidUser(result)) } - - async function checkIfLoggedIn() { - try { - await getCurrentUser() - return true - } catch (error) { - setAuth(false) - handleError(error) - } + catch (error) { + handleError(error) + throw new Error(error as string) } + } + + const currentEventsRSVP = computed(() => { + return rawUser.value?.Events?.map((event) => { + if (typeof event.Events_id === 'string') { + return { Events_id: event.Events_id } + } + return { Events_id: event.Events_id.id.toString() } + }) || [] + }) + + const avatarUrl = computed(() => { + if (rawUser.value?.profile_picture) { + return base64Url(rawUser.value.profile_picture) + } + else if (rawUser.value?.github_username) { + return `https://github.com/${rawUser.value?.github_username}.png` + } + return false + }) - async function getCurrentUser() { - - const ACCOUNT_SETTINGS_FIELDS = [ - "id", - "first_name", - "last_name", - "full_name", - "email", - "phone", - "transport", - "meal", - "occupation", - "github_username", - "Events.Events_id.id", - "Events.Events_id.title", - "profile_picture", - "role.name", - ] - - try { - - const token = getCookieValue('access_token') - - if (!token) { - throw new Error('User is not logged in') - } - - client = await client.with(staticToken(token)) + function oAuthLogin() { + const currentPage = new URL(window.location.origin) + return `${DIRECTUS_URL()}/auth/login/google?redirect=${currentPage}redirect` + } - const result = await client.request(readMe({ - fields: ACCOUNT_SETTINGS_FIELDS - })); + async function updateUserProfile({ profile_updates }: { profile_updates: DirectusAstroUser }) { + try { + isLoading.value = true + const token = getCookieValue('access_token') - setAuth(true) - rawUser.value = result; + if (!token) { + isLoading.value = false + useToast().show({ + title: 'Session expired', + message: 'Please login again.', + type: 'INFO', + visible: true, + }) + throw new Error('User is not logged in') + } - setCurrentUser(mapToValidUser(result)); + client = await client.with(staticToken(token)) - } catch (error) { - handleError(error) - throw new Error(error as string) - } + const result = await client.request(updateMe(profile_updates)) + console.log('profile updated') + await getCurrentUser() + isLoading.value = false + } + catch (error) { + console.log(error) + } + } + + async function createRsvp({ eventId, userId }: { eventId: string, userId: string }) { + const payload = { + Events: { + create: [{ directus_users_id: userId, Events_id: { id: eventId } }], + update: [], + delete: [], + }, } - const currentEventsRSVP = computed(() => { - return rawUser.value?.Events?.map((event) => { - if (typeof event.Events_id === 'string') { - return { "Events_id": event.Events_id } - } - return { "Events_id": event.Events_id.id.toString() } - }) || [] - }) - - const avatarUrl = computed(() => { - if (rawUser.value?.profile_picture) { - return base64Url(rawUser.value.profile_picture) - } else if (rawUser.value?.github_username) { - return `https://github.com/${rawUser.value?.github_username}.png` - } - return false; + // list all events from this user + const eventList = rawUser.value?.Events || [] + const eventListIds = eventList.map((event: any) => { + if (typeof event === 'object') { + return event.Events_id.id + } }) - function oAuthLogin() { - const currentPage = new URL(window.location.origin); - return `${DIRECTUS_URL()}/auth/login/google?redirect=${currentPage}redirect` + if (eventListIds.includes(Number.parseInt(eventId))) { + // console.log('Already RSVPd, skipping') } + else { + const result = await fetch(`https://directus.frontend.mu/users/me`, { + method: 'PATCH', + headers: { + 'Content-Type': 'application/json', + 'Accept': 'application/json', + 'Authorization': `Bearer ${getCookieValue('access_token')}`, + }, + body: JSON.stringify(payload), + }) + } + } - async function updateUserProfile({ profile_updates, }: { profile_updates: DirectusAstroUser, }) { - - try { - isLoading.value = true; - const token = getCookieValue('access_token') - - if (!token) { - isLoading.value = false; - useToast().show({ - title: "Session expired", - message: "Please login again.", - type: "INFO", - visible: true, - }) - throw new Error('User is not logged in') - } - - client = await client.with(staticToken(token)) + async function cancelRsvp({ currentEventId }: { currentEventId: string }) { + try { + isLoading.value = true + const token = getCookieValue('access_token') - const result = await client.request(updateMe(profile_updates)); - console.log('profile updated') + if (!token) { + isLoading.value = false + throw new Error('User is not logged in') + } - await getCurrentUser(); - isLoading.value = false; + client = await client.with(staticToken(token)) - } catch (error) { - console.log(error) - } - } + const eventIds = currentEventsRSVP.value.map(event => event.Events_id) + const updatedEvents = currentEventsRSVP.value.filter(event => event.Events_id !== currentEventId) - async function createRsvp({ eventId, userId }: { eventId: string, userId: string }) { + const data = { Events: updatedEvents } - const payload = { - "Events": { - "create": [{ "directus_users_id": userId, "Events_id": { "id": eventId } }], - "update": [], - "delete": [] - } + if (eventIds.includes(currentEventId)) { + const confirmNotAttending = confirm('You are already attending this event! Do you want to remove yourself from the list?') + if (confirmNotAttending) { + await client.request(updateMe(data)) } - - // list all events from this user - const eventList = rawUser.value?.Events || [] - const eventListIds = eventList.map((event: any) => { - if (typeof event === 'object') { - return event.Events_id.id - } - }); - - if (eventListIds.includes(parseInt(eventId))) { - // console.log('Already RSVPd, skipping') - } else { - const result = await fetch(`https://directus.frontend.mu/users/me`, { - method: "PATCH", - headers: { - "Content-Type": "application/json", - "Accept": "application/json", - "Authorization": `Bearer ${getCookieValue('access_token')}` - }, - body: JSON.stringify(payload) - }) + else { + return } + } + await getCurrentUser() + await getListOfAttendeees(currentEventId) + isLoading.value = false + console.log('rsvp cancelled') } + catch (error) { + console.log(error) + } + } + + async function getRsvp({ event_id }: { event_id: string }) { + try { + isLoading.value = true + const token = getCookieValue('access_token') + + if (!token) { + isLoading.value = false + throw new Error('User is not logged in') + } + + client = await client.with(staticToken(token)) + await getCurrentUser() + + const query_object = { + filter: { + Events_id: { + _eq: event_id, + }, + directus_users_id: { + _eq: user.value?.id, + }, + }, + fields: [ + 'name', + 'transport', + 'meal', + 'occupation', + 'is_public', + 'verified', + ], + } + + // @ts-expect-error Becauseitems is not typed + const result = await client.request(readItems('Events_directus_users', query_object)) + return result + } + catch (error) { + console.log(error) + } + } + + async function updateRsvp({ event_id, rsvp_updates }: { event_id: string, rsvp_updates: RSVPMetaData }) { + try { + isLoading.value = true + const token = getCookieValue('access_token') + + if (!token) { + isLoading.value = false + throw new Error('User is not logged in') + } + + client = await client.with(staticToken(token)) + + const query_object = { + filter: { + Events_id: { + _eq: event_id, + }, + directus_users_id: { + _eq: user.value?.id, + }, + }, + } + + // @ts-expect-error Becauseitems is not typed + const primaryKeyQuery = await client.request(readItems('Events_directus_users', query_object)) + + const updates = { + meta: rsvp_updates.meta, + meal: rsvp_updates.meal, + transport: rsvp_updates.transport, + occupation: rsvp_updates.occupation, + is_public: rsvp_updates.is_public, + name: rsvp_updates.name, + profile_picture: rsvp_updates.profile_picture, + } + + const primaryKey = primaryKeyQuery[0].id + + const updateMetaResult = await client.request(updateItem('Events_directus_users', primaryKey, updates)) + + console.log('rsvp updated') + + await getListOfAttendeees(event_id) + await getCurrentUser() + + isLoading.value = false + } + catch (error) { + console.log(error) + } + } - async function cancelRsvp({ currentEventId }: { currentEventId: string }) { - try { - isLoading.value = true; - const token = getCookieValue('access_token') - - if (!token) { - isLoading.value = false; - throw new Error('User is not logged in') - } - - client = await client.with(staticToken(token)) + async function cloudFunctionUpdateProfilePicture(userId: string) { + const FUNCTION_AUTH_PICTURE_URL = `https://auth-picture.frontend.mu/` - const eventIds = currentEventsRSVP.value.map(event => event.Events_id); - const updatedEvents = currentEventsRSVP.value.filter(event => event.Events_id !== currentEventId); + const result = await fetch(FUNCTION_AUTH_PICTURE_URL, { + method: 'POST', + headers: { + 'user-id': userId, + 'access-token': getCookieValue('access_token'), + }, + }) - const data = { Events: updatedEvents } + console.log(result) - if (eventIds.includes(currentEventId)) { - const confirmNotAttending = confirm('You are already attending this event! Do you want to remove yourself from the list?'); - if (confirmNotAttending) { - await client.request(updateMe(data)); - } else { - return; - } - } + useToast().show({ + title: 'Success!', + message: 'Profile picture synced successfully', + type: 'SUCCESS', + visible: true, + }) + } - await getCurrentUser(); - await getListOfAttendeees(currentEventId); - isLoading.value = false; + async function getListOfAttendeees(currentEventId: string) { + const token = getCookieValue('access_token') - console.log('rsvp cancelled') - } catch (error) { - console.log(error) - } + if (!token) { + isLoading.value = false + throw new Error('User is not logged in') } - async function getRsvp({ event_id }: { event_id: string }) { - try { - isLoading.value = true; - const token = getCookieValue('access_token') - - if (!token) { - isLoading.value = false; - throw new Error('User is not logged in') - } - - client = await client.with(staticToken(token)) - await getCurrentUser(); - - const query_object = { - filter: { - Events_id: { - _eq: event_id - }, - directus_users_id: { - _eq: user.value?.id - } - }, - fields: [ - "name", - "transport", - "meal", - "occupation", - "is_public", - "verified", - ] - } - - // @ts-expect-error Becauseitems is not typed - const result = await client.request(readItems('Events_directus_users', query_object)); - return result - - } catch (error) { - console.log(error) - } + client = await client.with(staticToken(token)) + + const query_object = { + filter: { + Events_id: { + _eq: currentEventId, + }, + }, + fields: [ + '*', + ], } - async function updateRsvp({ event_id, rsvp_updates }: { event_id: string, rsvp_updates: RSVPMetaData }) { - try { - isLoading.value = true; - const token = getCookieValue('access_token') - - if (!token) { - isLoading.value = false; - throw new Error('User is not logged in') - } - - client = await client.with(staticToken(token)) - - const query_object = { - filter: { - Events_id: { - _eq: event_id - }, - directus_users_id: { - _eq: user.value?.id - } - } - } - - // @ts-expect-error Becauseitems is not typed - const primaryKeyQuery = await client.request(readItems('Events_directus_users', query_object)); - - const updates = { - meta: rsvp_updates.meta, - meal: rsvp_updates.meal, - transport: rsvp_updates.transport, - occupation: rsvp_updates.occupation, - is_public: rsvp_updates.is_public, - name: rsvp_updates.name, - profile_picture: rsvp_updates.profile_picture - } - - const primaryKey = primaryKeyQuery[0].id - - const updateMetaResult = await client.request(updateItem('Events_directus_users', primaryKey, updates)); - - console.log('rsvp updated') - - await getListOfAttendeees(event_id); - await getCurrentUser(); - - isLoading.value = false; - } catch (error) { - console.log(error) - } + try { + // @ts-expect-error Becauseitems is not typed + const result = await client.request(readItems('Events_directus_users', query_object)) + const attendees = filterAttendees(result) + meetupAttendees.value[currentEventId] = attendees + return attendees + } + catch (err) { + console.log(err) + throw new Error(err as string) } + } - async function cloudFunctionUpdateProfilePicture(userId: string) { + async function updateUserVerification({ user_id, event_id, status }: { user_id: string, event_id: string, status: boolean }) { + try { + isLoading.value = true + const token = getCookieValue('access_token') - const FUNCTION_AUTH_PICTURE_URL = `https://auth-picture.frontend.mu/` + if (!token) { + isLoading.value = false + throw new Error('User is not logged in') + } - const result = await fetch(FUNCTION_AUTH_PICTURE_URL, { - method: 'POST', - headers: { - 'user-id': userId, - 'access-token': getCookieValue('access_token') - }, - }); + client = await client.with(staticToken(token)) - console.log(result); + const query_object = { + filter: { + Events_id: { + _eq: event_id, + }, + directus_users_id: { + _eq: user_id, + }, + }, + } - useToast().show({ - title: "Success!", - message: "Profile picture synced successfully", - type: "SUCCESS", - visible: true - }) + // @ts-expect-error Becauseitems is not typed + const primaryKeyQuery = await client.request(readItems('Events_directus_users', query_object)) + const updates = { + verified: status, + } - } + const primaryKey = primaryKeyQuery[0].id - async function getListOfAttendeees(currentEventId: string) { + const updateMetaResult = await client.request(updateItem('Events_directus_users', primaryKey, updates)) - const token = getCookieValue('access_token') + useToast().show({ + title: 'Success!', + message: 'User verified successfully', + type: 'SUCCESS', + visible: true, + }) - if (!token) { - isLoading.value = false; - throw new Error('User is not logged in') - } + // await getListOfAttendeees(event_id); + // await getCurrentUser(); - client = await client.with(staticToken(token)) - - const query_object = { - filter: { - Events_id: { - _eq: currentEventId - }, - }, - fields: [ - "*", - ] - } - - try { - // @ts-expect-error Becauseitems is not typed - const result = await client.request(readItems('Events_directus_users', query_object)); - const attendees = filterAttendees(result); - meetupAttendees.value[currentEventId] = attendees - return attendees - } catch (err) { - console.log(err) - throw new Error(err as string) - } + isLoading.value = false + return updateMetaResult } - - async function updateUserVerification({ user_id, event_id, status }: { user_id: string, event_id: string, status: boolean }) { - try { - isLoading.value = true; - const token = getCookieValue('access_token') - - if (!token) { - isLoading.value = false; - throw new Error('User is not logged in') - } - - client = await client.with(staticToken(token)) - - const query_object = { - filter: { - Events_id: { - _eq: event_id - }, - directus_users_id: { - _eq: user_id - } - } - } - - // @ts-expect-error Becauseitems is not typed - const primaryKeyQuery = await client.request(readItems('Events_directus_users', query_object)); - - const updates = { - verified: status, - } - - const primaryKey = primaryKeyQuery[0].id - - const updateMetaResult = await client.request(updateItem('Events_directus_users', primaryKey, updates)); - - useToast().show({ - title: "Success!", - message: "User verified successfully", - type: "SUCCESS", - visible: true - }) - - // await getListOfAttendeees(event_id); - // await getCurrentUser(); - - isLoading.value = false; - - return updateMetaResult - } catch (error) { - useToast().show({ - title: "Oops!", - message: "Failed to verify the user!", - type: "ERROR", - visible: true - }) - - return new Error("You don't have permission for this action") - } - } - - return { - cloudFunctionUpdateProfilePicture, - loginWithUsernameAndPassword, - logout, - isLoggedIn, - getCurrentUser, - checkIfLoggedIn, - rawUser, - user, - responseFromServer, - client, - loginWithSSO, - oAuthLogin, - createRsvp, - updateRsvp, - getRsvp, - updateUserProfile, - cancelRsvp, - getListOfAttendeees, - updateUserVerification, - currentEventsRSVP, - isLoading, - avatarUrl, - meetupAttendees, + catch (error) { + useToast().show({ + title: 'Oops!', + message: 'Failed to verify the user!', + type: 'ERROR', + visible: true, + }) + + return new Error('You don\'t have permission for this action') } + } + + return { + cloudFunctionUpdateProfilePicture, + loginWithUsernameAndPassword, + logout, + isLoggedIn, + getCurrentUser, + checkIfLoggedIn, + rawUser, + user, + responseFromServer, + client, + loginWithSSO, + oAuthLogin, + createRsvp, + updateRsvp, + getRsvp, + updateUserProfile, + cancelRsvp, + getListOfAttendeees, + updateUserVerification, + currentEventsRSVP, + isLoading, + avatarUrl, + meetupAttendees, + } } diff --git a/packages/frontendmu-nuxt/auth-utils/useAuthRedirect.ts b/packages/frontendmu-nuxt/auth-utils/useAuthRedirect.ts index 4ef210dc..991a7705 100644 --- a/packages/frontendmu-nuxt/auth-utils/useAuthRedirect.ts +++ b/packages/frontendmu-nuxt/auth-utils/useAuthRedirect.ts @@ -1,49 +1,48 @@ -import { computed, ref } from 'vue'; +import { computed, ref } from 'vue' + export default function useAuthRedirect() { - const duration = ref(2500); - const countdown = ref(duration.value); - const willRedirect = ref(false); - const countDownPercentage = computed(() => { - return (((duration.value - countdown.value) / duration.value) * 100) + '%'; - }); + const duration = ref(2500) + const countdown = ref(duration.value) + const willRedirect = ref(false) + const countDownPercentage = computed(() => { + return `${((duration.value - countdown.value) / duration.value) * 100}%` + }) - function setUrl() { - const url = window.location.href; - // Store in session storage - sessionStorage.setItem('redirectUrl', url); - } + function setUrl() { + const url = window.location.href + // Store in session storage + sessionStorage.setItem('redirectUrl', url) + } - function tryRedirect() { - const redirectUrl = sessionStorage.getItem('redirectUrl'); - sessionStorage.removeItem('redirectUrl'); - if (redirectUrl) { - willRedirect.value = true; - // start the countdown - setTimeout(() => { - window.location.href = redirectUrl; - } , duration.value); - - const intervalDelay = 10; - // start the countdown such that the progress bar is updated every 100ms and and the countdown reaches 0 in duration ms - const interval = setInterval(() => { - countdown.value -= intervalDelay; - if (countdown.value <= 0) { - clearInterval(interval); - } - }, intervalDelay); - - + function tryRedirect() { + const redirectUrl = sessionStorage.getItem('redirectUrl') + sessionStorage.removeItem('redirectUrl') + if (redirectUrl) { + willRedirect.value = true + // start the countdown + setTimeout(() => { + window.location.href = redirectUrl + }, duration.value) - return true; + const intervalDelay = 10 + // start the countdown such that the progress bar is updated every 100ms and and the countdown reaches 0 in duration ms + const interval = setInterval(() => { + countdown.value -= intervalDelay + if (countdown.value <= 0) { + clearInterval(interval) } - } + }, intervalDelay) - return { - setUrl, - tryRedirect, - countdown, - duration, - countDownPercentage, - willRedirect + return true } -} \ No newline at end of file + } + + return { + setUrl, + tryRedirect, + countdown, + duration, + countDownPercentage, + willRedirect, + } +} diff --git a/packages/frontendmu-nuxt/components.json b/packages/frontendmu-nuxt/components.json index 7791978b..2432d4fd 100644 --- a/packages/frontendmu-nuxt/components.json +++ b/packages/frontendmu-nuxt/components.json @@ -14,4 +14,4 @@ "components": "@/components", "utils": "@/lib/utils" } -} \ No newline at end of file +} diff --git a/packages/frontendmu-nuxt/components/ContentBlock.vue b/packages/frontendmu-nuxt/components/ContentBlock.vue index fa2e0afc..fd064376 100644 --- a/packages/frontendmu-nuxt/components/ContentBlock.vue +++ b/packages/frontendmu-nuxt/components/ContentBlock.vue @@ -1,20 +1,17 @@ - diff --git a/packages/frontendmu-nuxt/components/LayoutBackdrop.vue b/packages/frontendmu-nuxt/components/LayoutBackdrop.vue index cbca1679..736304ea 100644 --- a/packages/frontendmu-nuxt/components/LayoutBackdrop.vue +++ b/packages/frontendmu-nuxt/components/LayoutBackdrop.vue @@ -1,11 +1,11 @@ \ No newline at end of file + diff --git a/packages/frontendmu-nuxt/components/OgImage/BlogPost.vue b/packages/frontendmu-nuxt/components/OgImage/BlogPost.vue index 64fb3340..93093e06 100644 --- a/packages/frontendmu-nuxt/components/OgImage/BlogPost.vue +++ b/packages/frontendmu-nuxt/components/OgImage/BlogPost.vue @@ -19,4 +19,4 @@ withDefaults(defineProps<{ - \ No newline at end of file + diff --git a/packages/frontendmu-nuxt/components/OgImage/Event.vue b/packages/frontendmu-nuxt/components/OgImage/Event.vue index 64044c4d..d41fe25b 100644 --- a/packages/frontendmu-nuxt/components/OgImage/Event.vue +++ b/packages/frontendmu-nuxt/components/OgImage/Event.vue @@ -5,12 +5,11 @@ withDefaults(defineProps<{ }>(), { title: 'Meetup', }) - \ No newline at end of file + > + {{ title }} + + + diff --git a/packages/frontendmu-nuxt/components/OgImage/Generic.vue b/packages/frontendmu-nuxt/components/OgImage/Generic.vue index 55b8a69c..34484126 100644 --- a/packages/frontendmu-nuxt/components/OgImage/Generic.vue +++ b/packages/frontendmu-nuxt/components/OgImage/Generic.vue @@ -5,12 +5,11 @@ withDefaults(defineProps<{ }>(), { title: 'frontend.mu', }) - \ No newline at end of file + > + {{ title }} + + + diff --git a/packages/frontendmu-nuxt/components/OgImage/Home.vue b/packages/frontendmu-nuxt/components/OgImage/Home.vue index 1aa826e0..1d111d86 100644 --- a/packages/frontendmu-nuxt/components/OgImage/Home.vue +++ b/packages/frontendmu-nuxt/components/OgImage/Home.vue @@ -1,124 +1,125 @@ diff --git a/packages/frontendmu-nuxt/components/OgImage/Speaker.vue b/packages/frontendmu-nuxt/components/OgImage/Speaker.vue index ed302294..06b14a50 100644 --- a/packages/frontendmu-nuxt/components/OgImage/Speaker.vue +++ b/packages/frontendmu-nuxt/components/OgImage/Speaker.vue @@ -1,18 +1,17 @@ diff --git a/packages/frontendmu-nuxt/components/auth/AdminVerifyAttendee.vue b/packages/frontendmu-nuxt/components/auth/AdminVerifyAttendee.vue index bc0274ea..bcf5d480 100644 --- a/packages/frontendmu-nuxt/components/auth/AdminVerifyAttendee.vue +++ b/packages/frontendmu-nuxt/components/auth/AdminVerifyAttendee.vue @@ -1,30 +1,32 @@ \ No newline at end of file + + diff --git a/packages/frontendmu-nuxt/components/auth/AttendeeQRCode.vue b/packages/frontendmu-nuxt/components/auth/AttendeeQRCode.vue index 17eea04f..307315e2 100644 --- a/packages/frontendmu-nuxt/components/auth/AttendeeQRCode.vue +++ b/packages/frontendmu-nuxt/components/auth/AttendeeQRCode.vue @@ -1,10 +1,10 @@ - \ No newline at end of file + diff --git a/packages/frontendmu-nuxt/components/auth/Bran.vue b/packages/frontendmu-nuxt/components/auth/Bran.vue index 8b690c72..c606f94b 100644 --- a/packages/frontendmu-nuxt/components/auth/Bran.vue +++ b/packages/frontendmu-nuxt/components/auth/Bran.vue @@ -1,22 +1,25 @@ + + - - \ No newline at end of file diff --git a/packages/frontendmu-nuxt/components/auth/FormLabel.vue b/packages/frontendmu-nuxt/components/auth/FormLabel.vue index b50aa3b3..9c10df17 100644 --- a/packages/frontendmu-nuxt/components/auth/FormLabel.vue +++ b/packages/frontendmu-nuxt/components/auth/FormLabel.vue @@ -1,23 +1,23 @@ \ No newline at end of file + + + diff --git a/packages/frontendmu-nuxt/components/auth/FormRadio.vue b/packages/frontendmu-nuxt/components/auth/FormRadio.vue index 9786e066..fd9edd25 100644 --- a/packages/frontendmu-nuxt/components/auth/FormRadio.vue +++ b/packages/frontendmu-nuxt/components/auth/FormRadio.vue @@ -1,40 +1,39 @@ diff --git a/packages/frontendmu-nuxt/components/auth/OrganiserQRCodeScanner.vue b/packages/frontendmu-nuxt/components/auth/OrganiserQRCodeScanner.vue index 9edd2a77..53ad8430 100644 --- a/packages/frontendmu-nuxt/components/auth/OrganiserQRCodeScanner.vue +++ b/packages/frontendmu-nuxt/components/auth/OrganiserQRCodeScanner.vue @@ -1,20 +1,20 @@ @@ -67,14 +67,19 @@ async function verifyUser() {
-
Success !
+ v-if="verifiedUserData?.profile_picture" class="block w-[50vw] aspect-square" + :src="base64Url(verifiedUserData?.profile_picture)" alt="" + > +
+ Success ! +
{{ verifiedUserData?.name }} has been verified
- Verify another user + + Verify another user +
diff --git a/packages/frontendmu-nuxt/components/auth/RefreshToken.vue b/packages/frontendmu-nuxt/components/auth/RefreshToken.vue index 317883ec..49564ac6 100644 --- a/packages/frontendmu-nuxt/components/auth/RefreshToken.vue +++ b/packages/frontendmu-nuxt/components/auth/RefreshToken.vue @@ -1,45 +1,47 @@ diff --git a/packages/frontendmu-nuxt/components/auth/RsvpAttendeeList.vue b/packages/frontendmu-nuxt/components/auth/RsvpAttendeeList.vue index 4b93abac..90093488 100644 --- a/packages/frontendmu-nuxt/components/auth/RsvpAttendeeList.vue +++ b/packages/frontendmu-nuxt/components/auth/RsvpAttendeeList.vue @@ -1,17 +1,10 @@ diff --git a/packages/frontendmu-nuxt/components/auth/RsvpToMeetup.vue b/packages/frontendmu-nuxt/components/auth/RsvpToMeetup.vue index e87073e4..64f5a578 100644 --- a/packages/frontendmu-nuxt/components/auth/RsvpToMeetup.vue +++ b/packages/frontendmu-nuxt/components/auth/RsvpToMeetup.vue @@ -1,241 +1,240 @@ - + + + + + +
+
+
- -
- - - -
-
+ + +
+ + + +
+
+ \ No newline at end of file + diff --git a/packages/frontendmu-nuxt/components/auth/SideInfo.vue b/packages/frontendmu-nuxt/components/auth/SideInfo.vue index 6283aceb..1b916df0 100644 --- a/packages/frontendmu-nuxt/components/auth/SideInfo.vue +++ b/packages/frontendmu-nuxt/components/auth/SideInfo.vue @@ -3,12 +3,12 @@ defineProps<{ title: string }>() diff --git a/packages/frontendmu-nuxt/components/auth/ToastMessage.vue b/packages/frontendmu-nuxt/components/auth/ToastMessage.vue index 1a38fab0..4bb53a33 100644 --- a/packages/frontendmu-nuxt/components/auth/ToastMessage.vue +++ b/packages/frontendmu-nuxt/components/auth/ToastMessage.vue @@ -1,52 +1,52 @@ + \ No newline at end of file + diff --git a/packages/frontendmu-nuxt/components/auth/constants.ts b/packages/frontendmu-nuxt/components/auth/constants.ts index ed45ff7c..e8126b1d 100644 --- a/packages/frontendmu-nuxt/components/auth/constants.ts +++ b/packages/frontendmu-nuxt/components/auth/constants.ts @@ -1,51 +1,51 @@ -import { Icon } from '#components' import type { RendererElement } from 'vue' +import { Icon } from '#components' -import type { Meal, Occupation, Transport } from "@/utils/types"; +import type { Meal, Occupation, Transport } from '@/utils/types' -const IconChicken = h(Icon, { name: 'icon-park-twotone:chicken'}) -const IconVegan = h(Icon, { name: 'iconoir:vegan'}) -const IconBus = h(Icon, { name: 'mdi:bus-side'}) -const IconCar = h(Icon, { name: 'mdi:car-side'}) -const IconBroom = h(Icon, { name: 'game-icons:magic-broom'}) -const IconRide = h(Icon, { name: 'ic:round-thumb-up-off-alt'}) -const IconNoFood = h(Icon, { name: 'radix-icons:component-none'}) +const IconChicken = h(Icon, { name: 'icon-park-twotone:chicken' }) +const IconVegan = h(Icon, { name: 'iconoir:vegan' }) +const IconBus = h(Icon, { name: 'mdi:bus-side' }) +const IconCar = h(Icon, { name: 'mdi:car-side' }) +const IconBroom = h(Icon, { name: 'game-icons:magic-broom' }) +const IconRide = h(Icon, { name: 'ic:round-thumb-up-off-alt' }) +const IconNoFood = h(Icon, { name: 'radix-icons:component-none' }) -const IconPhone = h(Icon, { name: 'material-symbols:phone-android-outline-rounded'}) -const IconEmail = h(Icon, { name: 'material-symbols:mail-outline-rounded'}) -const IconPublic = h(Icon, { name: 'material-symbols:public'}) +const IconPhone = h(Icon, { name: 'material-symbols:phone-android-outline-rounded' }) +const IconEmail = h(Icon, { name: 'material-symbols:mail-outline-rounded' }) +const IconPublic = h(Icon, { name: 'material-symbols:public' }) -const IconDeveloper = h(Icon, { name: 'ic:round-code'}) -const IconStudent = h(Icon, { name: 'ph:student'}) -const IconManager = h(Icon, { name: 'material-symbols:person-celebrate-rounded'}) -const IconDesigner = h(Icon, { name: 'ph:paint-brush-duotone'}) -const IconHr = h(Icon, { name: 'mdi:briefcase-account'}) -const IconEntrepreneur = h(Icon, { name: 'mdi:head-cog-outline'}) +const IconDeveloper = h(Icon, { name: 'ic:round-code' }) +const IconStudent = h(Icon, { name: 'ph:student' }) +const IconManager = h(Icon, { name: 'material-symbols:person-celebrate-rounded' }) +const IconDesigner = h(Icon, { name: 'ph:paint-brush-duotone' }) +const IconHr = h(Icon, { name: 'mdi:briefcase-account' }) +const IconEntrepreneur = h(Icon, { name: 'mdi:head-cog-outline' }) export const foodOptions = [ - { value: "none", name: "None", icon: IconNoFood }, - { value: "veg", name: "Veg", icon: IconVegan }, - { value: "non_veg", name: "Non/Veg", icon: IconChicken }, -] as { value: Meal, name: string, icon: RendererElement }[]; + { value: 'none', name: 'None', icon: IconNoFood }, + { value: 'veg', name: 'Veg', icon: IconVegan }, + { value: 'non_veg', name: 'Non/Veg', icon: IconChicken }, +] as { value: Meal, name: string, icon: RendererElement }[] export const professionOptions = [ - { value: "developer", name: "Developer", icon: IconDeveloper }, - { value: "student", name: "Student", icon: IconStudent }, - { value: "manager", name: "Manager", icon: IconManager }, - { value: "designer", name: "Designer", icon: IconDesigner }, - { value: "hr", name: "Hr", icon: IconHr }, - { value: "entrepreneur", name: "Entrepreneur", icon: IconEntrepreneur }, - { value: "other", name: "Other", icon: IconHr }, -] as { value: Occupation, name: string, icon: RendererElement }[]; + { value: 'developer', name: 'Developer', icon: IconDeveloper }, + { value: 'student', name: 'Student', icon: IconStudent }, + { value: 'manager', name: 'Manager', icon: IconManager }, + { value: 'designer', name: 'Designer', icon: IconDesigner }, + { value: 'hr', name: 'Hr', icon: IconHr }, + { value: 'entrepreneur', name: 'Entrepreneur', icon: IconEntrepreneur }, + { value: 'other', name: 'Other', icon: IconHr }, +] as { value: Occupation, name: string, icon: RendererElement }[] export const showMeAsAttendingOptions = [ - { value: "true", name: "Public", icon: IconPublic }, - { value: "false", name: "Hide", icon: IconNoFood }, -]; + { value: 'true', name: 'Public', icon: IconPublic }, + { value: 'false', name: 'Hide', icon: IconNoFood }, +] export const transportOptions = [ - { value: "bus", name: "Bus", icon: IconBus }, - { value: "car", name: "Car", icon: IconCar }, - { value: "need_a_ride", name: "Need a ride", icon: IconRide }, - { value: "other", name: "Other", icon: IconBroom }, -] as { value: Transport, name: string, icon: RendererElement }[]; \ No newline at end of file + { value: 'bus', name: 'Bus', icon: IconBus }, + { value: 'car', name: 'Car', icon: IconCar }, + { value: 'need_a_ride', name: 'Need a ride', icon: IconRide }, + { value: 'other', name: 'Other', icon: IconBroom }, +] as { value: Transport, name: string, icon: RendererElement }[] diff --git a/packages/frontendmu-nuxt/components/base/Button.vue b/packages/frontendmu-nuxt/components/base/Button.vue index adbfb537..5891365a 100644 --- a/packages/frontendmu-nuxt/components/base/Button.vue +++ b/packages/frontendmu-nuxt/components/base/Button.vue @@ -1,46 +1,44 @@ \ No newline at end of file + + + + + + + + diff --git a/packages/frontendmu-nuxt/components/base/Card.vue b/packages/frontendmu-nuxt/components/base/Card.vue index 390e4fdf..ed6371bb 100644 --- a/packages/frontendmu-nuxt/components/base/Card.vue +++ b/packages/frontendmu-nuxt/components/base/Card.vue @@ -3,8 +3,9 @@ \ No newline at end of file +
+ +
+ diff --git a/packages/frontendmu-nuxt/components/base/Heading.vue b/packages/frontendmu-nuxt/components/base/Heading.vue index d24d7b87..0435fe47 100644 --- a/packages/frontendmu-nuxt/components/base/Heading.vue +++ b/packages/frontendmu-nuxt/components/base/Heading.vue @@ -1,7 +1,7 @@ diff --git a/packages/frontendmu-nuxt/components/cards/BrandingCard.vue b/packages/frontendmu-nuxt/components/cards/BrandingCard.vue index 7708a969..e7f17f1c 100644 --- a/packages/frontendmu-nuxt/components/cards/BrandingCard.vue +++ b/packages/frontendmu-nuxt/components/cards/BrandingCard.vue @@ -1,13 +1,40 @@ + + - - diff --git a/packages/frontendmu-nuxt/components/cards/CardAlbum.vue b/packages/frontendmu-nuxt/components/cards/CardAlbum.vue index fd88e002..f6c58b82 100644 --- a/packages/frontendmu-nuxt/components/cards/CardAlbum.vue +++ b/packages/frontendmu-nuxt/components/cards/CardAlbum.vue @@ -1,13 +1,14 @@ + + - - diff --git a/packages/frontendmu-nuxt/components/cards/EventCard.vue b/packages/frontendmu-nuxt/components/cards/EventCard.vue index ff5626a6..144d8a73 100644 --- a/packages/frontendmu-nuxt/components/cards/EventCard.vue +++ b/packages/frontendmu-nuxt/components/cards/EventCard.vue @@ -1,36 +1,86 @@ + + - - diff --git a/packages/frontendmu-nuxt/components/cards/EventTilt.vue b/packages/frontendmu-nuxt/components/cards/EventTilt.vue index 765d2b39..f5e560a3 100644 --- a/packages/frontendmu-nuxt/components/cards/EventTilt.vue +++ b/packages/frontendmu-nuxt/components/cards/EventTilt.vue @@ -1,26 +1,28 @@ - - - \ No newline at end of file + diff --git a/packages/frontendmu-nuxt/components/site/Menu.vue b/packages/frontendmu-nuxt/components/site/Menu.vue index a27a3758..5dcd6e06 100644 --- a/packages/frontendmu-nuxt/components/site/Menu.vue +++ b/packages/frontendmu-nuxt/components/site/Menu.vue @@ -1,18 +1,19 @@ diff --git a/packages/frontendmu-nuxt/pages/admin/verify.vue b/packages/frontendmu-nuxt/pages/admin/verify.vue index 46cc5c10..b20b489b 100644 --- a/packages/frontendmu-nuxt/pages/admin/verify.vue +++ b/packages/frontendmu-nuxt/pages/admin/verify.vue @@ -1,9 +1,9 @@ - - + + diff --git a/packages/frontendmu-nuxt/pages/branding.vue b/packages/frontendmu-nuxt/pages/branding.vue index fdd9d2df..9a8c658d 100644 --- a/packages/frontendmu-nuxt/pages/branding.vue +++ b/packages/frontendmu-nuxt/pages/branding.vue @@ -1,35 +1,6 @@ - - + + \ No newline at end of file + diff --git a/packages/frontendmu-nuxt/pages/redirect.vue b/packages/frontendmu-nuxt/pages/redirect.vue index 091d7311..35f3a121 100644 --- a/packages/frontendmu-nuxt/pages/redirect.vue +++ b/packages/frontendmu-nuxt/pages/redirect.vue @@ -2,7 +2,6 @@ -