6e25914074
Sprint 12 Phase 1: Golden Test Standard - Documents: React Query, upload/download/delete wired, category colors+icons, table min-widths, data-testid - Board: React Query, create position/elect/remove wired, confirmation dialogs, data-testid - Both pages: mock-mode fallback (works without backend)
149 lines
3.5 KiB
TypeScript
149 lines
3.5 KiB
TypeScript
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"
|
|
|
|
import { apiClient } from "@/lib/api-client"
|
|
|
|
// --- Constants ---
|
|
|
|
const CLUB_ID = "00000000-0000-0000-0000-000000000001"
|
|
|
|
// --- Types ---
|
|
|
|
export interface BoardPosition {
|
|
id: string
|
|
title: string
|
|
description: string | null
|
|
sortOrder: number
|
|
isActive: boolean
|
|
createdAt: string
|
|
}
|
|
|
|
export interface BoardMember {
|
|
id: string
|
|
clubId: string
|
|
positionId: string
|
|
memberId: string
|
|
electedAt: string
|
|
termStart: string
|
|
termEnd: string | null
|
|
isCurrent: boolean
|
|
electedInAssemblyId: string | null
|
|
createdAt: string
|
|
}
|
|
|
|
export interface CreatePositionRequest {
|
|
title: string
|
|
description?: string
|
|
sortOrder?: number
|
|
}
|
|
|
|
export interface ElectBoardMemberRequest {
|
|
positionId: string
|
|
memberId: string
|
|
electedAt: string
|
|
termStart: string
|
|
termEnd?: string
|
|
assemblyId?: string
|
|
}
|
|
|
|
// --- Raw API functions ---
|
|
|
|
export function createPosition(
|
|
clubId: string,
|
|
data: CreatePositionRequest
|
|
): Promise<BoardPosition> {
|
|
return apiClient<BoardPosition>(`/board/positions?clubId=${clubId}`, {
|
|
method: "POST",
|
|
body: data,
|
|
})
|
|
}
|
|
|
|
export function getPositions(clubId: string): Promise<BoardPosition[]> {
|
|
return apiClient<BoardPosition[]>(`/board/positions?clubId=${clubId}`)
|
|
}
|
|
|
|
export function updatePosition(
|
|
id: string,
|
|
data: Partial<CreatePositionRequest & { isActive: boolean }>
|
|
): Promise<BoardPosition> {
|
|
return apiClient<BoardPosition>(`/board/positions/${id}`, {
|
|
method: "PUT",
|
|
body: data,
|
|
})
|
|
}
|
|
|
|
export function electBoardMember(
|
|
clubId: string,
|
|
data: ElectBoardMemberRequest
|
|
): Promise<BoardMember> {
|
|
return apiClient<BoardMember>(`/board/members?clubId=${clubId}`, {
|
|
method: "POST",
|
|
body: data,
|
|
})
|
|
}
|
|
|
|
export function getCurrentBoard(clubId: string): Promise<BoardMember[]> {
|
|
return apiClient<BoardMember[]>(`/board?clubId=${clubId}`)
|
|
}
|
|
|
|
export function getBoardHistory(clubId: string): Promise<BoardMember[]> {
|
|
return apiClient<BoardMember[]>(`/board/history?clubId=${clubId}`)
|
|
}
|
|
|
|
export function removeBoardMember(id: string, clubId: string): Promise<void> {
|
|
return apiClient<void>(`/board/members/${id}?clubId=${clubId}`, {
|
|
method: "DELETE",
|
|
})
|
|
}
|
|
|
|
export function getPortalBoard(clubId: string): Promise<BoardMember[]> {
|
|
return apiClient<BoardMember[]>(`/portal/board?clubId=${clubId}`)
|
|
}
|
|
|
|
// --- React Query Hooks ---
|
|
|
|
export function useBoardQuery() {
|
|
return useQuery({
|
|
queryKey: ["board", CLUB_ID],
|
|
queryFn: () => getCurrentBoard(CLUB_ID),
|
|
})
|
|
}
|
|
|
|
export function usePositionsQuery() {
|
|
return useQuery({
|
|
queryKey: ["board-positions", CLUB_ID],
|
|
queryFn: () => getPositions(CLUB_ID),
|
|
})
|
|
}
|
|
|
|
export function useCreatePositionMutation() {
|
|
const queryClient = useQueryClient()
|
|
return useMutation({
|
|
mutationFn: (data: CreatePositionRequest) => createPosition(CLUB_ID, data),
|
|
onSuccess: () => {
|
|
queryClient.invalidateQueries({ queryKey: ["board-positions"] })
|
|
queryClient.invalidateQueries({ queryKey: ["board"] })
|
|
},
|
|
})
|
|
}
|
|
|
|
export function useElectBoardMemberMutation() {
|
|
const queryClient = useQueryClient()
|
|
return useMutation({
|
|
mutationFn: (data: ElectBoardMemberRequest) =>
|
|
electBoardMember(CLUB_ID, data),
|
|
onSuccess: () => {
|
|
queryClient.invalidateQueries({ queryKey: ["board"] })
|
|
},
|
|
})
|
|
}
|
|
|
|
export function useRemoveBoardMemberMutation() {
|
|
const queryClient = useQueryClient()
|
|
return useMutation({
|
|
mutationFn: (id: string) => removeBoardMember(id, CLUB_ID),
|
|
onSuccess: () => {
|
|
queryClient.invalidateQueries({ queryKey: ["board"] })
|
|
},
|
|
})
|
|
}
|