- Backend: is_public in Profile, UpdateProfile; strip SocialLinks for private - Settings: ProfileVisibilityCard toggle in Privacy tab - UserProfilePage: show 'Profil privé' when viewing private profile
127 lines
3.2 KiB
TypeScript
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;
|
|
}
|