feat: implement performance optimizations
- Add database indexes for frequently queried fields (listId, completed, priority, dueDate, createdAt) - Add compound indexes for common query patterns (listId+completed, listId+priority) - Implement pagination support in getItemsByFilter with configurable page size (default 50) - Optimize components with React.memo (ItemCard, ListCard, FilterPanel, SearchBar, SearchResults, EmptyState) - Configure Next.js for better bundle optimization: - Enable optimizePackageImports for lucide-react - Enable SWC minification - Remove console logs in production (except errors/warnings) - Optimize images with AVIF/WebP formats - Enable compression - Disable production source maps for smaller bundles - Loading states already implemented to prevent layout shift Task 18 complete - all performance optimizations implemented
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
'use client'
|
||||
|
||||
import { ReactNode } from 'react'
|
||||
import { memo, ReactNode } from 'react'
|
||||
import { Inbox, ListTodo, Search, Filter } from 'lucide-react'
|
||||
|
||||
interface EmptyStateProps {
|
||||
@@ -10,7 +10,7 @@ interface EmptyStateProps {
|
||||
action?: ReactNode
|
||||
}
|
||||
|
||||
export default function EmptyState({ icon = 'inbox', title, description, action }: EmptyStateProps) {
|
||||
function EmptyState({ icon = 'inbox', title, description, action }: EmptyStateProps) {
|
||||
const icons = {
|
||||
inbox: <Inbox size={48} className="text-gray-300" />,
|
||||
list: <ListTodo size={48} className="text-gray-300" />,
|
||||
@@ -39,3 +39,5 @@ export default function EmptyState({ icon = 'inbox', title, description, action
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default memo(EmptyState)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
'use client'
|
||||
|
||||
import { useState } from 'react'
|
||||
import { memo, useState } from 'react'
|
||||
import { Filter, X, ChevronDown, ChevronUp } from 'lucide-react'
|
||||
|
||||
export interface FilterState {
|
||||
@@ -19,7 +19,7 @@ interface FilterPanelProps {
|
||||
showListScope?: boolean
|
||||
}
|
||||
|
||||
export default function FilterPanel({
|
||||
function FilterPanel({
|
||||
filters,
|
||||
onFiltersChange,
|
||||
availableTags = [],
|
||||
@@ -294,3 +294,5 @@ export default function FilterPanel({
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default memo(FilterPanel)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
'use client'
|
||||
|
||||
import { memo } from 'react'
|
||||
import Link from 'next/link'
|
||||
import { Calendar, Tag, AlertCircle } from 'lucide-react'
|
||||
import ToggleItemButton from './ToggleItemButton'
|
||||
@@ -19,7 +20,7 @@ interface ItemCardProps {
|
||||
listId: string
|
||||
}
|
||||
|
||||
export default function ItemCard({ item, listId }: ItemCardProps) {
|
||||
function ItemCard({ item, listId }: ItemCardProps) {
|
||||
const tags = Array.isArray(item.tags) ? item.tags : []
|
||||
const isOverdue = item.dueDate && new Date(item.dueDate) < new Date() && !item.completed
|
||||
|
||||
@@ -104,3 +105,5 @@ export default function ItemCard({ item, listId }: ItemCardProps) {
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default memo(ItemCard)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
'use client'
|
||||
|
||||
import { memo, useState } from 'react'
|
||||
import Link from 'next/link'
|
||||
import { useState } from 'react'
|
||||
import { Edit2 } from 'lucide-react'
|
||||
import Modal from './Modal'
|
||||
import ListForm from './ListForm'
|
||||
@@ -17,7 +17,7 @@ interface List {
|
||||
}>
|
||||
}
|
||||
|
||||
export default function ListCard({ list }: { list: List }) {
|
||||
function ListCard({ list }: { list: List }) {
|
||||
const [isEditModalOpen, setIsEditModalOpen] = useState(false)
|
||||
const completedCount = list.items.filter(item => item.completed).length
|
||||
const totalCount = list.items.length
|
||||
@@ -94,4 +94,6 @@ export default function ListCard({ list }: { list: List }) {
|
||||
</Modal>
|
||||
</>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default memo(ListCard)
|
||||
@@ -93,7 +93,9 @@ export default function ListDetailView({ listId, initialItems }: ListDetailViewP
|
||||
sortBy: newFilters.sortBy,
|
||||
sortOrder: newFilters.sortOrder
|
||||
})
|
||||
setFilteredItems(results as Item[])
|
||||
// Extract items from pagination result
|
||||
const items = 'items' in results ? results.items : results
|
||||
setFilteredItems(items as Item[])
|
||||
} catch (error) {
|
||||
console.error('Filter error:', error)
|
||||
setFilteredItems(initialItems)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
'use client'
|
||||
|
||||
import { memo } from 'react'
|
||||
import { Search, X } from 'lucide-react'
|
||||
import { useSearch } from '@/hooks'
|
||||
|
||||
@@ -10,7 +11,7 @@ interface SearchBarProps {
|
||||
initialValue?: string
|
||||
}
|
||||
|
||||
export default function SearchBar({
|
||||
function SearchBar({
|
||||
onSearch,
|
||||
placeholder = 'Search tasks...',
|
||||
debounceMs = 300,
|
||||
@@ -53,3 +54,5 @@ export default function SearchBar({
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default memo(SearchBar)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
'use client'
|
||||
|
||||
import { memo } from 'react'
|
||||
import { highlightText } from '@/lib/utils'
|
||||
import Link from 'next/link'
|
||||
import { Calendar, Tag, AlertCircle } from 'lucide-react'
|
||||
@@ -25,7 +26,7 @@ interface SearchResultsProps {
|
||||
onClose?: () => void
|
||||
}
|
||||
|
||||
export default function SearchResults({ results, query, onClose }: SearchResultsProps) {
|
||||
function SearchResults({ results, query, onClose }: SearchResultsProps) {
|
||||
if (!query.trim()) {
|
||||
return null
|
||||
}
|
||||
@@ -155,3 +156,5 @@ export default function SearchResults({ results, query, onClose }: SearchResults
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default memo(SearchResults)
|
||||
|
||||
Reference in New Issue
Block a user