Split the Dashboard from All Tasks. (#10)

Reviewed-on: #10
Co-authored-by: Drew Galbraith <drew@tiramisu.one>
Co-committed-by: Drew Galbraith <drew@tiramisu.one>
This commit is contained in:
Drew 2025-09-24 01:02:23 +00:00 committed by Drew
parent b0916990fb
commit 8e6ac03f70
10 changed files with 572 additions and 23 deletions

View file

@ -25,6 +25,8 @@ import {
DialogContent,
DialogContentText,
DialogActions,
TableSortLabel,
Tooltip,
} from '@mui/material'
import { Delete as DeleteIcon } from '@mui/icons-material'
import { useTasks } from '~/hooks/useTasks'
@ -122,6 +124,19 @@ export function TaskList({ className, initialTasks }: TaskListProps) {
return `${Math.floor(diffInDays / 365)}y ago`
}
const formatFullTimestamp = (dateString: string) => {
const date = new Date(dateString)
return date.toLocaleString(undefined, {
year: 'numeric',
month: 'long',
day: 'numeric',
hour: '2-digit',
minute: '2-digit',
second: '2-digit',
timeZoneName: 'short',
})
}
const handleSelectAll = (checked: boolean) => {
if (checked) {
setSelectedTaskIds(new Set(filteredAndSortedTasks.map(task => task.id)))
@ -165,6 +180,43 @@ export function TaskList({ className, initialTasks }: TaskListProps) {
}
}
const handleSort = (field: string) => {
let newSortBy: SortOption
switch (field) {
case 'title':
newSortBy = sortBy === 'title_asc' ? 'title_desc' : 'title_asc'
break
case 'status':
newSortBy = 'status'
break
case 'created':
newSortBy = sortBy === 'created_asc' ? 'created_desc' : 'created_asc'
break
default:
return
}
setSortBy(newSortBy)
}
const getSortDirection = (field: string): 'asc' | 'desc' | false => {
switch (field) {
case 'title':
if (sortBy === 'title_asc') return 'asc'
if (sortBy === 'title_desc') return 'desc'
return false
case 'status':
return sortBy === 'status' ? 'asc' : false
case 'created':
if (sortBy === 'created_asc') return 'asc'
if (sortBy === 'created_desc') return 'desc'
return false
default:
return false
}
}
const isAllSelected =
filteredAndSortedTasks.length > 0 &&
filteredAndSortedTasks.every(task => selectedTaskIds.has(task.id))
@ -287,15 +339,35 @@ export function TaskList({ className, initialTasks }: TaskListProps) {
}}
/>
</TableCell>
<TableCell sx={{ fontWeight: 'bold' }}>Title</TableCell>
<TableCell sx={{ fontWeight: 'bold' }}>
<TableSortLabel
active={getSortDirection('title') !== false}
direction={getSortDirection('title') || 'asc'}
onClick={() => handleSort('title')}
>
Title
</TableSortLabel>
</TableCell>
{!isMobile && (
<TableCell sx={{ fontWeight: 'bold' }}>Description</TableCell>
)}
<TableCell sx={{ fontWeight: 'bold', width: 100 }}>
Status
<TableSortLabel
active={getSortDirection('status') !== false}
direction={getSortDirection('status') || 'asc'}
onClick={() => handleSort('status')}
>
Status
</TableSortLabel>
</TableCell>
<TableCell sx={{ fontWeight: 'bold', width: 120 }}>
Created
<TableSortLabel
active={getSortDirection('created') !== false}
direction={getSortDirection('created') || 'asc'}
onClick={() => handleSort('created')}
>
Created
</TableSortLabel>
</TableCell>
{!isMobile && (
<TableCell sx={{ fontWeight: 'bold', width: 120 }}>
@ -383,17 +455,41 @@ export function TaskList({ className, initialTasks }: TaskListProps) {
/>
</TableCell>
<TableCell>
<Typography variant="body2" color="text.secondary">
{formatCompactDate(task.created_at)}
</Typography>
<Tooltip
title={formatFullTimestamp(task.created_at)}
arrow
placement="top"
>
<Typography
variant="body2"
color="text.secondary"
sx={{ cursor: 'help' }}
>
{formatCompactDate(task.created_at)}
</Typography>
</Tooltip>
</TableCell>
{!isMobile && (
<TableCell>
<Typography variant="body2" color="text.secondary">
{task.completed_at
? formatCompactDate(task.completed_at)
: '—'}
</Typography>
{task.completed_at ? (
<Tooltip
title={formatFullTimestamp(task.completed_at)}
arrow
placement="top"
>
<Typography
variant="body2"
color="text.secondary"
sx={{ cursor: 'help' }}
>
{formatCompactDate(task.completed_at)}
</Typography>
</Tooltip>
) : (
<Typography variant="body2" color="text.secondary">
</Typography>
)}
</TableCell>
)}
</TableRow>