Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Simple Speed Score #66

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions src/apollo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import { setContext } from '@apollo/client/link/context'
import { persistCache } from 'apollo3-cache-persist'
import { getAuth } from 'firebase/auth'

import type { SpeedResultsQueryVariables } from './graphql/generated/graphql'

const httpLink = createHttpLink({
uri: import.meta.env.VITE_GRAPHQL_URL
})
Expand All @@ -22,6 +24,26 @@ const cache = new InMemoryCache({
User: {
merge (existing, incoming, { mergeObjects }) {
return mergeObjects(existing, incoming)
},
fields: {
speedResults: {
keyArgs: false,
merge (existing: any[] = [], incoming: any[], { readField, args }) {
const merged = existing.slice(0)
const existingIds = new Set(merged.map(doc => readField('id', doc)))

incoming = incoming.filter(doc => !existingIds.has(readField("id", doc)))
const afterIndex = merged.findIndex(doc => (args as SpeedResultsQueryVariables).startAfter === readField("createdAt", doc))


if (afterIndex >= 0) {
merged.splice(afterIndex + 1, 0, ...incoming)
} else {
merged.push(...incoming)
}
return merged
}
}
}
}
}
Expand Down
47 changes: 40 additions & 7 deletions src/components/NavHeader.vue
Original file line number Diff line number Diff line change
@@ -1,24 +1,46 @@
<template>
<header class="border-b-ttred-900 bg-ttred-500 border-b sticky top-0 left-0 right-0 flex justify-between items-center py-1 px-2 whitespace-nowrap z-1000">
<header ref="headerRef" class="border-b-ttred-900 bg-ttred-500 border-b sticky top-0 left-0 right-0 flex justify-between items-center py-1 px-2 whitespace-nowrap z-1000">
<router-link to="/" class="inline-flex justify-start items-center text-white text-size-xl">
<img src="/tricktionary2.svg" height="30" with="30" class="h-30px mr-1 align-bottom">
the Tricktionary
</router-link>

<nav class="flex">
<router-link exact-active-class="active" class="nav-link" to="/">Tricks</router-link>
<!-- <router-link active-class="active" class="nav-link" to="/speed">Speed</router-link> -->
<router-link active-class="active" class="nav-link" to="/shop">Shop</router-link>
<router-link active-class="active" class="nav-link" to="/profile" v-if="user">Profile</router-link>
<router-link active-class="active" class="nav-link" to="/auth" v-else>Sign in</router-link>
<div class="flex sm:hidden">
<a
class="nav-link inline-flex items-center justify-center min-h-8 pointer-hand"
@click="showNav = !showNav"
><icon-menu title="Toggle Menu" /></a>
</div>
<nav
class="flex <sm:absolute <sm:top-12 <sm:right-0 <sm:left-0 <sm:flex-col"
:class="{
'<sm:hidden': !showNav,
}"
@click="showNav = false"
>
<router-link exact-active-class="active" class="nav-block nav-link" to="/">Tricks</router-link>
<router-link active-class="active" class="nav-block nav-link" to="/speed">Speed</router-link>
<router-link active-class="active" class="nav-block nav-link" to="/shop">Shop</router-link>
<router-link active-class="active" class="nav-block nav-link" to="/profile" v-if="user">Profile</router-link>
<router-link active-class="active" class="nav-block nav-link" to="/auth" v-else>Sign in</router-link>
</nav>
</header>
</template>

<script setup lang="ts">
import { ref } from 'vue'
import { onClickOutside } from '@vueuse/core'
import useAuth from '../hooks/useAuth'

import IconMenu from 'virtual:vite-icons/mdi/menu'

const { firebaseUser: user } = useAuth()
const showNav = ref(false)
const headerRef = ref()

onClickOutside(headerRef, () => {
showNav.value = false
})
</script>

<style scoped>
Expand All @@ -31,6 +53,17 @@ const { firebaseUser: user } = useAuth()
color: white;
}

@media (max-width: 639.9px) {
.nav-block {
@apply bg-ttred-500;
@apply rounded-none;
@apply m-0;
@apply py-4;
@apply border-t;
@apply border-ttred-900;
}
}

.nav-link:hover,
.nav-link.active {
@apply bg-ttyellow-500;
Expand Down
35 changes: 35 additions & 0 deletions src/components/SpeedBox.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<template>
<router-link
class="
block grid grid-cols-[auto,4rem] grid-rows-3
rounded border border-gray-300 hover:bg-gray-200
p-2
"
:to="`/speed/${result.id}`"
@click="$emit('navigate')"
>
<span class="col-start-2 row-span-3 flex justify-center items-center">{{ result.count }}</span>

<span class="col-start-1 row-start-1 font-bold">
{{ result.eventDefinition.name }}
</span>
<span class="col-start-1">{{ formatDateTime(result.createdAt) }}</span>
<span class="col-start-1">{{ result.name }}</span>
</router-link>
</template>

<script setup lang="ts">
import { formatDateTime } from '../helpers'

import type { PropType } from 'vue'
import type { SpeedResult } from '../graphql/generated/graphql'

defineProps({
result: {
type: Object as PropType<Pick<SpeedResult, 'id' | 'name' | 'createdAt' | 'count' | 'eventDefinition'>>,
required: true
}
})

const a = 1
</script>
2 changes: 1 addition & 1 deletion src/components/TrickBox.vue
Original file line number Diff line number Diff line change
Expand Up @@ -43,13 +43,13 @@
import { ref, toRef } from 'vue'

import { disciplineToSlug } from "../helpers";
import useCompleteTrick from '../hooks/useCompleteTrick';

import IconCheck from 'virtual:vite-icons/mdi/check'
import IconLoading from 'virtual:vite-icons/mdi/loading'

import type { PropType } from 'vue'
import type { TricksQuery } from '../graphql/generated/graphql'
import useCompleteTrick from '../hooks/useCompleteTrick';

const props = defineProps({
trick: {
Expand Down
Empty file.
11 changes: 11 additions & 0 deletions src/graphql/queries/checklist.gql
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
query Checklist {
me {
id
checklist {
id
trick {
id
}
}
}
}
8 changes: 1 addition & 7 deletions src/graphql/queries/me.gql
Original file line number Diff line number Diff line change
@@ -1,15 +1,9 @@
query Me ($withChecklist: Boolean!) {
query Me {
me {
id
username
name
photo
lang
checklist @include(if: $withChecklist) {
id
trick {
id
}
}
}
}
34 changes: 34 additions & 0 deletions src/graphql/queries/speedResutls.gql
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
query SpeedResults ($limit: Int, $startAfter: Timestamp) {
me {
id
speedResults (limit: $limit, startAfter: $startAfter) {
... on SimpleSpeedResult {
id
name
createdAt
count
eventDefinition {
id
name
totalDuration
}
}
... on DetailedSpeedResult {
id
name
createdAt
count
eventDefinition {
id
name
totalDuration
}
}
}
}
eventDefinitions {
id
name
totalDuration
}
}
7 changes: 7 additions & 0 deletions src/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,10 @@ export function formatPrice (prices: PricesFormatFields | Readonly<PricesFormatF
currency
}).format(price?.unitAmount / 100)
}

export function formatDateTime (date: number | Date) {
return new Intl.DateTimeFormat(undefined, {
dateStyle: 'medium',
timeStyle: 'short'
}).format(date)
}
4 changes: 2 additions & 2 deletions src/hooks/useAuth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ const analytics = getAnalytics()
const firebaseUser = ref<User | null>()
let off: Unsubscribe

export default function useAuth ({ withChecklist = false } = {}) {
const userQuery = useMeQuery({ withChecklist }, { fetchPolicy: 'cache-and-network' })
export default function useAuth () {
const userQuery = useMeQuery({ fetchPolicy: 'cache-and-network' })

const user = useResult(userQuery.result, null, data => data.me)

Expand Down
11 changes: 4 additions & 7 deletions src/hooks/useCompleteTrick.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
import { getAnalytics, logEvent } from '@firebase/analytics'
import { MeDocument, MeQuery, MeQueryVariables, useCompleteTrickMutation } from '../graphql/generated/graphql'

import type { Ref } from 'vue'
import { ChecklistDocument, ChecklistQuery, ChecklistQueryVariables, useCompleteTrickMutation } from '../graphql/generated/graphql'

const analytics = getAnalytics()

export default function useCompleteTrick (variables?: { trickId: string, completed: boolean }) {
const mutation = useCompleteTrickMutation(() => ({
...(variables ? { variables } : {}),
update (cache, { data }) {
const cachedData = cache.readQuery<MeQuery, MeQueryVariables>({ query: MeDocument, variables: { withChecklist: true } })
const cachedData = cache.readQuery<ChecklistQuery, ChecklistQueryVariables>({ query: ChecklistDocument })

if (cachedData?.me?.checklist?.length) {
const checklist = [...cachedData.me.checklist]
Expand All @@ -21,9 +19,8 @@ export default function useCompleteTrick (variables?: { trickId: string, complet
checklist.push(data.createTrickCompletion)
}

cache.writeQuery<Partial<MeQuery> | null, MeQueryVariables>({
query: MeDocument,
variables: { withChecklist: true },
cache.writeQuery<Partial<ChecklistQuery> | null, ChecklistQueryVariables>({
query: ChecklistDocument,
data: { me: { id: cachedData?.me?.id, checklist } }
})
}
Expand Down
13 changes: 11 additions & 2 deletions src/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,22 @@ const analytics = getAnalytics()

export const routes: RouteRecordRaw[] = [
{ name: 'tricktionary', path: '/', component: () => import('./views/Home.vue') },

{ name: 'trick', path: '/trick/:discipline/:slug', component: () => import('./views/Trick.vue') },

{ name: 'speed', path: '/speed', component: () => import('./views/SpeedIndex.vue') },
{ name: 'speed-create', path: '/speed/create', component: () => import('./views/SpeedCreate.vue') },
{ name: 'speed-details', path: '/speed/details/:id', component: () => import('./views/SpeedIndex.vue') },

{ name: 'shop', path: '/shop', component: () => import('./views/Shop.vue') },
{ name: 'shop-success', path: '/shop-success', component: () => import('./views/ShopSuccess.vue') },

{ name: 'auth', path: '/auth', component: () => import('./views/Auth.vue') },
{ name: 'profile', path: '/profile', component: () => import('./views/Profile.vue') },

{ name: 'rafiki', path: '/rafiki', component: () => import('./views/Rafiki.vue') },
{ name: 'policies', path: '/policies', component: () => import('./views/Policies.vue') },
{ name: 'shop', path: '/shop', component: () => import('./views/Shop.vue') },
{ name: 'shop-success', path: '/shop-success', component: () => import('./views/ShopSuccess.vue') },

{ name: 'not_found', path: '/:catchAll(.*)*', component: () => import('./views/404.vue') }
]

Expand Down
10 changes: 6 additions & 4 deletions src/views/Home.vue
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ import TtFooter from '../components/Footer.vue'
import Links from '../components/Links.vue'
import IconCheckbox from '../components/IconCheckbox.vue'

import { Discipline, useTricksQuery } from '../graphql/generated/graphql'
import { Discipline, useChecklistQuery, useTricksQuery } from '../graphql/generated/graphql'
import useAuth from '../hooks/useAuth'
import useSettings from '../hooks/useSettings'
import AdAdsense from '../components/AdAdsense.vue'
Expand All @@ -63,15 +63,18 @@ import BottomBar from '../components/BottomBar.vue'
const discipline = ref<Discipline>()
const settings = useSettings()
const analytics = getAnalytics()
const { firebaseUser, user } = useAuth({ withChecklist: true })
const { firebaseUser, user } = useAuth()

const tricksQuery = useTricksQuery({
discipline: discipline.value,
withLocalised: !!user.value?.lang && user.value?.lang !== 'en',
lang: !!user.value?.lang && user.value?.lang !== 'en' ? user.value.lang : undefined
})
const checklistQuery = useChecklistQuery()

const tricks = useResult(tricksQuery.result, [] as TricksQuery['tricks'], data => data?.tricks)
const checklist = ref<Set<string>>(new Set())
const checklist = useResult(checklistQuery.result, new Set() as Set<string>, data => new Set(data?.me?.checklist?.map(checklistItem => checklistItem.trick.id)))

const search = ref<string | undefined>(undefined)
const debouncedSearch = useDebounce(search, 1000)

Expand All @@ -86,7 +89,6 @@ watch(user, user => {
tricksQuery.variables.value.withLocalised = false
tricksQuery.variables.value.lang = undefined
}
checklist.value = new Set(user?.checklist?.map(checklistItem => checklistItem.trick.id))
})
watch(debouncedSearch, search => {
console.log(search)
Expand Down
11 changes: 11 additions & 0 deletions src/views/SpeedCreate.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<template>
<section class="container mx-auto p-2">
<label>Event</label>
<!-- select events or custom, custom brings up input boxes for name and duration -->
<!-- <label>Date (default today)</label> -->
<label>Name (optional)</label>
<label>Score</label> or <button>Count</button>

<button>create</button>
</section>
</template>
Loading
Loading