add oauth and create suggestion

This commit is contained in:
2023-12-09 23:03:04 +01:00
parent 4a3ff6c7ac
commit ff2d5ae7a8
9 changed files with 143 additions and 35 deletions

4
src/auth.d.ts vendored
View File

@@ -1,7 +1,9 @@
declare module '#auth-utils' {
interface UserSession {
user: {
username: string
email: string,
username: string,
picture: string
}
}
}

View File

@@ -16,5 +16,6 @@ const getColor = computed(() => appConfig.ui.primary)
<NuxtPage />
<Footer />
</main>
<UNotifications />
</div>
</template>

View File

@@ -1,31 +1,9 @@
<script lang="ts" setup>
import { providers } from '~~/types'
useHead({
title: 'Sign my guestbook • Arthur Danjou',
})
const providers = [
{
slug: 'github',
label: 'Use Github',
icon: 'i-ph-github-logo-bold',
link: '/api/auth/github',
color: 'black',
},
{
slug: 'twitter',
label: 'Use Twitter',
icon: 'i-ph-twitter-logo-bold',
link: '/api/auth/twitter',
color: 'cyan',
},
{
slug: 'google',
label: 'Use Google',
icon: 'i-ph-google-logo-bold',
link: '/api/auth/google',
color: 'red',
},
]
</script>
<template>

View File

@@ -1,12 +1,14 @@
<script lang="ts" setup>
import { useTalentsStore } from '~/store/talents'
import { providers } from '~~/types'
useHead({
title: 'Discover new talents • Arthur Danjou',
})
const categories = ref<Array<{ label: string; slug: string }>>([{ label: 'All', slug: 'all' }])
const categories = ref<Array<{ label: string, slug: string }>>([{ label: 'All', slug: 'all' }])
const { getCategory, setCategory, isFavorite, toggleFavorite } = useTalentsStore()
const { loggedIn, clear } = useUserSession()
const {
data: talents,
@@ -17,7 +19,7 @@ const {
favorite: isFavorite,
category: getCategory,
},
watch: [isFavorite, getCategory]
watch: [isFavorite, getCategory],
})
function isCategory(category: string) {
@@ -28,12 +30,38 @@ const {
data: getCategories,
} = await useFetch('/api/categories', { method: 'GET' })
getCategories.value?.forEach(category => categories.value.push({ label: category.name, slug: category.slug }))
getCategories.value?.forEach((category: any) => categories.value.push({ label: category.name, slug: category.slug }))
const appConfig = useAppConfig()
function getColor() {
return `text-${appConfig.ui.primary}-500`
}
const toast = useToast()
const suggestContent = ref<string>('')
async function suggest() {
if (suggestContent.value.trim().length < 4)
return
await $fetch('/api/suggestion', {
method: 'post',
body: {
content: suggestContent.value,
},
}).then((suggestion) => {
toast.add({
title: `Your suggestion for '${suggestion.content}'' has been successfully added`,
icon: 'i-material-symbols-check-circle-outline-rounded',
timeout: 4000,
})
}).catch(() => {
toast.add({
title: 'You already have suggested someone',
color: 'red',
})
})
suggestContent.value = ''
}
</script>
<template>
@@ -59,16 +87,49 @@ function getColor() {
Are you a web talent? Do you want to promote your project? Do you want to launch your career or gain visibility?
</p>
</div>
<NuxtLink href="mailto:arthurdanjou@outlook.fr?subject=Join your talents' list">
<UButton label="Join the talent's list" color="primary" />
</NuxtLink>
<div v-if="loggedIn" class="flex items-center justify-between gap-4">
<div class="w-full relative flex items-center">
<input
v-model="suggestContent"
type="text"
required
min="4"
class="w-full rounded-lg p-2 h-10 focus:outline-none bg-gray-100 dark:bg-stone-800"
placeholder="Suggest one name"
>
<UButton
class="absolute right-1 top-1 text-gray-900 dark:text-white rounded-md"
label="Send"
:disabled="suggestContent.trim().length < 4"
variant="soft"
@click.prevent="suggest()"
/>
</div>
<UButton
@click.prevent="clear()"
>
Logout
</UButton>
</div>
<div v-else class="flex gap-2">
<UButton
v-for="provider in providers"
:key="provider.slug"
:label="provider.label"
:color="provider.color"
variant="solid"
:icon="provider.icon"
:to="provider.link"
external
/>
</div>
</div>
<div v-if="getCategories" class="flex gap-2 w-full items-center justify-between pb-2 border-b border-zinc-100 dark:border-zinc-700/40 mb-4">
<div class="flex gap-2 overflow-x-scroll sm:overflow-x-hidden bg-gray-100 dark:bg-gray-800 rounded-lg p-1 relative">
<div
v-for="category in categories"
:key="category.slug"
class="relative px-3 py-1 text-sm font-medium rounded-md h-8 text-gray-500 dark:text-gray-400 min-w-fit flex items-center justify-center w-full focus:outline-none disabled:cursor-not-allowed disabled:opacity-75 transition-colors duration-200 ease-out cursor-pointer hover:bg-gray-200 dark:hover:bg-gray-700 hover:text-black dark:hover:text-white"
class="relative px-3 py-1 text-sm font-medium rounded-md h-8 text-gray-500 dark:text-gray-400 min-w-fit flex items-center justify-center w-full focus:outline-none transition-colors duration-200 ease-out cursor-pointer hover:bg-gray-200 dark:hover:bg-gray-700 hover:text-black dark:hover:text-white"
:class="{ 'text-gray-900 dark:text-white relative !bg-white dark:!bg-stone-900 rounded-md shadow-sm': isCategory(category.slug) }"
@click.prevent="setCategory(category.slug)"
>

View File

@@ -1,11 +1,22 @@
import { z } from 'zod'
const SuggestionValidator = z.object({
author: z.string().trim(),
content: z.string(),
}).parse
export default defineEventHandler(async (event) => {
const { author, content } = await getValidatedQuery(event, SuggestionValidator)
const { content } = await readValidatedBody(event, SuggestionValidator)
const { user } = await requireUserSession(event)
return await usePrisma().suggestion.upsert({
where: {
author: user.email,
},
update: {
content,
},
create: {
author: user.email,
content,
},
})
})

View File

@@ -28,7 +28,7 @@ export default defineEventHandler(async (event) => {
return await prisma.talent.findMany({
where: whereClause,
orderBy: {
createdAt: 'desc',
name: 'asc',
},
include: {
categories: {

View File

@@ -0,0 +1,18 @@
export default oauth.githubEventHandler({
config: {
emailRequired: true,
},
async onSuccess(event: any, { user }: any) {
await setUserSession(event, {
user: {
email: user.email,
picture: user.avatar_url,
username: String(user.name).trim(),
},
})
return sendRedirect(event, '/')
},
onError(error: any) {
console.error('GitHub OAuth error:', error)
},
})

View File

@@ -0,0 +1,12 @@
export default oauth.githubEventHandler({
async onSuccess(event: any, { user }: any) {
await setUserSession(event, {
user: {
email: user.email,
picture: user.photoUrl,
username: String(user.displayName).trim(),
},
})
return sendRedirect(event, '/')
},
})

View File

@@ -1,3 +1,4 @@
import exp from 'node:constants'
import type { MarkdownParsedContent, ParsedContent } from '@nuxt/content/dist/runtime/types'
export enum ColorsTheme {
@@ -69,3 +70,27 @@ export interface Skill extends ParsedContent {
}
color: string
}
export const providers = [
{
slug: 'github',
label: 'Use Github',
icon: 'i-ph-github-logo-bold',
link: '/auth/github',
color: 'black',
},
/* {
slug: 'twitter',
label: 'Use Twitter',
icon: 'i-ph-twitter-logo-bold',
link: '/auth/twitter',
color: 'cyan',
}, */
{
slug: 'google',
label: 'Use Google',
icon: 'i-ph-google-logo-bold',
link: '/auth/google',
color: 'red',
},
]