integrate need review cards
This commit is contained in:
@@ -32,7 +32,7 @@ const reload = () => {
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="buttons">
|
<div class="buttons">
|
||||||
<button class="button is-primary" v-if="needRefresh" @click="reload">
|
<button v-if="needRefresh" class="button is-primary" @click="reload">
|
||||||
<LiteLoading v-if="isLoading" />
|
<LiteLoading v-if="isLoading" />
|
||||||
<span v-else>Reload</span>
|
<span v-else>Reload</span>
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { ref } from 'vue'
|
|||||||
import { Card } from '../models/Card'
|
import { Card } from '../models/Card'
|
||||||
|
|
||||||
defineProps<{ card: Card }>()
|
defineProps<{ card: Card }>()
|
||||||
const emit = defineEmits<{ success: []; fail: [] }>()
|
const emit = defineEmits<{ success: []; fail: []; needsReview: [] }>()
|
||||||
|
|
||||||
const flipped = ref(false)
|
const flipped = ref(false)
|
||||||
const flip = () => {
|
const flip = () => {
|
||||||
@@ -11,8 +11,8 @@ const flip = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const success = () => emit('success')
|
const success = () => emit('success')
|
||||||
|
|
||||||
const fail = () => emit('fail')
|
const fail = () => emit('fail')
|
||||||
|
const needsReview = () => emit('needsReview')
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@@ -27,8 +27,13 @@ const fail = () => emit('fail')
|
|||||||
<div class="actions">
|
<div class="actions">
|
||||||
<p>Did you remember this?</p>
|
<p>Did you remember this?</p>
|
||||||
<div class="buttons is-centered">
|
<div class="buttons is-centered">
|
||||||
<div class="button is-warning" @click.stop="fail">failed</div>
|
<button class="button is-warning" @click.stop="fail">failed</button>
|
||||||
<div class="button is-success" @click.stop="success">got it</div>
|
<button class="button is-success" @click.stop="success">
|
||||||
|
got it
|
||||||
|
</button>
|
||||||
|
<button class="button is-danger" @click.stop="needsReview">
|
||||||
|
<em>needs review</em>
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ const props = defineProps<{ cards: Repetition[] }>()
|
|||||||
const emits = defineEmits<{
|
const emits = defineEmits<{
|
||||||
success: [id: string]
|
success: [id: string]
|
||||||
fail: [id: string]
|
fail: [id: string]
|
||||||
|
needsReview: [id: string]
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
const cards = ref(
|
const cards = ref(
|
||||||
@@ -32,6 +33,12 @@ const goToNextCard = (success: boolean) => {
|
|||||||
|
|
||||||
currentIndex.value++
|
currentIndex.value++
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const needsReview = () => {
|
||||||
|
const id = cards.value[currentIndex.value].repetition._id ?? ''
|
||||||
|
emits('needsReview', id)
|
||||||
|
currentIndex.value++
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@@ -52,6 +59,7 @@ const goToNextCard = (success: boolean) => {
|
|||||||
:card="card.card"
|
:card="card.card"
|
||||||
@success="goToNextCard(true)"
|
@success="goToNextCard(true)"
|
||||||
@fail="goToNextCard(false)"
|
@fail="goToNextCard(false)"
|
||||||
|
@needs-review="needsReview"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div v-else>No more cards to check!</div>
|
<div v-else>No more cards to check!</div>
|
||||||
|
|||||||
22
src/modules/card/hooks/useNeedReviewCards.ts
Normal file
22
src/modules/card/hooks/useNeedReviewCards.ts
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
import { data } from '@/data/data'
|
||||||
|
import { DataType } from '@/data/DataType.enum'
|
||||||
|
import { RepetitionCard } from '@/modules/card/models/RepetitionCard'
|
||||||
|
import { useAsyncState } from '@vueuse/core'
|
||||||
|
|
||||||
|
export const useNeedReviewCards = () => {
|
||||||
|
const { state: cardsToReview, isReady } = useAsyncState(async () => {
|
||||||
|
const repetitions = await data.getAll<
|
||||||
|
DataType.RepetitionCard,
|
||||||
|
RepetitionCard
|
||||||
|
>({
|
||||||
|
prefix: DataType.RepetitionCard
|
||||||
|
})
|
||||||
|
|
||||||
|
return repetitions.filter((repetition) => repetition.needsReview)
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
return {
|
||||||
|
cardsToReview,
|
||||||
|
isReady
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
// https://npm.io/package/supermemo
|
// https://npm.io/package/supermemo
|
||||||
|
|
||||||
import { DataType } from '@/data/DataType.enum'
|
|
||||||
import { data } from '@/data/data'
|
import { data } from '@/data/data'
|
||||||
|
import { DataType } from '@/data/DataType.enum'
|
||||||
import { useFile } from '@/hooks/useFile.hook'
|
import { useFile } from '@/hooks/useFile.hook'
|
||||||
import { useLinks } from '@/hooks/useLinks.hook'
|
import { useLinks } from '@/hooks/useLinks.hook'
|
||||||
import { useMarkdown } from '@/hooks/useMarkdown.hook'
|
import { useMarkdown } from '@/hooks/useMarkdown.hook'
|
||||||
@@ -53,12 +53,14 @@ export const useSpacedRepetitionCards = () => {
|
|||||||
>(data.generateId(DataType.RepetitionCard, cardFile.path), {
|
>(data.generateId(DataType.RepetitionCard, cardFile.path), {
|
||||||
$type: DataType.RepetitionCard,
|
$type: DataType.RepetitionCard,
|
||||||
level: 1,
|
level: 1,
|
||||||
repeatDate: new Date()
|
repeatDate: new Date(),
|
||||||
|
needsReview: false
|
||||||
})
|
})
|
||||||
|
|
||||||
if (
|
if (
|
||||||
isAfter(new Date(repetition.repeatDate), new Date()) ||
|
isAfter(new Date(repetition.repeatDate), new Date()) ||
|
||||||
repetition.level === MAX_LEVEL
|
repetition.level === MAX_LEVEL ||
|
||||||
|
repetition.needsReview
|
||||||
) {
|
) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@@ -95,6 +97,7 @@ export const useSpacedRepetitionCards = () => {
|
|||||||
|
|
||||||
await data.update<DataType.RepetitionCard, RepetitionCard>({
|
await data.update<DataType.RepetitionCard, RepetitionCard>({
|
||||||
...repetition,
|
...repetition,
|
||||||
|
needsReview: false,
|
||||||
level: Math.min(repetition.level + 1, MAX_LEVEL),
|
level: Math.min(repetition.level + 1, MAX_LEVEL),
|
||||||
repeatDate: addDays(new Date(), 2 ** repetition.level)
|
repeatDate: addDays(new Date(), 2 ** repetition.level)
|
||||||
})
|
})
|
||||||
@@ -113,10 +116,25 @@ export const useSpacedRepetitionCards = () => {
|
|||||||
await data.update<DataType.RepetitionCard, RepetitionCard>({
|
await data.update<DataType.RepetitionCard, RepetitionCard>({
|
||||||
...repetition,
|
...repetition,
|
||||||
level,
|
level,
|
||||||
|
needsReview: false,
|
||||||
repeatDate: addDays(new Date(), level)
|
repeatDate: addDays(new Date(), level)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const needsReview = async (cardId: string) => {
|
||||||
|
const repetition = await data.get<DataType.RepetitionCard, RepetitionCard>(
|
||||||
|
cardId
|
||||||
|
)
|
||||||
|
if (!repetition) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
await data.update<DataType.RepetitionCard, RepetitionCard>({
|
||||||
|
...repetition,
|
||||||
|
needsReview: true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
cards,
|
cards,
|
||||||
() =>
|
() =>
|
||||||
@@ -128,5 +146,11 @@ export const useSpacedRepetitionCards = () => {
|
|||||||
|
|
||||||
watch(cardFiles, () => execute())
|
watch(cardFiles, () => execute())
|
||||||
|
|
||||||
return { cards, successRepetition, failRepetition, isLoading: !isReady }
|
return {
|
||||||
|
cards,
|
||||||
|
successRepetition,
|
||||||
|
failRepetition,
|
||||||
|
needsReview,
|
||||||
|
isLoading: !isReady
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,4 +4,5 @@ import { Model } from '@/data/models/Model'
|
|||||||
export interface RepetitionCard extends Model<DataType.RepetitionCard> {
|
export interface RepetitionCard extends Model<DataType.RepetitionCard> {
|
||||||
level: number
|
level: number
|
||||||
repeatDate: Date
|
repeatDate: Date
|
||||||
|
needsReview: boolean
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { resolvePath } from '@/modules/repo/services/resolvePath'
|
|
||||||
import { describe, expect, it } from 'vitest'
|
import { describe, expect, it } from 'vitest'
|
||||||
|
import { resolvePath } from './resolvePath'
|
||||||
|
|
||||||
describe('resolve path service', () => {
|
describe('resolve path service', () => {
|
||||||
it('set the absolute path if path to resolve is empty', () => {
|
it('set the absolute path if path to resolve is empty', () => {
|
||||||
@@ -43,6 +43,12 @@ const routes: Array<RouteRecordRaw> = [
|
|||||||
props: true,
|
props: true,
|
||||||
component: () => import('@/views/SpacedRepetitionCard.vue')
|
component: () => import('@/views/SpacedRepetitionCard.vue')
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: '/:user/:repo/need-review-cards',
|
||||||
|
name: 'NeedReviewCards',
|
||||||
|
props: true,
|
||||||
|
component: () => import('@/views/NeedReviewCards.vue')
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: '/about',
|
path: '/about',
|
||||||
name: 'About',
|
name: 'About',
|
||||||
|
|||||||
38
src/views/NeedReviewCards.vue
Normal file
38
src/views/NeedReviewCards.vue
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import FluxNote from '@/components/FluxNote.vue'
|
||||||
|
import { DataType } from '@/data/DataType.enum'
|
||||||
|
import { useNeedReviewCards } from '@/modules/card/hooks/useNeedReviewCards'
|
||||||
|
import { computed } from 'vue'
|
||||||
|
|
||||||
|
defineProps<{
|
||||||
|
user: string
|
||||||
|
repo: string
|
||||||
|
}>()
|
||||||
|
|
||||||
|
const { cardsToReview } = useNeedReviewCards()
|
||||||
|
const cardNames = computed(() =>
|
||||||
|
cardsToReview.value.map((card) => ({
|
||||||
|
id: card._id,
|
||||||
|
name: card._id?.split(DataType.RepetitionCard).pop()
|
||||||
|
}))
|
||||||
|
)
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="needs-review-cards">
|
||||||
|
<flux-note
|
||||||
|
key="needs-review-cards"
|
||||||
|
class="card-container"
|
||||||
|
:user="user"
|
||||||
|
:repo="repo"
|
||||||
|
:with-content="false"
|
||||||
|
>
|
||||||
|
needs review cards
|
||||||
|
<ul>
|
||||||
|
<li v-for="card in cardNames" :key="card.id">
|
||||||
|
{{ card.name }}
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</flux-note>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
@@ -8,7 +8,7 @@ defineProps<{
|
|||||||
repo: string
|
repo: string
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
const { cards, isLoading, successRepetition, failRepetition } =
|
const { cards, isLoading, successRepetition, failRepetition, needsReview } =
|
||||||
useSpacedRepetitionCards()
|
useSpacedRepetitionCards()
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -27,9 +27,13 @@ const { cards, isLoading, successRepetition, failRepetition } =
|
|||||||
:cards="cards"
|
:cards="cards"
|
||||||
@success="successRepetition"
|
@success="successRepetition"
|
||||||
@fail="failRepetition"
|
@fail="failRepetition"
|
||||||
|
@needs-review="needsReview"
|
||||||
/>
|
/>
|
||||||
</section>
|
</section>
|
||||||
<section v-else>No cards to review!</section>
|
<section v-else>No cards to review!</section>
|
||||||
|
<router-link :to="{ name: 'NeedReviewCards', params: { user, repo } }">
|
||||||
|
needs review cards
|
||||||
|
</router-link>
|
||||||
</flux-note>
|
</flux-note>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -18,12 +18,6 @@
|
|||||||
},
|
},
|
||||||
"lib": ["esnext", "dom", "dom.iterable", "scripthost", "ES2015"]
|
"lib": ["esnext", "dom", "dom.iterable", "scripthost", "ES2015"]
|
||||||
},
|
},
|
||||||
"include": [
|
"include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"],
|
||||||
"src/**/*.ts",
|
|
||||||
"src/**/*.tsx",
|
|
||||||
"src/**/*.vue",
|
|
||||||
"tests/**/*.ts",
|
|
||||||
"tests/**/*.tsx"
|
|
||||||
],
|
|
||||||
"exclude": ["node_modules"]
|
"exclude": ["node_modules"]
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user