integrate need review cards
This commit is contained in:
@@ -3,7 +3,7 @@ import { ref } from 'vue'
|
||||
import { Card } from '../models/Card'
|
||||
|
||||
defineProps<{ card: Card }>()
|
||||
const emit = defineEmits<{ success: []; fail: [] }>()
|
||||
const emit = defineEmits<{ success: []; fail: []; needsReview: [] }>()
|
||||
|
||||
const flipped = ref(false)
|
||||
const flip = () => {
|
||||
@@ -11,8 +11,8 @@ const flip = () => {
|
||||
}
|
||||
|
||||
const success = () => emit('success')
|
||||
|
||||
const fail = () => emit('fail')
|
||||
const needsReview = () => emit('needsReview')
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -27,8 +27,13 @@ const fail = () => emit('fail')
|
||||
<div class="actions">
|
||||
<p>Did you remember this?</p>
|
||||
<div class="buttons is-centered">
|
||||
<div class="button is-warning" @click.stop="fail">failed</div>
|
||||
<div class="button is-success" @click.stop="success">got it</div>
|
||||
<button class="button is-warning" @click.stop="fail">failed</button>
|
||||
<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>
|
||||
|
||||
@@ -7,6 +7,7 @@ const props = defineProps<{ cards: Repetition[] }>()
|
||||
const emits = defineEmits<{
|
||||
success: [id: string]
|
||||
fail: [id: string]
|
||||
needsReview: [id: string]
|
||||
}>()
|
||||
|
||||
const cards = ref(
|
||||
@@ -32,6 +33,12 @@ const goToNextCard = (success: boolean) => {
|
||||
|
||||
currentIndex.value++
|
||||
}
|
||||
|
||||
const needsReview = () => {
|
||||
const id = cards.value[currentIndex.value].repetition._id ?? ''
|
||||
emits('needsReview', id)
|
||||
currentIndex.value++
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -52,6 +59,7 @@ const goToNextCard = (success: boolean) => {
|
||||
:card="card.card"
|
||||
@success="goToNextCard(true)"
|
||||
@fail="goToNextCard(false)"
|
||||
@needs-review="needsReview"
|
||||
/>
|
||||
</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
|
||||
|
||||
import { DataType } from '@/data/DataType.enum'
|
||||
import { data } from '@/data/data'
|
||||
import { DataType } from '@/data/DataType.enum'
|
||||
import { useFile } from '@/hooks/useFile.hook'
|
||||
import { useLinks } from '@/hooks/useLinks.hook'
|
||||
import { useMarkdown } from '@/hooks/useMarkdown.hook'
|
||||
@@ -53,12 +53,14 @@ export const useSpacedRepetitionCards = () => {
|
||||
>(data.generateId(DataType.RepetitionCard, cardFile.path), {
|
||||
$type: DataType.RepetitionCard,
|
||||
level: 1,
|
||||
repeatDate: new Date()
|
||||
repeatDate: new Date(),
|
||||
needsReview: false
|
||||
})
|
||||
|
||||
if (
|
||||
isAfter(new Date(repetition.repeatDate), new Date()) ||
|
||||
repetition.level === MAX_LEVEL
|
||||
repetition.level === MAX_LEVEL ||
|
||||
repetition.needsReview
|
||||
) {
|
||||
continue
|
||||
}
|
||||
@@ -95,6 +97,7 @@ export const useSpacedRepetitionCards = () => {
|
||||
|
||||
await data.update<DataType.RepetitionCard, RepetitionCard>({
|
||||
...repetition,
|
||||
needsReview: false,
|
||||
level: Math.min(repetition.level + 1, MAX_LEVEL),
|
||||
repeatDate: addDays(new Date(), 2 ** repetition.level)
|
||||
})
|
||||
@@ -113,10 +116,25 @@ export const useSpacedRepetitionCards = () => {
|
||||
await data.update<DataType.RepetitionCard, RepetitionCard>({
|
||||
...repetition,
|
||||
level,
|
||||
needsReview: false,
|
||||
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(
|
||||
cards,
|
||||
() =>
|
||||
@@ -128,5 +146,11 @@ export const useSpacedRepetitionCards = () => {
|
||||
|
||||
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> {
|
||||
level: number
|
||||
repeatDate: Date
|
||||
needsReview: boolean
|
||||
}
|
||||
|
||||
42
src/modules/repo/services/resolvePath.spec.ts
Normal file
42
src/modules/repo/services/resolvePath.spec.ts
Normal file
@@ -0,0 +1,42 @@
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import { resolvePath } from './resolvePath'
|
||||
|
||||
describe('resolve path service', () => {
|
||||
it('set the absolute path if path to resolve is empty', () => {
|
||||
expect(resolvePath('standard/README.md', '')).toEqual('standard/')
|
||||
})
|
||||
|
||||
it('returns the path sanitized if there is no absolute path', () => {
|
||||
expect(resolvePath('', './here/note.md')).toEqual('here/note.md')
|
||||
})
|
||||
|
||||
it('set the absolute path from the current path', () => {
|
||||
expect(resolvePath('standard/README.md', './other-note.md')).toEqual(
|
||||
'standard/other-note.md'
|
||||
)
|
||||
})
|
||||
|
||||
it('set the absolute path from the current path with multiple level', () => {
|
||||
expect(
|
||||
resolvePath('standard/you/are/here/README.md', './other-note.md')
|
||||
).toEqual('standard/you/are/here/other-note.md')
|
||||
})
|
||||
|
||||
it('set the absolute path from the current path with a go back in the relative path', () => {
|
||||
expect(
|
||||
resolvePath('standard/you/are/here/README.md', '../other-note.md')
|
||||
).toEqual('standard/you/are/other-note.md')
|
||||
|
||||
expect(
|
||||
resolvePath('standard/you/are/here/README.md', '../../other-note.md')
|
||||
).toEqual('standard/you/other-note.md')
|
||||
|
||||
expect(
|
||||
resolvePath('standard/you/are/here/README.md', './../../other-note.md')
|
||||
).toEqual('standard/you/other-note.md')
|
||||
|
||||
expect(
|
||||
resolvePath('standard/you/are/here/README.md', './../../../other-note.md')
|
||||
).toEqual('standard/other-note.md')
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user