feat: Tier 1 & 2 — Daily Note, Voice, Flashcard quota, Readwise, Calendar, Agent Gallery
Tier 1: - BASIC tier: chat (10/mo) + reformulate (10/mo) désormais accessibles - Nouveaux quotas: ai_flashcard + voice_transcribe dans tous les tiers - /api/notes/daily : note du jour auto-créée (find or create) - Bouton Note du Jour dans la sidebar (CalendarDays) - Voice-to-Text dans l'éditeur (Web Speech API, bouton Mic toolbar) - Flashcard generation → quota ai_flashcard (au lieu de reformulate) Tier 2: - Intégration Readwise: GET/POST/DELETE /api/integrations/readwise - Intégration Google Calendar: OAuth flow + today's events + meeting notes - /api/integrations/calendar + /callback - Page /settings/integrations avec cards Calendar + Readwise - SettingsNav: onglet Intégrations - AgentTemplates: catégories + 4 nouveaux templates (Digest/Recap/AutoTagger/Synthesis) Schema: - UserAISettings.integrationTokens Json? (migration 20260529160000) - prisma generate + migrate deploy appliqués Fix: - SpeechRecognition types (triple-slash @types/dom-speech-recognition) - Notebook.create: suppression champ 'description' inexistant Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
@@ -12,6 +12,7 @@ import {
|
||||
BookMarked,
|
||||
Bot,
|
||||
Inbox,
|
||||
CalendarDays,
|
||||
FlaskConical,
|
||||
ArrowUpDown,
|
||||
Archive,
|
||||
@@ -764,6 +765,21 @@ export function Sidebar({ className, user }: { className?: string; user?: any })
|
||||
router.push('/home?forceList=1')
|
||||
}
|
||||
|
||||
const handleDailyNoteClick = async () => {
|
||||
try {
|
||||
const res = await fetch('/api/notes/daily')
|
||||
const data = await res.json()
|
||||
if (data.success && data.note) {
|
||||
const params = new URLSearchParams()
|
||||
if (data.note.notebookId) params.set('notebook', data.note.notebookId)
|
||||
params.set('openNote', data.note.id)
|
||||
router.push(`/home?${params.toString()}`)
|
||||
}
|
||||
} catch {
|
||||
toast.error(t('sidebar.dailyNoteError') || 'Impossible d\'ouvrir la note du jour')
|
||||
}
|
||||
}
|
||||
|
||||
const handleNoteClick = (noteId: string, notebookId: string) => {
|
||||
const params = new URLSearchParams(searchParams.toString())
|
||||
params.set('notebook', notebookId)
|
||||
@@ -1379,6 +1395,19 @@ export function Sidebar({ className, user }: { className?: string; user?: any })
|
||||
</span>
|
||||
</button>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
onClick={handleDailyNoteClick}
|
||||
className="sidebar-inbox-item"
|
||||
>
|
||||
<div className="w-8 h-8 rounded-full flex items-center justify-center text-sm font-medium border shrink-0 bg-paper dark:bg-white/5 text-muted-ink border-border">
|
||||
<CalendarDays size={14} />
|
||||
</div>
|
||||
<span className="text-[13px] font-medium truncate text-muted-ink">
|
||||
{t('sidebar.dailyNote') || 'Note du jour'}
|
||||
</span>
|
||||
</button>
|
||||
|
||||
<div className="my-3 h-px bg-border/40" />
|
||||
|
||||
<div
|
||||
|
||||
Reference in New Issue
Block a user