veza/apps/web/src/features/profile/services/profileService.ts
senke b33c9d3cca feat(profile): add profile privacy toggle (B3)
- Backend: is_public in Profile, UpdateProfile; strip SocialLinks for private
- Settings: ProfileVisibilityCard toggle in Privacy tab
- UserProfilePage: show 'Profil privé' when viewing private profile
2026-02-20 15:10:02 +01:00

127 lines
3.2 KiB
TypeScript

import { apiClient } from '@/services/api/client';
export interface UserProfile {
id: string;
username: string;
first_name: string | null;
last_name: string | null;
avatar_url: string | null;
banner_url?: string | null;
bio: string | null;
location: string | null;
birthdate: string | null;
gender: string | null;
created_at: string;
followers_count?: number;
following_count?: number;
social_links?: Record<string, any>;
is_public?: boolean;
}
export async function getProfile(userId: string): Promise<UserProfile> {
const response = await apiClient.get(`/users/${userId}`);
return (response.data as { profile?: UserProfile })?.profile ?? (response.data as UserProfile);
}
export async function getProfileByUsername(
username: string,
): Promise<UserProfile> {
const encoded = encodeURIComponent(username);
const response = await apiClient.get(`/users/by-username/${encoded}`);
// Backend returns { profile: {...} }; client unwraps success/data so response.data is the payload
return response.data?.profile ?? response.data;
}
export interface UpdateProfileRequest {
first_name?: string;
last_name?: string;
username?: string;
bio?: string;
banner_url?: string;
location?: string;
birthdate?: string;
gender?: string;
social_links?: Record<string, string>;
is_public?: boolean;
}
export async function updateProfile(
userId: string,
data: UpdateProfileRequest,
): Promise<UserProfile> {
const response = await apiClient.put(`/users/${userId}`, data);
return response.data.profile || response.data;
}
export interface ProfileCompletion {
percentage: number;
missing: string[];
}
export async function calculateProfileCompletion(
userId: string,
): Promise<ProfileCompletion> {
const response = await apiClient.get(`/users/${userId}/completion`);
return response.data;
}
// FE-PAGE-010: Complete User Profile page implementation - Follow/Unfollow
export interface FollowUserResponse {
message: string;
is_following: boolean;
}
export async function followUser(userId: string): Promise<FollowUserResponse> {
const response = await apiClient.post(`/users/${userId}/follow`);
return response.data;
}
export async function unfollowUser(
userId: string,
): Promise<FollowUserResponse> {
const response = await apiClient.delete(`/users/${userId}/follow`);
return response.data;
}
export interface UserFollowersResponse {
followers: Array<{
id: string;
username: string;
avatar_url?: string;
created_at: string;
}>;
total: number;
}
export async function getFollowers(
userId: string,
page: number = 1,
limit: number = 20,
): Promise<UserFollowersResponse> {
const response = await apiClient.get(`/users/${userId}/followers`, {
params: { page, limit },
});
return response.data;
}
export interface UserFollowingResponse {
following: Array<{
id: string;
username: string;
avatar_url?: string;
created_at: string;
}>;
total: number;
}
export async function getFollowing(
userId: string,
page: number = 1,
limit: number = 20,
): Promise<UserFollowingResponse> {
const response = await apiClient.get(`/users/${userId}/following`, {
params: { page, limit },
});
return response.data;
}