Skip to content

Commit

Permalink
feat: indiv responses
Browse files Browse the repository at this point in the history
  • Loading branch information
qin-guan committed Jul 14, 2023
1 parent dcb1489 commit d1d318c
Show file tree
Hide file tree
Showing 2 changed files with 67 additions and 9 deletions.
50 changes: 43 additions & 7 deletions pages/dashboard/surveys/[id]/analytics.vue
Original file line number Diff line number Diff line change
@@ -1,15 +1,21 @@
<script setup lang="ts">
import Button from 'primevue/button'
import RadioButton from 'primevue/radiobutton'
import Dialog from 'primevue/dialog'
import TabView from 'primevue/tabview'
import TabPanel from 'primevue/tabpanel'
import DataTable from 'primevue/datatable'
import Button from 'primevue/button'
import Textarea from 'primevue/textarea'
import Column from 'primevue/column'
const route = useRoute()
const { $client } = useNuxtApp()
const responsePreview = reactive({
visible: false,
idx: -1,
})
const { data } = await $client.analytics.listResponses.useQuery({ id: route.params.id as string })
// const qnData = computed(() => {
// return data.value.map((d) => d.data).reduce((acc, curr) => {
Expand All @@ -19,21 +25,51 @@ const { data } = await $client.analytics.listResponses.useQuery({ id: route.para

<template>
<main mx-auto p-6 container>
<Dialog v-model:visible="responsePreview.visible" modal header="Response" :style="{ width: '50vw' }">
<div flex flex-col divide-y divide-gray>
<div v-for="(question, idx) in data.schema" :key="idx" flex flex-col gap3 py6>
<span font-semibold>{{ question.title }}</span>
<div>
<Textarea
v-if="question.type === 'text'" disabled :value="
// @ts-expect-error Answer exists on text type
data.responses[responsePreview.idx].data[idx].answer
"
/>
<div v-else-if="question.type === 'mcq'" flex flex-col gap3>
<div v-for="(option, optionIdx) in question.options" :key="option" class="flex items-center">
<RadioButton
disabled
:model-value="
// @ts-expect-error Option does exist, but discriminated unions don't work well here
data.responses[responsePreview.idx].data[idx].option
"
:value="optionIdx"
:input-id="option"
/>
<label :for="option" class="ml-2">{{ option }}</label>
</div>
</div>
</div>
</div>
</div>
</Dialog>

<h1 text-3xl font-bold>
Surveys
Analytics
</h1>

<br>

<TabView>
<TabPanel header="Data table">
<DataTable :value="data" table-class="w-full">
<DataTable :value="data.responses" table-class="w-full">
<Column field="id" header="ID" />
<Column field="timestamp" header="Timestamp" />
<Column field="respondentId" header="Respondent" />
<Column field="respondent.name" header="Respondent" />
<Column header="Expand">
<template #body>
<Button icon="" link>
<template #body="bodySlot">
<Button icon="" link @click="responsePreview.idx = bodySlot.index; responsePreview.visible = true">
<div i-tabler-arrow-up-right text-xl />
</Button>
</template>
Expand Down
26 changes: 24 additions & 2 deletions server/trpc/routers/analytics/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { z } from 'zod'
import { TRPCError } from '@trpc/server'
import { protectedProcedure, router } from '../../trpc'
import { surveySchema } from '../../../../shared/survey'

export const analyticsRouter = router({
myResponses: protectedProcedure.query(async ({ ctx }) => {
Expand All @@ -18,10 +20,30 @@ export const analyticsRouter = router({
id: z.string(),
}),
).query(async ({ ctx, input }) => {
return await ctx.prisma.response.findMany({
const data = await ctx.prisma.survey.findUniqueOrThrow({
where: {
surveyId: input.id,
id: input.id,
},
include: {
responses: {
include: {
respondent: true,
},
},
},
})

const result = await surveySchema.safeParseAsync(data.schema)
if (!result.success) {
throw new TRPCError({
code: 'BAD_REQUEST',
cause: result.error,
})
}

return {
...data,
schema: result.data,
}
}),
})

0 comments on commit d1d318c

Please sign in to comment.