Web and mobile: - Follower/following lists (tap the counts), with Follow buttons and "Remove" on your own followers. - Profile ⋯ menu: block (with confirmation) / unblock, and report with a reason and optional note. "Follows you" label, "Follow back", and a banner on profiles you've blocked. - Blocked accounts list in Settings, with unblock. Web only: /admin for the admin account: stats, open/resolved reports, resolve, suspend/unsuspend. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MzFywujuH9TiuXbr9vjoX8
This commit is contained in:
@@ -1,5 +1,8 @@
|
||||
import type {
|
||||
AdminReportDTO,
|
||||
AdminStatsDTO,
|
||||
ConnectionDTO,
|
||||
FollowListDTO,
|
||||
FeedItemDTO,
|
||||
MeDTO,
|
||||
ProfileDTO,
|
||||
@@ -7,7 +10,7 @@ import type {
|
||||
UserSummaryDTO,
|
||||
} from './dto';
|
||||
import type { DeviceDTO } from './devices';
|
||||
import type { LoginInput, RegisterInput, ResetPasswordInput, SetFeaturedInput, UpdateMeInput } from './schemas';
|
||||
import type { LoginInput, RegisterInput, ReportReason, ResetPasswordInput, SetFeaturedInput, UpdateMeInput } from './schemas';
|
||||
|
||||
export class ApiError extends Error {
|
||||
constructor(
|
||||
@@ -89,6 +92,24 @@ export function createApiClient({ baseUrl, getToken, credentials }: ApiClientOpt
|
||||
pin: (username: string) => request(`/users/${q(username)}/pin`, { method: 'PUT', body: {} }),
|
||||
unpin: (username: string) => request(`/users/${q(username)}/pin`, { method: 'DELETE' }),
|
||||
|
||||
followers: (username: string, cursor?: string | null) =>
|
||||
request<FollowListDTO>(`/users/${q(username)}/followers${cursor ? `?cursor=${q(cursor)}` : ''}`),
|
||||
following: (username: string, cursor?: string | null) =>
|
||||
request<FollowListDTO>(`/users/${q(username)}/following${cursor ? `?cursor=${q(cursor)}` : ''}`),
|
||||
/** Stop someone following you (they aren't told). */
|
||||
removeFollower: (username: string) => request(`/me/followers/${q(username)}`, { method: 'DELETE' }),
|
||||
block: (username: string) => request(`/users/${q(username)}/block`, { method: 'POST', body: {} }),
|
||||
unblock: (username: string) => request(`/users/${q(username)}/block`, { method: 'DELETE' }),
|
||||
blocks: () => request<UserSummaryDTO[]>('/me/blocks'),
|
||||
report: (username: string, input: { reason: ReportReason; note?: string | null }) =>
|
||||
request(`/users/${q(username)}/report`, { body: input }),
|
||||
|
||||
adminStats: () => request<AdminStatsDTO>('/admin/stats'),
|
||||
adminReports: (status: 'open' | 'resolved' = 'open') => request<AdminReportDTO[]>(`/admin/reports?status=${status}`),
|
||||
resolveReport: (id: string) => request(`/admin/reports/${q(id)}/resolve`, { method: 'POST', body: {} }),
|
||||
suspend: (username: string) => request(`/admin/users/${q(username)}/suspend`, { method: 'POST', body: {} }),
|
||||
unsuspend: (username: string) => request(`/admin/users/${q(username)}/suspend`, { method: 'DELETE' }),
|
||||
|
||||
searchTracks: (query: string) => request<TrackSearchResultDTO[]>(`/tracks/search?q=${q(query)}`),
|
||||
|
||||
connections: () => request<ConnectionDTO[]>('/connections'),
|
||||
|
||||
Reference in New Issue
Block a user