use h3 instead of trpc

This commit is contained in:
2023-12-09 21:26:41 +01:00
parent f0aa9ebdf4
commit ba067cf533
25 changed files with 1395 additions and 940 deletions

View File

@@ -1,24 +1,19 @@
export default defineNuxtConfig({ export default defineNuxtConfig({
srcDir: 'src', srcDir: 'src',
build: {
transpile: ['trpc-nuxt'],
},
css: [ css: [
'@/assets/css/main.scss', '@/assets/css/main.scss',
], ],
modules: [ modules: [
'@nuxt/ui',
'nuxt-auth-utils',
'@nuxt/image', '@nuxt/image',
'@nuxthq/studio', '@nuxthq/studio',
'@nuxt/content', '@nuxt/content',
'@nuxt/ui',
'@pinia/nuxt', '@pinia/nuxt',
'@pinia-plugin-persistedstate/nuxt', '@pinia-plugin-persistedstate/nuxt',
'@nuxt/devtools',
'@vueuse/nuxt', '@vueuse/nuxt',
'nuxt-icon',
], ],
colorMode: { colorMode: {

View File

@@ -13,38 +13,32 @@
}, },
"dependencies": { "dependencies": {
"@nuxt/content": "2.9.0", "@nuxt/content": "2.9.0",
"@nuxt/image": "1.0.0", "@nuxt/image": "1.1.0",
"@nuxt/ui": "^2.10.0", "@nuxt/ui": "2.11.0",
"@pinia/nuxt": "0.5.1", "@pinia/nuxt": "0.5.1",
"@prisma/client": "^5.6.0", "@prisma/client": "5.7.0",
"@tresjs/nuxt": "^1.2.2",
"@trpc/client": "10.43.3",
"@trpc/server": "10.43.3",
"@vercel/analytics": "1.1.1", "@vercel/analytics": "1.1.1",
"@vueuse/motion": "2.0.0", "@vueuse/motion": "2.0.0",
"pinia": "2.1.7", "pinia": "2.1.7",
"postcss-custom-properties": "13.3.2", "postcss-custom-properties": "13.3.2",
"sass": "1.69.5", "sass": "1.69.5",
"superjson": "2.2.1", "superjson": "2.2.1",
"tailwindcss": "3.3.5", "tailwindcss": "3.3.6",
"three": "^0.158.0", "zod": "^3.22.4"
"trpc-nuxt": "0.10.12",
"zod": "3.22.4"
}, },
"devDependencies": { "devDependencies": {
"@antfu/eslint-config": "1.1.0", "@antfu/eslint-config": "2.4.2",
"@iconify/json": "2.2.140", "@iconify/json": "2.2.153",
"@nuxt/devtools": "1.0.1", "@nuxthq/studio": "1.0.5",
"@nuxthq/studio": "1.0.3",
"@pinia-plugin-persistedstate/nuxt": "1.2.0", "@pinia-plugin-persistedstate/nuxt": "1.2.0",
"@tailwindcss/typography": "^0.5.10", "@tailwindcss/typography": "^0.5.10",
"@types/node": "20.9.0", "@types/node": "20.10.4",
"@vueuse/core": "10.6.0", "@vueuse/core": "10.7.0",
"@vueuse/nuxt": "10.6.0", "@vueuse/nuxt": "10.7.0",
"eslint": "8.53.0", "eslint": "8.55.0",
"nuxt": "3.8.1", "nuxt": "3.8.2",
"nuxt-icon": "0.5.0", "nuxt-auth-utils": "^0.0.10",
"prisma": "^5.6.0", "prisma": "5.7.0",
"typescript": "5.2.2" "typescript": "5.3.3"
} }
} }

View File

@@ -29,8 +29,6 @@ model Category {
createdAt DateTime @default(now()) createdAt DateTime @default(now())
slug String slug String
name String name String
type CategoryType
bookmarks CategoriesOnBookMarks[]
talents CategoriesOnTalents[] talents CategoriesOnTalents[]
} }
@@ -56,26 +54,6 @@ model CategoriesOnTalents {
@@index([categoryId]) @@index([categoryId])
} }
model BookMark {
id Int @id @default(autoincrement())
createdAd DateTime @default(now())
name String
description String
link String
CategoriesOnBookMarks CategoriesOnBookMarks[]
}
model CategoriesOnBookMarks {
bookmarkId Int
categoryId Int
bookmark BookMark @relation(fields: [bookmarkId], references: [id])
category Category @relation(fields: [categoryId], references: [id])
@@id([bookmarkId, categoryId])
@@index([bookmarkId])
@@index([categoryId])
}
model Post { model Post {
id Int @id @default(autoincrement()) id Int @id @default(autoincrement())
slug String @unique slug String @unique
@@ -84,6 +62,14 @@ model Post {
likes Int @default(0) likes Int @default(0)
} }
model Suggestion {
id Int @id @default(autoincrement())
author String @unique
content String
added Boolean @default(false)
createdAt DateTime @default(now())
}
model Form { model Form {
id Int @id @default(autoincrement()) id Int @id @default(autoincrement())
name String name String
@@ -91,8 +77,3 @@ model Form {
content String content String
createdAt DateTime @default(now()) createdAt DateTime @default(now())
} }
enum CategoryType {
TALENT
BOOKMARK
}

View File

@@ -1,6 +1,5 @@
<script lang="ts" setup> <script lang="ts" setup>
const { $trpc } = useNuxtApp() const { data: announce } = await useFetch('/api/announcement')
const announce = await $trpc.announcement.get.query()
const appConfig = useAppConfig() const appConfig = useAppConfig()
function getColor() { function getColor() {

View File

@@ -1,24 +1,15 @@
<script setup lang="ts">
defineProps({
navigation: {
type: Boolean,
default: true,
},
})
</script>
<template> <template>
<header class="z-30 sticky top-0 left-0 flex justify-center w-full"> <header class="z-30 sticky top-0 left-0 flex justify-center w-full">
<div class="w-full px-4 sm:px-6 lg:px-8 sm:mx-8 max-w-7xl py-4 flex justify-between bg-white dark:bg-zinc-900 border-b border-zinc-100 dark:border-zinc-300/10"> <div class="w-full px-4 sm:px-6 lg:px-8 sm:mx-8 max-w-7xl py-4 flex justify-between items-center bg-white dark:bg-zinc-900 border-b border-zinc-100 dark:border-zinc-300/10">
<ClientOnly> <ClientOnly>
<Logo /> <Logo />
<NavBar v-if="navigation" /> <NavBar />
<div class="flex gap-2"> <div class="flex gap-2 items-center">
<div class="flex items-center rounded-md p-1 gap-1 relative bg-black/5 text-sm font-medium text-zinc-700 dark:bg-zinc-800/90 dark:text-zinc-300"> <div class="flex items-center rounded-md p-1 gap-1 relative bg-black/5 text-sm font-medium text-zinc-700 dark:bg-zinc-800/90 dark:text-zinc-300">
<ColorPicker /> <ColorPicker />
<ColorModeButton /> <ColorModeButton />
</div> </div>
<MobileNavBar v-if="navigation" /> <MobileNavBar />
</div> </div>
</ClientOnly> </ClientOnly>
</div> </div>

View File

@@ -54,7 +54,7 @@ function isRoute(path: string) {
</script> </script>
<template> <template>
<div class="md:hidden"> <div class="lg:hidden">
<div class="p-1 rounded-md bg-black/5 text-sm font-medium text-zinc-700 dark:bg-zinc-800/90 dark:text-zinc-300"> <div class="p-1 rounded-md bg-black/5 text-sm font-medium text-zinc-700 dark:bg-zinc-800/90 dark:text-zinc-300">
<UButton <UButton
variant="ghost" variant="ghost"
@@ -69,7 +69,7 @@ function isRoute(path: string) {
<UCard class="flex flex-col flex-1" :ui="{ body: { base: 'flex-1' }, ring: '', divide: 'divide-y divide-gray-100 dark:divide-gray-800' }"> <UCard class="flex flex-col flex-1" :ui="{ body: { base: 'flex-1' }, ring: '', divide: 'divide-y divide-gray-100 dark:divide-gray-800' }">
<template #header> <template #header>
<div class="flex justify-between items-center"> <div class="flex justify-between items-center">
<div>Logo</div> <Logo />
<UButton <UButton
size="md" size="md"
icon="i-ic-round-close" icon="i-ic-round-close"

View File

@@ -6,15 +6,15 @@ const items = [
to: '/talents', to: '/talents',
icon: 'i-ph-users-bold', icon: 'i-ph-users-bold',
}, { }, {
label: 'Bookmarks', label: 'Guestbook',
to: '/bookmarks', to: '/guestbook',
icon: 'i-ph-bookmark-simple-bold', icon: 'i-material-symbols-book-2-outline',
}], }],
] ]
</script> </script>
<template> <template>
<nav class="hidden md:block z-50"> <nav class="hidden lg:block z-50">
<div class="flex items-center h-10 rounded-md p-1 gap-1 relative bg-black/5 text-sm font-medium text-zinc-700 dark:bg-zinc-800/90 dark:text-zinc-300"> <div class="flex items-center h-10 rounded-md p-1 gap-1 relative bg-black/5 text-sm font-medium text-zinc-700 dark:bg-zinc-800/90 dark:text-zinc-300">
<UButton to="/" size="sm" variant="ghost" color="white" :class="{ 'link-active': route.path === '/' }"> <UButton to="/" size="sm" variant="ghost" color="white" :class="{ 'link-active': route.path === '/' }">
Home Home

View File

@@ -15,8 +15,8 @@ const isLight = computed(() => $colorMode.value === 'light')
class="flex items-center gap-2 rounded-md px-2 py-3 duration-300 md:hover:bg-gray-100 md:dark:hover:bg-neutral-800" class="flex items-center gap-2 rounded-md px-2 py-3 duration-300 md:hover:bg-gray-100 md:dark:hover:bg-neutral-800"
> >
<div class="flex items-center"> <div class="flex items-center">
<Icon v-if="isLight" :name="skill.icon.light ? skill.icon.light : skill.icon" size="20" /> <UIcon v-if="isLight" :name="skill.icon.light ? skill.icon.light : skill.icon" size="20" dynamic />
<Icon v-else :name="skill.icon.dark ? skill.icon.dark : skill.icon" size="20" /> <UIcon v-else :name="skill.icon.dark ? skill.icon.dark : skill.icon" size="20" dynamic />
</div> </div>
<span class="text-sm text-subtitle">{{ skill.name }}</span> <span class="text-sm text-subtitle">{{ skill.name }}</span>
</li> </li>

View File

@@ -1,23 +1,24 @@
export async function usePost(slug: string) { export async function usePost(slug: string) {
const { $trpc } = useNuxtApp()
const { const {
data: post, data: post,
refresh: refreshPost, refresh: refreshPost,
} = await useAsyncData(`blog:post-db:${slug}`, async () => await $trpc.post.createOrUpdate.mutate({ } = useFetch('/api/article', {
slug, method: 'POST',
})) body: {
slug,
},
})
const likes = ref(post.value!.likes) const likes = ref(post.value?.likes)
const like = async () => { const like = async () => {
const data = await $trpc.post.like.mutate({ slug }) const { data } = await useFetch('/api/like', { method: 'PUT' })
likes.value = data.likes likes.value = data
} }
const views = ref(post.value!.views) const views = ref(post.value!.views)
const view = async () => { const view = async () => {
const data = await $trpc.post.view.mutate({ slug }) const { data } = await useFetch('/api/view', { method: 'PUT' })
views.value = data.views likes.value = data
} }
return { return {

View File

@@ -1,40 +0,0 @@
import { useTalentsStore } from '~/store/talents'
export async function useTalents() {
const { $trpc } = useNuxtApp()
const { setCategory, setFavorite, getCategory, isFavorite } = useTalentsStore()
const {
data: talents,
refresh: refreshTalents,
pending,
} = await useAsyncData('talents:talents', async () => await $trpc.talents.getTalents.query({ favorite: isFavorite.value, category: getCategory.value }))
async function switchCategory(category: string) {
setCategory(category)
await refreshTalents()
}
async function toggleFavorite() {
setFavorite()
await refreshTalents()
}
function isCategory(category: string) {
return getCategory.value === category
}
const {
data: getCategories,
} = await $trpc.talents.getCategories.useQuery()
return {
talents,
getCategories,
isFavorite,
switchCategory,
toggleFavorite,
pending,
isCategory,
}
}

View File

@@ -1,9 +1,9 @@
export default defineNuxtRouteMiddleware(async (to) => { export default defineNuxtRouteMiddleware(async (to) => {
const isMaintenance = ref<boolean>(true) const isMaintenance = ref<boolean>(true)
const { $trpc } = useNuxtApp()
try { try {
isMaintenance.value = await $trpc.maintenance.is.query() await $fetch('/api/maintenance').then((maintenance: any) => {
isMaintenance.value = maintenance.enabled
})
} }
catch (error) { catch (error) {
return navigateTo('/maintenance') return navigateTo('/maintenance')

View File

@@ -7,8 +7,7 @@ useHead({
title: 'Site under maintenance • Arthur Danjou', title: 'Site under maintenance • Arthur Danjou',
}) })
const { $trpc } = useNuxtApp() const { data: maintenance } = await useFetch('/api/maintenance')
const maintenance = await $trpc.maintenance.get.query()
const format = 'DD MMMM YYYY, HH:mm' const format = 'DD MMMM YYYY, HH:mm'
const appConfig = useAppConfig() const appConfig = useAppConfig()
@@ -47,13 +46,13 @@ const socials = [
<h1 class="text-4xl md:text-7xl font-bold"> <h1 class="text-4xl md:text-7xl font-bold">
The website is under maintenance The website is under maintenance
</h1> </h1>
<div v-if="maintenance"> <div v-if="maintenance && maintenance.maintenance">
<p :class="getColor" class="font-bold mb-8 text-xl"> <p :class="getColor" class="font-bold mb-8 text-xl">
{{ maintenance.reason }} {{ maintenance.maintenance.reason }}
</p> </p>
<div> <div>
<p class="text-subtitle italic"> <p class="text-subtitle italic">
Maintenance planned from {{ useDateFormat(maintenance.beginAt, format).value }} to {{ useDateFormat(maintenance.endAt, format).value }} Maintenance planned from {{ useDateFormat(maintenance.maintenance.beginAt, format).value }} to {{ useDateFormat(maintenance.maintenance.endAt, format).value }}
</p> </p>
</div> </div>
</div> </div>

View File

@@ -1,10 +1,32 @@
<script lang="ts" setup> <script lang="ts" setup>
import { useTalentsStore } from '~/store/talents'
useHead({ useHead({
title: 'Discover new talents • Arthur Danjou', 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 { getCategories, talents, isFavorite, toggleFavorite, switchCategory, pending, isCategory } = await useTalents() const { getCategory, setCategory, isFavorite, toggleFavorite } = useTalentsStore()
const {
data: talents,
pending,
} = await useFetch('/api/talents', {
method: 'get',
query: {
favorite: isFavorite,
category: getCategory,
},
watch: [isFavorite, getCategory]
})
function isCategory(category: string) {
return getCategory.value === category
}
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 => categories.value.push({ label: category.name, slug: category.slug }))
@@ -28,6 +50,7 @@ function getColor() {
<div class="mb-6"> <div class="mb-6">
<div class="mb-2 flex items-center gap-2"> <div class="mb-2 flex items-center gap-2">
<UIcon name="i-ph-circle-wavy-question-bold" class="text-subtitle text-xl" /> <UIcon name="i-ph-circle-wavy-question-bold" class="text-subtitle text-xl" />
<!-- TODO: use suggestions -->
<h1 class="text-lg font-bold"> <h1 class="text-lg font-bold">
Want to be here ? Want to be here ?
</h1> </h1>
@@ -43,21 +66,14 @@ function getColor() {
<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 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 class="flex gap-2 overflow-x-scroll sm:overflow-x-hidden bg-gray-100 dark:bg-gray-800 rounded-lg p-1 relative">
<div <div
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" v-for="category in categories"
:class="{ 'text-gray-900 dark:text-white relative !bg-white dark:!bg-stone-900 rounded-md shadow-sm': isCategory('all') }"
@click.prevent="switchCategory('all')"
>
All
</div>
<div
v-for="category in getCategories"
:key="category.slug" :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 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="{ 'text-gray-900 dark:text-white relative !bg-white dark:!bg-stone-900 rounded-md shadow-sm': isCategory(category.slug) }" :class="{ 'text-gray-900 dark:text-white relative !bg-white dark:!bg-stone-900 rounded-md shadow-sm': isCategory(category.slug) }"
@click.prevent="switchCategory(category.slug)" @click.prevent="setCategory(category.slug)"
> >
<p class="w-full"> <p class="w-full">
{{ category.name }} {{ category.label }}
</p> </p>
</div> </div>
</div> </div>

View File

@@ -31,7 +31,7 @@ const { data: projects } = await useProjects()
class="group relative flex flex-col justify-between" class="group relative flex flex-col justify-between"
> >
<div class="relative z-10 flex h-12 w-12 items-center justify-center rounded-full bg-white shadow-md shadow-zinc-800/5 ring-1 ring-zinc-900/5 dark:border dark:border-zinc-700/50 dark:bg-zinc-800 dark:ring-0"> <div class="relative z-10 flex h-12 w-12 items-center justify-center rounded-full bg-white shadow-md shadow-zinc-800/5 ring-1 ring-zinc-900/5 dark:border dark:border-zinc-700/50 dark:bg-zinc-800 dark:ring-0">
<Icon :name="project.icon" size="24" /> <UIcon :name="project.icon" size="24" dynamic />
</div> </div>
<h2 class="mt-6 text-base font-semibold text-zinc-800 dark:text-zinc-100"> <h2 class="mt-6 text-base font-semibold text-zinc-800 dark:text-zinc-100">
<div class="absolute -inset-y-6 -inset-x-4 z-0 scale-95 bg-zinc-50 opacity-0 transition group-hover:scale-100 group-hover:opacity-100 dark:bg-zinc-800/50 sm:-inset-x-6 sm:rounded-2xl" /> <div class="absolute -inset-y-6 -inset-x-4 z-0 scale-95 bg-zinc-50 opacity-0 transition group-hover:scale-100 group-hover:opacity-100 dark:bg-zinc-800/50 sm:-inset-x-6 sm:rounded-2xl" />

View File

@@ -1,26 +0,0 @@
import { loggerLink } from '@trpc/client'
import SuperJSON from 'superjson'
import { createTRPCNuxtClient, httpBatchLink } from 'trpc-nuxt/client'
import type { AppRouter } from '~/server/trpc/routers'
export default defineNuxtPlugin(() => {
const trpc = createTRPCNuxtClient<AppRouter>({
transformer: SuperJSON,
links: [
loggerLink({
enabled: opts =>
process.env.NODE_ENV === 'development'
|| (opts.direction === 'down' && opts.result instanceof Error),
}),
httpBatchLink({
url: '/api/trpc',
}),
],
})
return {
provide: {
trpc,
},
}
})

View File

@@ -1,8 +0,0 @@
import { createNuxtApiHandler } from 'trpc-nuxt'
import { createContext } from '~/server/trpc/context'
import { appRouter } from '~/server/trpc/routers'
export default createNuxtApiHandler({
createContext,
router: appRouter,
})

View File

@@ -1,19 +0,0 @@
import { PrismaClient } from '@prisma/client'
import type { inferAsyncReturnType } from '@trpc/server'
import type { H3Event } from 'h3'
let prisma: PrismaClient | undefined
export function createContext(_event: H3Event) {
if (!prisma) {
prisma = new PrismaClient({
log: ['warn', 'info', 'error'],
})
}
return {
prisma,
}
}
export type Context = inferAsyncReturnType<typeof createContext>

View File

@@ -1,12 +0,0 @@
import { publicProcedure, router } from '../trpc'
export default router({
get: publicProcedure
.query(async ({ ctx }) => {
return await ctx.prisma.announcement.findFirst({
orderBy: {
createdAt: 'desc',
},
})
}),
})

View File

@@ -1,14 +0,0 @@
import { router } from '../trpc'
import announcement from './announcement'
import maintenance from './maintenance'
import post from './post'
import talents from './talents'
export const appRouter = router({
announcement,
post,
talents,
maintenance,
})
export type AppRouter = typeof appRouter

View File

@@ -1,29 +0,0 @@
import { publicProcedure, router } from '../trpc'
export default router({
get: publicProcedure
.query(async ({ ctx }) => {
return await ctx.prisma.maintenance.findFirst({
orderBy: {
createdAt: 'desc',
},
})
}),
is: publicProcedure
.query(async ({ ctx }) => {
const maintenance = await ctx.prisma.maintenance.findFirst({
orderBy: {
createdAt: 'desc',
},
})
if (process.env.NODE_ENV === 'development')
return false
const today = new Date()
return !!maintenance
&& maintenance.enabled
&& maintenance.beginAt.getTime() < today.getTime()
&& maintenance.endAt.getTime() > today.getTime()
}),
})

View File

@@ -1,68 +0,0 @@
import { z } from 'zod'
import { publicProcedure, router } from '../trpc'
const PostSchema = z.object({
slug: z.string(),
})
export default router({
createOrUpdate: publicProcedure
.input(PostSchema)
.mutation(async ({ ctx, input }) => {
return await ctx.prisma.post.upsert({
where: {
slug: input.slug,
},
update: {},
create: {
slug: input.slug,
},
})
}),
getTotalViews: publicProcedure
.query(async ({ ctx }) => {
const views = await ctx.prisma.post.aggregate({
_sum: {
views: true,
},
})
return views._sum.views || 0
}),
view: publicProcedure
.input(PostSchema)
.mutation(async ({ ctx, input }) => {
return await ctx.prisma.post.update({
where: {
slug: input.slug,
},
data: {
views: {
increment: 1,
},
},
})
}),
getTotalLikes: publicProcedure
.query(async ({ ctx }) => {
const likes = await ctx.prisma.post.aggregate({
_sum: {
likes: true,
},
})
return likes._sum.likes || 0
}),
like: publicProcedure
.input(PostSchema)
.mutation(async ({ ctx, input }) => {
return await ctx.prisma.post.update({
where: {
slug: input.slug,
},
data: {
likes: {
increment: 1,
},
},
})
}),
})

View File

@@ -1,112 +0,0 @@
import { z } from 'zod'
import { publicProcedure, router } from '../trpc'
export default router({
getTalents: publicProcedure
.input(z.object({
favorite: z.boolean(),
category: z.union([z.string(), z.literal('all')]),
}))
.query(async ({ ctx, input }) => {
if (input.favorite) {
return input.category === 'all'
? await ctx.prisma.talent.findMany({
orderBy: {
createdAt: 'desc',
},
include: {
categories: {
include: {
talent: true,
category: true,
},
orderBy: {
category: {
name: 'asc',
},
},
},
},
where: {
favorite: true,
categories: { every: { category: {} } },
},
})
: await ctx.prisma.talent.findMany({
orderBy: {
createdAt: 'desc',
},
include: {
categories: {
include: {
talent: true,
category: true,
},
orderBy: {
category: {
name: 'asc',
},
},
},
},
where: {
favorite: true,
categories: { some: { category: { slug: input.category } } },
},
})
}
else {
return input.category === 'all'
? await ctx.prisma.talent.findMany({
orderBy: {
createdAt: 'desc',
},
include: {
categories: {
include: {
talent: true,
category: true,
},
orderBy: {
category: {
name: 'asc',
},
},
},
},
where: {
categories: { every: { category: {} } },
},
})
: await ctx.prisma.talent.findMany({
orderBy: {
createdAt: 'desc',
},
include: {
categories: {
include: {
talent: true,
category: true,
},
orderBy: {
category: {
name: 'asc',
},
},
},
},
where: {
categories: { some: { category: { slug: input.category } } },
},
})
}
}),
getCategories: publicProcedure
.query(async ({ ctx }) => {
return await ctx.prisma.category.findMany({
where: {
type: 'TALENT',
},
})
}),
})

View File

@@ -1,12 +0,0 @@
import { initTRPC } from '@trpc/server'
import SuperJSON from 'superjson'
import type { Context } from './context'
const trpc = initTRPC.context<Context>().create({
transformer: SuperJSON,
})
export const publicProcedure = trpc.procedure
export const router = trpc.router
export const middleware = trpc.middleware
export const mergeRouters = trpc.mergeRouters

View File

@@ -7,21 +7,20 @@ export const useTalentsStore = defineStore(
const currentFavorite = ref<boolean>(false) const currentFavorite = ref<boolean>(false)
const getCategory = computed(() => currentCategory) const getCategory = computed(() => currentCategory)
const isFavorite = computed(() => currentFavorite) function setCategory(newCategory: string) {
currentCategory.value = newCategory
function setCategory(category: string) {
currentCategory.value = category
} }
function setFavorite() { const isFavorite = computed(() => currentFavorite)
function toggleFavorite() {
currentFavorite.value = !currentFavorite.value currentFavorite.value = !currentFavorite.value
} }
return { return {
getCategory, getCategory,
setCategory, setCategory,
setFavorite,
isFavorite, isFavorite,
toggleFavorite,
} }
}, },
{ {

1790
yarn.lock

File diff suppressed because it is too large Load Diff