3.5 KiB

My Activity Page

Overview

File Path: admin/src/pages/volunteer/MyActivityPage.tsx (137 lines)

Route: /volunteer/activity

Role Requirements: Authenticated users

Purpose: Volunteer activity dashboard showing canvassing statistics and visit history.

Key Features:

  • Statistics cards (Today's Visits, Total Doors, Total Sessions)
  • Outcome breakdown with color-coded tags
  • Visit history table (address, outcome, timestamp)
  • Pagination (20 visits per page)
  • Parallel stats + visits fetch
  • Dark theme (VolunteerLayout)

Features

1. Statistics Cards

<Row gutter={16}>
  <Col xs={24} sm={8}>
    <Card>
      <Statistic
        title="Today's Visits"
        value={stats.todayVisits}
        prefix={<CheckCircleOutlined />}
        valueStyle={{ color: '#52c41a' }}
      />
    </Card>
  </Col>
  
  <Col xs={24} sm={8}>
    <Card>
      <Statistic
        title="Total Doors"
        value={stats.totalDoors}
        prefix={<HomeOutlined />}
        valueStyle={{ color: '#1890ff' }}
      />
    </Card>
  </Col>
  
  <Col xs={24} sm={8}>
    <Card>
      <Statistic
        title="Total Sessions"
        value={stats.totalSessions}
        prefix={<ClockCircleOutlined />}
        valueStyle={{ color: '#722ed1' }}
      />
    </Card>
  </Col>
</Row>

2. Outcome Breakdown

<Card title="Outcome Breakdown">
  <Space wrap>
    <Tag color="green">Strong Support: {outcomes.strongSupport}</Tag>
    <Tag color="blue">Leaning Support: {outcomes.leaningSupport}</Tag>
    <Tag color="yellow">Undecided: {outcomes.undecided}</Tag>
    <Tag color="orange">Leaning Opposed: {outcomes.leaningOpposed}</Tag>
    <Tag color="red">Opposed: {outcomes.opposed}</Tag>
    <Tag color="default">No Answer: {outcomes.noAnswer}</Tag>
    <Tag color="gray">Not Home: {outcomes.notHome}</Tag>
  </Space>
</Card>

3. Visit History Table

<Table
  dataSource={visits}
  columns={[
    {
      title: 'Address',
      dataIndex: 'address',
      key: 'address'
    },
    {
      title: 'Outcome',
      dataIndex: 'outcome',
      key: 'outcome',
      render: (outcome) => (
        <Tag color={getOutcomeColor(outcome)}>
          {outcome.replace('_', ' ')}
        </Tag>
      )
    },
    {
      title: 'Notes',
      dataIndex: 'notes',
      key: 'notes',
      ellipsis: true
    },
    {
      title: 'Time',
      dataIndex: 'createdAt',
      key: 'createdAt',
      render: (date) => dayjs(date).format('MMM D, h:mm A')
    }
  ]}
  pagination={{
    current: page,
    total: total,
    pageSize: 20,
    onChange: setPage
  }}
/>

API Integration

Endpoints

1. Get Stats

GET /api/map/canvass/my-stats
Authorization: Bearer {token}

Response:

{
  "todayVisits": 23,
  "totalDoors": 187,
  "totalSessions": 12,
  "outcomes": {
    "strongSupport": 45,
    "leaningSupport": 32,
    "undecided": 28,
    "leaningOpposed": 15,
    "opposed": 12,
    "noAnswer": 38,
    "notHome": 17
  }
}

2. Get Visit History

GET /api/map/canvass/my-visits?page=1&limit=20
Authorization: Bearer {token}

Response:

{
  "visits": [
    {
      "id": "cm1visit123",
      "address": "123 Main St",
      "outcome": "strong_support",
      "notes": "Very enthusiastic, requested yard sign",
      "createdAt": "2025-02-12T14:30:00.000Z"
    }
  ],
  "total": 187,
  "page": 1
}