Skip to content

Commit

Permalink
feat: caching and improved thanks page
Browse files Browse the repository at this point in the history
  • Loading branch information
qin-guan committed Jul 16, 2023
1 parent bd4fc1f commit 9d92f16
Show file tree
Hide file tree
Showing 6 changed files with 121 additions and 50 deletions.
16 changes: 16 additions & 0 deletions nuxt.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,22 @@ export default defineNuxtConfig({
},

image: {},
nitro: {
storage: {
devStorage: {
driver: 'memory',
},
redis: (() => (process.env.NUXT_ENABLE_REDIS
? {
driver: 'redis',
port: process.env.NUXT_REDIS_PORT,
host: process.env.NUXT_REDIS_HOST,
username: process.env.NUXT_REDIS_USERNAME,
password: process.env.NUXT_REDIS_PASSWORD,
}
: undefined))(),
},
},

runtimeConfig: {
public: {
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
"superjson": "^1.12.4",
"trpc-nuxt": "^0.10.6",
"trpc-openapi": "^1.2.0",
"unstorage": "^1.8.0",
"vitepress": "1.0.0-beta.5",
"vue": "^3.3.4",
"vue-tsc": "^1.8.4",
Expand Down
100 changes: 58 additions & 42 deletions pages/thanks.vue
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ useSeoMeta({
})
const route = useRoute()
const config = useRuntimeConfig()
const toast = useToast()
const { $client } = useNuxtApp()
Expand All @@ -26,6 +25,14 @@ const { data: responses, pending: responsesPending, error: responsesError } = aw
const { data: survey, pending: surveyPending } = await $client.survey.get.useQuery({ id: route.query.id as string }, { lazy: true })
const { data: me } = await $client.me.get.useQuery(undefined, { lazy: true })
const formData = reactive({
name: '',
nric: '',
phone: '',
pending: false,
showDetails: true,
})
const eligibleForLuckyDraw = computed(() => {
if (responsesPending.value || responsesError.value)
return false
Expand All @@ -51,18 +58,14 @@ const progresses = computed(() => {
}
})
const formData = reactive({
name: '',
nric: '',
phone: '',
pending: false,
})
watch(me, (value) => {
if (value) {
formData.name = value.name ?? ''
formData.nric = value.nric ?? ''
formData.phone = value.phone ?? ''
if (value.name && value.nric && value.phone)
formData.showDetails = false
}
}, { immediate: true })
Expand All @@ -78,6 +81,7 @@ async function create() {
summary: 'Profile updated!',
detail: 'Successfully registered for lucky draw!',
})
formData.showDetails = false
}
catch (err) {
console.error(err)
Expand Down Expand Up @@ -110,42 +114,54 @@ async function create() {
</span>
</section>

<Card
<template
v-if="eligibleForLuckyDraw"
>
<template #title>
🎉 You're eligible for lucky draw
</template>
<template #subtitle>
Stand a chance to win by updating your personal information below.
</template>
<template #content>
<form flex="~ col gap6" @submit.prevent="create">
<div class="flex flex-col gap-2">
<label for="name">Name</label>
<InputText id="name" v-model="formData.name" placeholder="John Smith" required type="text" aria-describedby="name-help" class="max-w-md" />
<small id="name-help" class="sr-only">Enter your name</small>
</div>

<div class="flex flex-col gap-2">
<label for="nric">NRIC (last 4 characters)</label>
<InputMask id="nric" v-model="formData.nric" mask="999a" placeholder="123B" required type="text" aria-describedby="nric-help" class="max-w-md" />
<small id="nric-help" class="sr-only">Enter the last 4 characters of your NRIC</small>
</div>

<div class="flex flex-col gap-2">
<label for="phone">Phone number</label>
<InputMask id="phone" v-model="formData.phone" date="phone" mask="9999 9999" placeholder="8888 8888" required aria-describedby="phone-help" class="max-w-md" />
<small id="phone-help" class="sr-only">Enter the last 4 characters of your NRIC</small>
</div>

<div>
<Button label="Update" type="submit" size="small" :loading="formData.pending" />
</div>
</form>
</template>
</Card>

<Card v-if="formData.showDetails">
<template #title>
🎉 You're eligible for lucky draw
</template>
<template #subtitle>
Stand a chance to win by updating your personal information below.
</template>
<template #content>
<form flex="~ col gap6" @submit.prevent="create">
<div class="flex flex-col gap-2">
<label for="name">Name</label>
<InputText id="name" v-model="formData.name" placeholder="John Smith" required type="text" aria-describedby="name-help" class="max-w-md" />
<small id="name-help" class="sr-only">Enter your name</small>
</div>

<div class="flex flex-col gap-2">
<label for="nric">NRIC (last 4 characters)</label>
<InputMask id="nric" v-model="formData.nric" mask="999a" placeholder="123B" required type="text" aria-describedby="nric-help" class="max-w-md" />
<small id="nric-help" class="sr-only">Enter the last 4 characters of your NRIC</small>
</div>

<div class="flex flex-col gap-2">
<label for="phone">Phone number</label>
<InputMask id="phone" v-model="formData.phone" date="phone" mask="9999 9999" placeholder="8888 8888" required aria-describedby="phone-help" class="max-w-md" />
<small id="phone-help" class="sr-only">Enter the last 4 characters of your NRIC</small>
</div>

<div>
<Button label="Submit!" type="submit" size="small" :loading="formData.pending" />
</div>
</form>
</template>
</Card>
<Card v-else>
<template #title>
🎉 You're all set!
</template>
<template #subtitle>
You're in the lucky draw! Remember to make sure your details are correct!
</template>
<template #content>
<Button label="Update my details" type="button" size="small" @click="formData.showDetails = true" />
</template>
</Card>
</template>
<Card v-else>
<template #title>
Fill out more forms to participate in the lucky draw!
Expand Down
11 changes: 7 additions & 4 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

17 changes: 15 additions & 2 deletions server/trpc/routers/me/index.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,25 @@
import { z } from 'zod'
import { createStorage, prefixStorage } from 'unstorage'
import type { User } from '@prisma/client'
import { protectedProcedure, router } from '../../trpc'

const baseStorage = createStorage()
const userStorage = prefixStorage(baseStorage, 'users')

export const meRouter = router({
get: protectedProcedure
.meta({ participants: true })
.query(async ({ ctx }) => {
return ctx.prisma.user.findUniqueOrThrow({
if (await userStorage.hasItem(ctx.session.user.id))
return await userStorage.getItem<User>(ctx.session.user.id)

const user = ctx.prisma.user.findUniqueOrThrow({
where: { id: ctx.session.user.id },
select: defaultUserSelect,
})

await userStorage.setItem(ctx.session.user.id, user)
return user
}),
update: protectedProcedure
.meta({ participants: true }).input(
Expand All @@ -19,9 +30,11 @@ export const meRouter = router({
}),
)
.mutation(async ({ ctx, input }) => {
return ctx.prisma.user.update({
const user = ctx.prisma.user.update({
where: { id: ctx.session.user.id },
data: input,
})
await userStorage.setItem(ctx.session.user.id, user)
return user
}),
})
26 changes: 24 additions & 2 deletions server/trpc/routers/survey/index.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,33 @@
import type { Survey } from '@prisma/client'
import { Prisma } from '@prisma/client'
import { TRPCError } from '@trpc/server'
import { z } from 'zod'
import { createStorage, prefixStorage } from 'unstorage'
import type { QuestionsSchema, SurveyPermissionSchema } from '../../../../shared/survey'
import { questionsSchema, surveyPermissionSchema } from '../../../../shared/survey'
import { protectedProcedure, router } from '../../trpc'

const baseStorage = createStorage()
const surveyStorage = prefixStorage(baseStorage, 'surveys')

export const surveyRouter = router({
get: protectedProcedure.meta({ participants: true }).input(
z.object({
id: z.string(),
}),
).query(async ({ ctx, input }) => {
if (await surveyStorage.hasItem(input.id))
return await surveyStorage.getItem<Survey>(ctx.session.user.id)

try {
const survey = await ctx.prisma.survey.findUniqueOrThrow({
where: {
id: input.id,
},
})

await surveyStorage.setItem(input.id, survey)

return {
...survey,
questions: survey.questions as QuestionsSchema,
Expand All @@ -39,7 +49,13 @@ export const surveyRouter = router({
}),

list: protectedProcedure.query(async ({ ctx }) => {
return await ctx.prisma.survey.findMany()
if (await surveyStorage.hasItem('__all_surveys'))
return await surveyStorage.getItem<Survey[]>('__all_surveys')

const surveys = await ctx.prisma.survey.findMany()
await surveyStorage.setItem('__all_surveys', surveys)

return surveys
}),

create: protectedProcedure
Expand Down Expand Up @@ -68,6 +84,8 @@ export const surveyRouter = router({
data: input,
})

await surveyStorage.setItem(survey.id, survey)

return {
...survey,
questions: survey.questions as QuestionsSchema,
Expand All @@ -86,9 +104,13 @@ export const surveyRouter = router({
permissions: surveyPermissionSchema,
}),
).mutation(async ({ ctx, input }) => {
return await ctx.prisma.survey.update({
const survey = await ctx.prisma.survey.update({
where: { id: input.id },
data: input,
})

await surveyStorage.setItem(survey.id, survey)

return survey
}),
})

0 comments on commit 9d92f16

Please sign in to comment.