Files
calebburke.dev/web/src/pages/FlashcardsPage.vue
T
2026-07-17 04:39:18 -07:00

166 lines
4.1 KiB
Vue

<template>
<v-row class="fill-height">
<v-col
cols="12"
md="3"
>
<v-card
height="100%"
class="pa-2"
>
<FlashcardDeckTree
ref="deckTree"
@select="onDeckSelected"
@updated="onDeckUpdated"
@deleted="onDeckDeleted"
/>
</v-card>
</v-col>
<v-col
cols="12"
md="9"
>
<template v-if="selectedDeck">
<v-row>
<v-col
cols="12"
md="3"
>
<span class="text-h3">{{ selectedDeck.name }}</span>
<span class="ml-2">({{ totalCount }})</span>
</v-col>
<v-col
cols="12"
md="6"
/>
<v-col
class="d-flex align-center"
cols="12"
md="2"
>
<v-btn
color="primary"
variant="tonal"
prepend-icon="mdi-plus"
text="Add Flashcard"
@click="openFlashcardCreateDialog"
/>
<FlashcardDeckStartReviewBtn :flashcard-deck-id="selectedDeck.id" />
</v-col>
</v-row>
<v-divider class="my-5" />
<v-row>
<v-col
v-for="flashcard in flashcards"
:key="flashcard.id"
cols="12"
md="6"
lg="4"
>
<FlashcardCard
:flashcard="flashcard"
@updated="refreshFlashcards"
@deleted="refreshFlashcards"
/>
</v-col>
</v-row>
<EnhancedPagination
v-model="page"
v-model:per-page="perPage"
:total-count="totalCount"
class="mt-4"
/>
<FlashcardCreateDialog
v-if="selectedDeck"
ref="flashcardCreateDialog"
:flashcard-deck-id="selectedDeck.id"
@created="refreshFlashcards"
/>
</template>
<div
v-else
class="d-flex align-center justify-center h-100 text-medium-emphasis"
>
Select a deck to view its flashcards
</div>
</v-col>
</v-row>
</template>
<script setup lang="ts">
import { computed, ref } from "vue"
import useBreadcrumbs from "@/use/use-breadcrumbs"
import useFlashcards from "@/use/use-flashcards"
import useRouteQueryPagination from "@/use/utils/use-route-query-pagination"
import flashcardDecksApi from "@/api/flashcard-decks-api"
import FlashcardDeckTree, {
type DeckNode,
} from "@/components/flashcard-decks/FlashcardDeckTree.vue"
import FlashcardCard from "@/components/flashcards/FlashcardCard.vue"
import FlashcardCreateDialog from "@/components/flashcards/FlashcardCreateDialog.vue"
import FlashcardDeckStartReviewBtn from "@/components/flashcard-decks/FlashcardDeckStartReviewBtn.vue"
import EnhancedPagination from "@/components/common/EnhancedPagination.vue"
const deckTree = ref<InstanceType<typeof FlashcardDeckTree> | null>(null)
const selectedDeck = ref<DeckNode | null>(null)
const flashcardCreateDialog = ref<InstanceType<typeof FlashcardCreateDialog> | null>(null)
const { page, perPage } = useRouteQueryPagination({ perPage: 4 })
const flashcardsQueryOptions = computed(() => ({
where: { flashcardDeckId: selectedDeck.value?.id },
page: page.value,
perPage: perPage.value,
}))
const {
flashcards,
totalCount,
refresh: refreshFlashcards,
} = useFlashcards(flashcardsQueryOptions, {
skipWatchIf: () => selectedDeck.value === null,
})
function onDeckSelected(deck: DeckNode) {
selectedDeck.value = deck
}
function onDeckDeleted(flashcardDeckId: number) {
if (selectedDeck.value?.id !== flashcardDeckId) {
return
}
selectedDeck.value = null
}
async function onDeckUpdated(flashcardDeckId: number) {
if (selectedDeck.value?.id !== flashcardDeckId) {
return
}
const { flashcardDeck } = await flashcardDecksApi.get(flashcardDeckId)
selectedDeck.value = { ...selectedDeck.value, ...flashcardDeck }
}
function openFlashcardCreateDialog() {
flashcardCreateDialog.value?.show()
}
useBreadcrumbs("Flashcards", [
{
title: "Flashcards",
to: {
name: "FlashcardsPage",
},
},
])
</script>