Implement filtering and sorting functionality
- Add getItemsByFilter server action with support for: - Priority filtering (low, medium, high) - Completed status filtering - Tag filtering with compound AND logic - Due date range filtering - Sorting by createdAt, dueDate, priority, and title - Ascending and descending sort order - Handle null due dates in sorting (placed at end) - Implement compound filter logic with AND conditions - Requirements: 6.1, 6.2, 6.3, 6.5
This commit is contained in:
106
lib/actions.ts
106
lib/actions.ts
@@ -178,8 +178,8 @@ export async function searchItems(query: string, listId?: string) {
|
||||
|
||||
const tagMatches = allItems.filter((item) => {
|
||||
const tags = Array.isArray(item.tags) ? item.tags : []
|
||||
return tags.some((tag: string) =>
|
||||
tag.toLowerCase().includes(searchTerm)
|
||||
return tags.some((tag) =>
|
||||
typeof tag === 'string' && tag.toLowerCase().includes(searchTerm)
|
||||
)
|
||||
})
|
||||
|
||||
@@ -190,4 +190,106 @@ export async function searchItems(query: string, listId?: string) {
|
||||
)
|
||||
|
||||
return uniqueResults
|
||||
}
|
||||
|
||||
export async function getItemsByFilter(
|
||||
listId: string | null,
|
||||
filters: {
|
||||
priority?: 'low' | 'medium' | 'high' | null
|
||||
completed?: boolean | null
|
||||
tags?: string[]
|
||||
dueDateRange?: { start: Date | null; end: Date | null }
|
||||
sortBy?: 'createdAt' | 'dueDate' | 'priority' | 'title'
|
||||
sortOrder?: 'asc' | 'desc'
|
||||
} = {}
|
||||
) {
|
||||
// Build the where clause with compound filters (AND logic)
|
||||
const whereClause: any = {}
|
||||
|
||||
// Add list scope if specified
|
||||
if (listId) {
|
||||
whereClause.listId = listId
|
||||
}
|
||||
|
||||
// Filter by priority
|
||||
if (filters.priority) {
|
||||
whereClause.priority = filters.priority
|
||||
}
|
||||
|
||||
// Filter by completed status
|
||||
if (filters.completed !== undefined && filters.completed !== null) {
|
||||
whereClause.completed = filters.completed
|
||||
}
|
||||
|
||||
// Filter by due date range
|
||||
if (filters.dueDateRange) {
|
||||
const { start, end } = filters.dueDateRange
|
||||
if (start || end) {
|
||||
whereClause.dueDate = {}
|
||||
if (start) {
|
||||
whereClause.dueDate.gte = start
|
||||
}
|
||||
if (end) {
|
||||
whereClause.dueDate.lte = end
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Fetch items from database
|
||||
const items = await prisma.item.findMany({
|
||||
where: whereClause,
|
||||
include: {
|
||||
list: true,
|
||||
},
|
||||
})
|
||||
|
||||
// Filter by tags (client-side since tags are stored as JSON)
|
||||
let filteredItems = items
|
||||
if (filters.tags && filters.tags.length > 0) {
|
||||
filteredItems = items.filter((item) => {
|
||||
const itemTags = Array.isArray(item.tags) ? item.tags : []
|
||||
return filters.tags!.every((filterTag) =>
|
||||
itemTags.some((itemTag) => typeof itemTag === 'string' && itemTag === filterTag)
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
// Sort items
|
||||
const sortBy = filters.sortBy || 'createdAt'
|
||||
const sortOrder = filters.sortOrder || 'desc'
|
||||
|
||||
const sortedItems = [...filteredItems].sort((a, b) => {
|
||||
let comparison = 0
|
||||
|
||||
switch (sortBy) {
|
||||
case 'createdAt':
|
||||
comparison = a.createdAt.getTime() - b.createdAt.getTime()
|
||||
break
|
||||
case 'dueDate':
|
||||
// Handle null due dates - place at end
|
||||
if (a.dueDate === null && b.dueDate === null) {
|
||||
comparison = 0
|
||||
} else if (a.dueDate === null) {
|
||||
comparison = 1 // a goes after b
|
||||
} else if (b.dueDate === null) {
|
||||
comparison = -1 // b goes after a
|
||||
} else {
|
||||
comparison = a.dueDate.getTime() - b.dueDate.getTime()
|
||||
}
|
||||
break
|
||||
case 'priority':
|
||||
const priorityOrder = { low: 1, medium: 2, high: 3 }
|
||||
const aPriority = priorityOrder[a.priority as keyof typeof priorityOrder] || 2
|
||||
const bPriority = priorityOrder[b.priority as keyof typeof priorityOrder] || 2
|
||||
comparison = aPriority - bPriority
|
||||
break
|
||||
case 'title':
|
||||
comparison = a.title.localeCompare(b.title)
|
||||
break
|
||||
}
|
||||
|
||||
return sortOrder === 'asc' ? comparison : -comparison
|
||||
})
|
||||
|
||||
return sortedItems
|
||||
}
|
||||
Reference in New Issue
Block a user