feat: implement user profile page with statistics, contribution map, and activity timeline

- Add userService for profile and activity API calls
- Create UserProfilePage with tabbed interface (overview, reports, events, activity)
- Display user statistics (reports count, events count, impact score)
- Implement personal contribution map showing all user report locations
- Add activity timeline with different activity types
- Enable profile editing for own profile (first name, last name, username)
- Update UserProfile component to link to profile page
- Add /profile/:userId route to App
- Install react-leaflet for map integration
- Requirements: 6.3, 6.4, 6.5
This commit is contained in:
2025-11-16 21:13:26 +00:00
parent 5cbdb8f284
commit f02f23e185
10 changed files with 728 additions and 5 deletions

View File

@@ -0,0 +1,66 @@
// User service for profile and user-related API calls
import { apiClient } from './api';
import type { User, Report, CleanupEvent } from '@/types';
export interface UserProfile extends User {
reportCount: number;
eventCount: number;
}
export interface UserActivity {
id: string;
type: 'report' | 'event_created' | 'event_attended' | 'event_completed';
timestamp: Date;
title: string;
description?: string;
location?: {
latitude: number;
longitude: number;
locationName?: string;
};
}
export interface UpdateProfileDTO {
firstName?: string;
lastName?: string;
username?: string;
notificationEmail?: boolean;
notificationInApp?: boolean;
}
export const userService = {
/**
* Get user profile by ID
*/
async getProfile(userId: string): Promise<UserProfile> {
return apiClient.get<UserProfile>(`/users/${userId}`);
},
/**
* Update user profile
*/
async updateProfile(userId: string, data: UpdateProfileDTO): Promise<User> {
return apiClient.patch<User>(`/users/${userId}`, data);
},
/**
* Get user's reports
*/
async getUserReports(userId: string): Promise<Report[]> {
return apiClient.get<Report[]>(`/users/${userId}/reports`);
},
/**
* Get user's events (created and attended)
*/
async getUserEvents(userId: string): Promise<CleanupEvent[]> {
return apiClient.get<CleanupEvent[]>(`/users/${userId}/events`);
},
/**
* Get user's activity timeline
*/
async getUserActivity(userId: string): Promise<UserActivity[]> {
return apiClient.get<UserActivity[]>(`/users/${userId}/activity`);
},
};