dramaling-vocab-learning/frontend/lib/utils/flashcardUtils.ts

107 lines
3.5 KiB
TypeScript

/**
* Flashcard 相關工具函數
* 統一管理詞卡相關的顯示和處理邏輯
*/
// 詞性簡寫轉換
export const getPartOfSpeechDisplay = (partOfSpeech: string): string => {
const shortMap: {[key: string]: string} = {
'noun': 'n.',
'verb': 'v.',
'adjective': 'adj.',
'adverb': 'adv.',
'pronoun': 'pron.',
'conjunction': 'conj.',
'preposition': 'prep.',
'interjection': 'int.',
'idiom': 'idiom'
}
// 處理複合詞性 (如 "preposition/adverb")
if (partOfSpeech?.includes('/')) {
return partOfSpeech.split('/').map(p => shortMap[p.trim()] || p.trim()).join('/')
}
return shortMap[partOfSpeech] || partOfSpeech || ''
}
// CEFR等級顏色獲取
export const getCEFRColor = (level: string): string => {
switch (level) {
case 'A1': return 'bg-green-100 text-green-700 border-green-200'
case 'A2': return 'bg-blue-100 text-blue-700 border-blue-200'
case 'B1': return 'bg-yellow-100 text-yellow-700 border-yellow-200'
case 'B2': return 'bg-orange-100 text-orange-700 border-orange-200'
case 'C1': return 'bg-red-100 text-red-700 border-red-200'
case 'C2': return 'bg-purple-100 text-purple-700 border-purple-200'
default: return 'bg-gray-100 text-gray-700 border-gray-200'
}
}
// 熟練度等級顏色獲取
export const getMasteryColor = (level: number): string => {
if (level >= 90) return 'bg-green-100 text-green-800'
if (level >= 70) return 'bg-yellow-100 text-yellow-800'
if (level >= 50) return 'bg-orange-100 text-orange-800'
return 'bg-red-100 text-red-800'
}
// 熟練度等級文字
export const getMasteryText = (level: number): string => {
if (level >= 90) return '精通'
if (level >= 70) return '熟悉'
if (level >= 50) return '理解'
return '學習中'
}
// 下次複習時間格式化
export const formatNextReviewDate = (dateString: string): string => {
const reviewDate = new Date(dateString)
const now = new Date()
const diffInDays = Math.ceil((reviewDate.getTime() - now.getTime()) / (1000 * 60 * 60 * 24))
if (diffInDays < 0) return '需要複習'
if (diffInDays === 0) return '今天'
if (diffInDays === 1) return '明天'
return `${diffInDays}天後`
}
// 詞卡創建時間格式化
export const formatCreatedDate = (dateString: string): string => {
return new Date(dateString).toLocaleDateString('zh-TW')
}
// 獲取例句圖片URL (統一邏輯)
export const getFlashcardImageUrl = (flashcard: any): string | null => {
// 優先使用 primaryImageUrl
if (flashcard.primaryImageUrl) {
return flashcard.primaryImageUrl
}
// 然後檢查 exampleImages 陣列
if (flashcard.exampleImages && flashcard.exampleImages.length > 0) {
const primaryImage = flashcard.exampleImages.find((img: any) => img.isPrimary)
if (primaryImage) return primaryImage.imageUrl
return flashcard.exampleImages[0].imageUrl
}
return null
}
// 詞卡統計計算
export const calculateFlashcardStats = (flashcards: any[]) => {
const total = flashcards.length
const mastered = flashcards.filter(card => card.masteryLevel >= 80).length
const learning = flashcards.filter(card => card.masteryLevel >= 40 && card.masteryLevel < 80).length
const new_cards = flashcards.filter(card => card.masteryLevel < 40).length
const favorites = flashcards.filter(card => card.isFavorite).length
return {
total,
mastered,
learning,
new: new_cards,
favorites,
masteryPercentage: total > 0 ? Math.round((mastered / total) * 100) : 0
}
}