xiaohongshu
xiaohongshu
calendar-interface-architect
COMPREHENSIVE calendar system skill combining TypeScript interface architecture,
Full skill instructions
This comprehensive skill handles all calendar-related issues in the Pomo-Flow application:
CURRENT COMPILATION ERRORS:
// PROBLEM: Missing properties in CalendarEvent interface
const calendarEvent: CalendarEvent = {
title: 'Task',
date: '2024-01-01',
isDueDate: true // Property does not exist on CalendarEvent
}
// CONSEQUENCE: Calendar functionality breaks, rendering fails
// Comprehensive temporal type system
export interface BaseTemporalEntity {
id: string
title: string
description?: string
createdAt: Date
updatedAt: Date
}
export interface CalendarEvent extends BaseTemporalEntity {
date: string // YYYY-MM-DD format
time?: string // HH:MM format
duration?: number // Duration in minutes
isDueDate: boolean // Whether this represents a task due date
isAllDay: boolean // Whether this is an all-day event
color?: string // Event color for UI
location?: string // Event location
attendees?: string[] // Event attendees
recurrencePattern?: RecurrencePattern
metadata?: Record<string, unknown> // Additional event data
}
export interface TaskCalendarEvent extends CalendarEvent {
taskId: string // Reference to the original task
taskStatus: Task['status']
taskPriority: Task['priority']
taskProgress: number // Task completion progress
subtaskProgress?: number[] // Individual subtask progress
isRecurring: boolean // Whether this is a recurring task instance
parentTaskId?: string // For recurring task instances
instanceId?: string // Unique instance identifier
}
// Complete TaskInstance interface for calendar operations
export interface TaskInstance {
id: string // Unique instance identifier
parentTaskId: string // Reference to original task
scheduledDate: string // YYYY-MM-DD format
scheduledTime?: string // HH:MM format
duration?: number // Duration in minutes
status: 'scheduled' | 'completed' | 'skipped' | 'in_progress'
isRecurring: boolean // True for recurring task instances
isModified?: boolean // True if this instance was modified from pattern
isSkipped?: boolean // True if this instance is skipped
recurrenceExceptionId?: string // Link to exception if this is an exception
pomodoroTracking?: {
completed: number
total: number
duration: number // Duration per pomodoro
}
completionData?: {
completedAt?: Date
completedBy?: string
notes?: string
actualDuration?: number
}
metadata?: Record<string, unknown>
}
// Task factory for calendar instances
export interface TaskInstanceFactory {
createFromTask: (task: Task, date: string, time?: string) => TaskInstance
createRecurringInstance: (task: Task, pattern: RecurrenceRule, date: string) => TaskInstance
createException: (instance: TaskInstance, modifications: Partial<TaskInstance>) => TaskInstance
}
// Calendar-specific state management
export interface CalendarState {
currentDate: Date
selectedDate: Date | null
viewMode: 'month' | 'week' | 'day' | 'agenda'
events: CalendarEvent[]
taskInstances: TaskInstance[]
loading: boolean
error: string | null
filters: CalendarFilters
}
export interface CalendarFilters {
showCompleted: boolean
showInbox: boolean
projectIds: string[]
priorities: Task['priority'][]
statuses: Task['status'][]
}
export interface CalendarActions {
setCurrentDate: (date: Date) => void
setSelectedDate: (date: Date | null) => void
setViewMode: (mode: CalendarState['viewMode']) => void
addEvent: (event: CalendarEvent) => void
removeEvent: (eventId: string) => void
updateEvent: (eventId: string, updates: Partial<CalendarEvent>) => void
loadTaskInstances: (startDate: Date, endDate: Date) => Promise<void>
createTaskInstance: (task: Task, date: string, time?: string) => Promise<void>
}
You're experiencing the classic Vue 3 calendar filtering failure:
taskStore.filteredTasks which applies sidebar filtersRun this diagnostic code in browser console:
// Check calendar vs inbox data discrepancy
async function diagnoseCalendarInboxSync() {
console.group('Calendar-Inbox Sync Diagnosis')
try {
// 1. Check task store state
const taskStore = window.Vue?.config?.globalProperties?.$pinia?._s?.get('tasks')
if (!taskStore) {
console.error('Task store not found')
return
}
const allTasks = taskStore.tasks || []
const filteredTasks = taskStore.filteredTasks || []
console.log(`All tasks: ${allTasks.length}`)
console.log(`Filtered tasks: ${filteredTasks.length}`)
console.log(`Tasks filtered out: ${allTasks.length - filteredTasks.length}`)
// 2. Check inbox vs calendar eligibility
const inboxTasks = allTasks.filter(task =>
task.isInInbox !== false &&
!task.canvasPosition &&
task.status !== 'done'
)
const calendarEligible = allTasks.filter(task => {
const hasInstances = task.instances && task.instances.length > 0
const hasLegacy = task.scheduledDate && task.scheduledTime
return hasInstances || hasLegacy
})
const calendarInboxTasks = allTasks.filter(task =>
task.isInInbox !== false &&
!task.canvasPosition &&
task.status !== 'done' &&
!((task.instances?.length || 0) + ((task.scheduledDate && task.scheduledTime) ? 1 : 0) > 0)
)
console.log(`Inbox tasks: ${inboxTasks.length}`)
console.log(`Calendar scheduled tasks: ${calendarEligible.length}`)
console.log(`Calendar inbox tasks: ${calendarInboxTasks.length}`)
// 3. Identify the problem
console.group('Problem Analysis')
if (inboxTasks.length > 0 && filteredTasks.length === 0) {
console.error('ISSUE: All tasks filtered out - calendar will show 0 tasks')
}
if (filteredTasks.length < allTasks.length) {
console.warn('Sidebar filters are hiding tasks from calendar')
}
console.groupEnd()
return {
allTasks: allTasks.length,
filteredTasks: filteredTasks.length,
inboxTasks: inboxTasks.length,
calendarInboxTasks: calendarInboxTasks.length,
hasIssue: inboxTasks.length > 0 && filteredTasks.length === 0
}
} catch (error) {
console.error('Diagnosis failed:', error)
} finally {
console.groupEnd()
}
}
// Run diagnosis
await diagnoseCalendarInboxSync()
Symptom: Calendar shows 0 tasks when sidebar has active filters
Cause: useCalendarDayView.ts uses taskStore.filteredTasks
Fix: Use taskStore.tasks with calendar-specific filtering
Symptom: Calendar inbox count doesn't match inbox count Cause: Project/smart view filters affect calendar visibility Fix: Calendar should be independent of sidebar filters
Symptom: Tasks disappear when marked as done Cause: Global "hide done" filter affects calendar Fix: Only hide done tasks from calendar timeline, not inbox
// Replace in useCalendarDayView.ts around line 81
// OLD CODE:
const filteredTasks = taskStore.filteredTasks
// NEW CODE:
const calendarTasks = computed(() => {
const allTasks = taskStore.tasks
// Calendar-specific filtering - independent of sidebar
return allTasks.filter(task => {
// Only hide tasks that should never appear in calendar
if (task.status === 'done') return false
// Check if task is scheduled for current date
const hasInstances = task.instances && task.instances.length > 0
const hasLegacy = task.scheduledDate && task.scheduledTime
return hasInstances || hasLegacy
})
})
// In CalendarInboxPanel.vue or similar
const calendarInboxTasks = computed(() => {
const allTasks = taskStore.tasks
return allTasks.filter(task => {
// Task is in inbox and not scheduled
const isInInbox = task.isInInbox !== false && !task.canvasPosition
const isUnscheduled = !((task.instances?.length || 0) + ((task.scheduledDate && task.scheduledTime) ? 1 : 0) > 0)
const isNotDone = task.status !== 'done'
return isInInbox && isUnscheduled && isNotDone
})
})
dueDate field for deadline metadata, stay in inbox until manually scheduledinstances array for time-specific commitments with scheduled dates/timesisInInbox: true) and scheduled stateTask Creation -> Smart Groups -> Calendar Inbox -> Manual Scheduling -> Calendar Grid
| | | | |
New Task dueDate=Today isInInbox=true Create Instance Show in Calendar
// When task is moved to "Today" smart group:
moveTaskToSmartGroup(taskId, 'today') {
const updates = {
dueDate: '2025-11-08', // Set deadline for organization
isInInbox: true, // Keep in inbox for manual scheduling
// CRITICAL: Do NOT create instances
}
updateTask(taskId, updates)
}
// When task is manually scheduled from inbox:
scheduleTaskFromInbox(taskId, date, time) {
// 1. Create calendar instance
createTaskInstance(taskId, {
scheduledDate: date,
scheduledTime: time
})
// 2. Remove from inbox state
updateTask(taskId, { isInInbox: false })
// 3. Task now appears in calendar grid
}
Problem:
// Wrong: Creating calendar events from dueDate
if (task.dueDate === today) {
createCalendarEvent(task) // This should NOT happen
}
Solution:
// Correct: Only create events from instances
if (task.instances?.some(inst => inst.scheduledDate === today)) {
createCalendarEvent(task) // Only for explicitly scheduled tasks
}
Problem:
// Wrong: Task appears in both places
const updates = {
dueDate: today,
isInInbox: true,
instances: [{ scheduledDate: today, scheduledTime: '09:00' }]
}
Solution:
// Correct: Clear state transition
const updates = {
dueDate: today,
isInInbox: false, // Remove from inbox
instances: [{ scheduledDate: today, scheduledTime: '09:00' }]
}
Problem:
// Wrong: Smart group creates time-based scheduling
moveTaskToSmartGroup(taskId, 'today') {
createTaskInstance(taskId, { scheduledDate: today, scheduledTime: '09:00' })
}
Solution:
// Correct: Smart group only sets deadline
moveTaskToSmartGroup(taskId, 'today') {
updateTask(taskId, { dueDate: today })
// Task stays in inbox for manual scheduling
}
// Factory for creating calendar events from different sources
export class CalendarEventFactory {
static fromTask(task: Task, date: string, time?: string): TaskCalendarEvent {
return {
id: generateId(),
title: task.title,
description: task.description,
date,
time,
duration: task.estimatedDuration || 25,
isDueDate: true,
isAllDay: !time,
color: this.getTaskEventColor(task.priority),
taskId: task.id,
taskStatus: task.status,
taskPriority: task.priority,
taskProgress: task.progress,
isRecurring: false,
createdAt: new Date(),
updatedAt: new Date()
}
}
static fromTaskInstance(instance: TaskInstance): TaskCalendarEvent {
const task = taskStore.getTask(instance.parentTaskId)
if (!task) {
throw new Error(`Task not found: ${instance.parentTaskId}`)
}
return {
id: instance.id,
title: task.title,
description: task.description,
date: instance.scheduledDate,
time: instance.scheduledTime,
duration: instance.duration,
isDueDate: true,
isAllDay: !instance.scheduledTime,
color: this.getTaskEventColor(task.priority),
taskId: task.id,
taskStatus: task.status,
taskPriority: task.priority,
taskProgress: task.progress,
isRecurring: instance.isRecurring,
parentTaskId: instance.parentTaskId,
instanceId: instance.id,
createdAt: new Date(),
updatedAt: new Date()
}
}
private static getTaskEventColor(priority: Task['priority']): string {
switch (priority) {
case 'high': return '#ef4444'
case 'medium': return '#f59e0b'
case 'low': return '#10b981'
default: return '#6b7280'
}
}
}
// Pinia store for calendar state with full type safety
export const useCalendarStore = defineStore('calendar', () => {
const state = ref<CalendarState>({
currentDate: new Date(),
selectedDate: null,
viewMode: 'month',
events: [],
taskInstances: [],
loading: false,
error: null,
filters: {
showCompleted: true,
showInbox: true,
projectIds: [],
priorities: [],
statuses: []
}
})
const actions: CalendarActions = {
setCurrentDate: (date: Date) => {
state.value.currentDate = date
},
addEvent: (event: CalendarEvent) => {
state.value.events.push(event)
},
async createTaskInstance(task: Task, date: string, time?: string): Promise<void> {
try {
const instance = taskStore.createTaskInstance(task, date, time)
state.value.taskInstances.push(instance)
} catch (error) {
state.value.error = error instanceof Error ? error.message : 'Failed to create instance'
}
}
}
// Computed properties
const filteredEvents = computed((): TaskCalendarEvent[] => {
return state.value.taskInstances
.filter(instance => passesFilters(instance, state.value.filters))
.map(instance => CalendarEventFactory.fromTaskInstance(instance))
})
return {
state: readonly(state),
actions,
filteredEvents
}
})
// Type-safe date utilities for calendar operations
export class CalendarDateUtils {
static parseDateKey(dateKey: string): Date {
const [year, month, day] = dateKey.split('-').map(Number)
if (isNaN(year) || isNaN(month) || isNaN(day)) {
throw new Error(`Invalid date format: ${dateKey}`)
}
return new Date(year, month - 1, day)
}
static formatDateKey(date: Date): string {
return format(date, 'yyyy-MM-dd')
}
static isValidTime(time: string): boolean {
const timeRegex = /^([01]?[0-9]|2[0-3]):[0-5][0-9]$/
return timeRegex.test(time)
}
static parseTime(time: string): { hours: number; minutes: number } {
if (!this.isValidTime(time)) {
throw new Error(`Invalid time format: ${time}`)
}
const [hours, minutes] = time.split(':').map(Number)
return { hours, minutes }
}
static addTimeToDate(date: string, time: string, duration: number): Date {
const baseDate = this.parseDateKey(date)
const { hours, minutes } = this.parseTime(time)
const result = new Date(baseDate)
result.setHours(hours, minutes, 0, 0)
result.setMinutes(result.getMinutes() + duration)
return result
}
}
Before claiming any fix works, perform these visual tests:
# TypeScript compilation check
npx tsc --noEmit --skipLibCheck
# Calendar-specific tests
npm run test -- --grep "calendar"
# Development server test
npm run dev
See the references/ directory for detailed documentation:
task-calendar-separation.md - Data model separation principlesvue-calendar-best-practices.md - Vue.js calendar implementation patternsAfter successful execution:
CRITICAL: Before claiming ANY issue, bug, or problem is "fixed", "resolved", "working", or "complete", the following verification protocol is MANDATORY:
REQUIRED: Use the AskUserQuestion tool to explicitly ask the user to verify the fix:
"I've implemented [description of fix]. Before I mark this as complete, please verify:
1. [Specific thing to check #1]
2. [Specific thing to check #2]
3. Does this fix the issue you were experiencing?
Please confirm the fix works as expected, or let me know what's still not working."
Remember: The user is the final authority on whether something is fixed. No exceptions.
xiaohongshu
technical spec
product ux expert
database patterns
Conduct multi-agent task orchestration and workflow coordination.
Initialize project with Conductor artifacts (product definition,
Expert in web animations, transitions, and motion design using Framer Motion and CSS
Creates Mermaid and ASCII diagrams for flowcharts, architecture, ERDs, state machines, mindmaps, and more. Use when user mentions diagram, flowchart, mermaid, ASCII diagram, text diagram, terminal diagram, visualize, C4, mindmap, architecture diagram, sequence diagram, ERD, or needs visual docume...
PostgreSQL bindings for H3 hexagonal grid system. Use when working with H3 cells in Postgres, including spatial indexing, geometry/geography integration, and raster analysis.
Context-Driven Development skill for projects using Conductor. Use this skill when you detect a `conductor/` directory in the project, when working on tasks defined in a `plan.md` file, or when the user asks about tracks, specs, or plans. Automatically applies TDD workflow, tracks task completion...
Display project status, active tracks, and next actions
Official Stakpak application containerization standard operating procedure, a step-by-step guidline to properly dockerize applications. This is a rule book curated by the Stakpak Team.
Generate, edit, and beat-sync AI video with leading models in one workspace.
The world's fastest calendar for remote work
Transform Your Design with AI Designer by ImgCreator.ai
Revolutionizing Video Production with AI-Powered Creativity
Extend an image past the frame and let AI fill the new aspect ratio.
Discover your celebrity doppelgänger with StarByFace!
ChainClarity explains 700+ crypto whitepapers in plain English, with layered summaries, comparisons, research tools, alerts, and a $4.99 Pro plan.
Opus.ai: Revolutionize Your Web Experience