Create a TaskList for the home page. (#8)

This task list can display tasks and delete them currently.

Reviewed-on: #8
Co-authored-by: Drew Galbraith <drew@tiramisu.one>
Co-committed-by: Drew Galbraith <drew@tiramisu.one>
This commit is contained in:
Drew 2025-09-23 04:39:29 +00:00 committed by Drew
parent d60d834f38
commit a683a071d1
8 changed files with 526 additions and 37 deletions

25
frontend/app/routes/$.tsx Normal file
View file

@ -0,0 +1,25 @@
import { redirect } from 'react-router'
import type { Route } from './+types/$'
export async function loader({ request }: Route.LoaderArgs) {
const url = new URL(request.url)
// Handle React DevTools and other development files
if (
url.pathname.endsWith('.js.map') ||
url.pathname.includes('installHook') ||
url.pathname.startsWith('/__') ||
url.pathname.startsWith('/node_modules/')
) {
// Return a 404 response for these dev-only requests
throw new Response('Not Found', { status: 404 })
}
// For any other unmatched routes, redirect to home
return redirect('/')
}
export default function CatchAll() {
// This component should never render since we always redirect or throw
return null
}

View file

@ -4,13 +4,12 @@ import Home from './home'
describe('Home component', () => {
it('should render task management interface', () => {
render(<Home />)
expect(screen.getByText(/Tasks/i)).toBeInTheDocument()
const mockLoaderData = { tasks: [] }
render(<Home loaderData={mockLoaderData} />)
expect(
screen.getByText(/GTD-inspired task management system/i)
).toBeInTheDocument()
expect(
screen.getByText(/Task Management Interface Coming Soon/i)
screen.getByRole('heading', { level: 1, name: /Tasks/i })
).toBeInTheDocument()
// TaskList component should be rendered with empty state
expect(screen.getByText(/No tasks found/i)).toBeInTheDocument()
})
})

View file

@ -1,43 +1,46 @@
import type { Route } from './+types/home'
import { Box, Typography, Container } from '@mui/material'
import { TaskList } from '~/components/TaskList'
import type { Task } from '~/types/task'
export function meta(_: Route.MetaArgs) {
return [
{ title: "Captain's Log - Tasks" },
{ name: 'description', content: 'GTD-inspired task management system' },
{ name: 'description', content: 'Task Dashboard' },
]
}
export default function Home() {
export async function loader(): Promise<{ tasks: Task[] }> {
try {
// Fetch tasks from the backend API during SSR
const apiUrl = process.env.API_URL || 'http://localhost:3000'
const response = await fetch(`${apiUrl}/api/tasks`, {
headers: {
'Content-Type': 'application/json',
},
})
if (!response.ok) {
console.error('Failed to fetch tasks:', response.statusText)
return { tasks: [] }
}
const tasks = await response.json()
return { tasks }
} catch (error) {
console.error('Error fetching tasks during SSR:', error)
return { tasks: [] }
}
}
export default function Home({ loaderData }: Route.ComponentProps) {
return (
<Container maxWidth="lg">
<Box sx={{ py: 4 }}>
<Typography variant="h1" component="h1" gutterBottom>
Tasks
</Typography>
<Typography variant="body1" color="text.secondary" sx={{ mb: 4 }}>
Your GTD-inspired task management system. Capture everything, see only
what matters.
</Typography>
<Box
sx={{
p: 4,
textAlign: 'center',
color: 'text.secondary',
border: '2px dashed',
borderColor: 'grey.300',
borderRadius: 2,
}}
>
<Typography variant="h6" gutterBottom>
Task Management Interface Coming Soon
</Typography>
<Typography variant="body2">
The task list, task cards, and quick capture components will be
implemented in the next phase.
</Typography>
</Box>
<TaskList initialTasks={loaderData.tasks} />
</Box>
</Container>
)