Skip to content

Commit

Permalink
feat: ts-rest + admission passes (#5)
Browse files Browse the repository at this point in the history
  • Loading branch information
qin-guan authored Oct 1, 2023
1 parent fbd3902 commit 80e7712
Show file tree
Hide file tree
Showing 11 changed files with 877 additions and 89 deletions.
2 changes: 1 addition & 1 deletion components/app/services/page.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<script setup lang="ts">
import { FetchError } from 'ofetch'
import { f7, f7Block, f7BlockTitle, f7Button, f7Card, f7CardContent, f7CardFooter, f7CardHeader, f7Icon, f7List, f7ListButton, f7ListGroup, f7ListInput, f7ListItem, f7NavTitle, f7NavTitleLarge, f7Navbar, f7Page, f7PageContent, f7Sheet, f7SwipeoutButton } from 'framework7-vue'
import { f7, f7Block, f7BlockTitle, f7Button, f7Icon, f7List, f7ListButton, f7ListInput, f7ListItem, f7NavTitle, f7NavTitleLarge, f7Navbar, f7Page, f7PageContent, f7Sheet } from 'framework7-vue'
const sstaarsStore = useSstaarsStore()
Expand Down
9 changes: 9 additions & 0 deletions composables/fetch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ import { defu } from 'defu'
import { getAuth } from 'firebase/auth'
import type { UseFetchOptions } from '#app'

/**
* @deprecated Use contracts from @ts-rest/core instead
*/
export const $api = $fetch.create({
async onRequest(context) {
const token = await getAuth().currentUser?.getIdToken()
Expand All @@ -15,6 +18,9 @@ export const $api = $fetch.create({

type ApiFetchRequest<T> = Ref<T> | T | (() => T)

/**
* @deprecated Use contracts from @ts-rest/core instead
*/
export function useApiFetch<ResT, ReqT extends string = string>(request: ApiFetchRequest<ReqT>, options: UseFetchOptions<ResT> = {}) {
const defaults: UseFetchOptions<ResT> = {
$fetch: $api,
Expand All @@ -23,6 +29,9 @@ export function useApiFetch<ResT, ReqT extends string = string>(request: ApiFetc
return useFetch(request, params)
}

/**
* @deprecated Use contracts from @ts-rest/core instead
*/
export function useLazyApiFetch<ResT, ReqT extends string = string>(request: ApiFetchRequest<ReqT>, options: Omit<UseFetchOptions<ResT>, 'lazy'> = {}) {
const defaults: UseFetchOptions<ResT> = {
$fetch: $api,
Expand Down
16 changes: 16 additions & 0 deletions composables/sstaars.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,21 @@
import { useStorage } from '@vueuse/core'

const queryKeyFactory = {
admission: (key: string) => ['sstaars', 'admission', key],
}

export const useSstaarsStore = createGlobalState(() => {
return useStorage('sstaars:data', { previousEvents: {} as Record<string, string> })
})

export function useAdmission(key: string) {
const app = useNuxtApp()
return app.$apiQuery.getAdmission.useQuery(
queryKeyFactory.admission(key),
() => ({
params: {
key,
},
}),
)
}
4 changes: 4 additions & 0 deletions nuxt.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ export default defineNuxtConfig({
devtools: { enabled: true },
spaLoadingTemplate: './app/spa-loading-template.html',

typescript: {
strict: true,
},

vue: {
defineModel: true,
},
Expand Down
5 changes: 5 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,13 @@
"@tanstack/query-persist-client-core": "^4.35.3",
"@tanstack/query-sync-storage-persister": "^4.35.3",
"@tanstack/vue-query": "^4.35.3",
"@ts-rest/core": "^3.30.2",
"@ts-rest/vue-query": "^3.30.2",
"@unocss/nuxt": "^0.56.0",
"@vite-pwa/assets-generator": "^0.0.10",
"@vite-pwa/nuxt": "^0.1.1",
"@vueuse/core": "^10.4.1",
"@vueuse/integrations": "^10.4.1",
"@vueuse/nuxt": "^10.4.1",
"dayjs": "^1.11.9",
"dotenv": "^16.3.1",
Expand All @@ -43,7 +46,9 @@
"material-icons": "^1.13.11",
"nuxt": "^3.7.3",
"nuxt-vuefire": "^0.3.0",
"qrcode": "^1.5.3",
"simple-git": "^3.20.0",
"vue-tsc": "^1.8.15",
"vuefire": "^3.1.17",
"web-auth-library": "^1.0.3",
"zod": "^3.22.2"
Expand Down
106 changes: 106 additions & 0 deletions pages/pass/[admissionKey].vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
<script setup lang="ts">
import { f7AccordionContent, f7App, f7Block, f7BlockTitle, f7Button, f7List, f7ListItem, f7Navbar, f7Page, f7SkeletonBlock, f7View } from 'framework7-vue'
import 'framework7/css/bundle'
import 'framework7-icons/css/framework7-icons.css'
import 'material-icons/iconfont/material-icons.css'
// @ts-expect-error Missing types
import Framework7 from 'framework7/lite-bundle'
// @ts-expect-error Missing types
import Framework7Vue from 'framework7-vue/bundle'
import { useQRCode } from '@vueuse/integrations/useQRCode'
Framework7.use(Framework7Vue)
const route = useRoute()
const { data: admission, isLoading: admissionIsLoading, error } = useAdmission(route.params.admissionKey as string)
const qrcode = useQRCode(() => admission.value?.body.admissionKey ?? '', {
width: 500,
color: {
light: '#fefbff',
},
})
</script>

<template>
<f7App theme="md">
<f7View>
<f7Page>
<f7Navbar title="SST Alumni Association Passes" />

<div v-if="admissionIsLoading">
<f7List inset class="flex flex-gap-4 flex-col">
<f7SkeletonBlock height="100px" class="rounded-md!" />
<f7SkeletonBlock height="200px" class="rounded-md!" />
<f7SkeletonBlock height="300px" class="rounded-md!" />
</f7List>
</div>

<div v-else-if="error">
<f7Block class="flex flex-col items-start">
<f7BlockTitle large>
Not found :/
</f7BlockTitle>
<span class="text-lg">
Your pass was not found.
<br>
That's all we know.
</span>
<f7Button href="/app" external fill class="mt-10!">
Return to app
</f7Button>
</f7Block>
</div>

<div v-else-if="admission">
<f7BlockTitle>
Pass info
</f7BlockTitle>
<f7Block strong inset>
<p class="font-semibold">
Event name
</p>
<p>
{{ admission?.body.event.name }}
</p>
</f7Block>

<f7BlockTitle>
QR code
</f7BlockTitle>
<f7Block>
<div class="w-full flex flex-col items-center">
<img :src="qrcode" alt="QR Code" class="max-w-200px">
<span>{{ admission?.body.admissionKey }}</span>
</div>
</f7Block>

<f7BlockTitle>FAQs</f7BlockTitle>
<f7List strong outline-ios dividers-ios inset-md accordion-list>
<f7ListItem accordion-item title="What do I do with this QR code?">
<f7AccordionContent>
<f7Block>
<p>
Simply present it to the SSTAA volunteers when entering SST.
</p>
</f7Block>
</f7AccordionContent>
</f7ListItem>

<f7ListItem accordion-item title="Can I reuse this QR code?">
<f7AccordionContent>
<f7Block>
<p>
No, each QR code is single use only. Please refrain from leaving the venue after admission.
</p>
</f7Block>
</f7AccordionContent>
</f7ListItem>
</f7List>
</div>
</f7Page>
</f7View>
</f7App>
</template>
13 changes: 13 additions & 0 deletions plugins/vue-query.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { initQueryClient } from '@ts-rest/vue-query'
import { VueQueryPlugin, type VueQueryPluginOptions } from '@tanstack/vue-query'
import { persistQueryClient } from '@tanstack/query-persist-client-core'
import { createSyncStoragePersister } from '@tanstack/query-sync-storage-persister'
import { contract } from '~/shared/contracts'

export default defineNuxtPlugin((nuxtApp) => {
const vueQueryOptions: VueQueryPluginOptions = {
Expand All @@ -21,4 +23,15 @@ export default defineNuxtPlugin((nuxtApp) => {
}

nuxtApp.vueApp.use(VueQueryPlugin, vueQueryOptions)

const query = initQueryClient(contract, {
baseUrl: '',
baseHeaders: {},
})

return {
provide: {
apiQuery: query,
},
}
})
Loading

0 comments on commit 80e7712

Please # to comment.