feat(pricing): manage workspace member rates in edit flows
This commit is contained in:
107
src/api/rates.ts
Normal file
107
src/api/rates.ts
Normal file
@@ -0,0 +1,107 @@
|
||||
import { authFetch } from "./client";
|
||||
|
||||
export interface RateUser {
|
||||
id: string;
|
||||
first_name?: string;
|
||||
last_name?: string;
|
||||
mobile?: string;
|
||||
profile_picture?: string;
|
||||
avatar?: string;
|
||||
name?: string;
|
||||
}
|
||||
|
||||
export interface PriceUnit {
|
||||
id: string;
|
||||
code: string;
|
||||
name: string;
|
||||
local_name?: string;
|
||||
symbol?: string;
|
||||
}
|
||||
|
||||
export interface WorkspaceUserRate {
|
||||
id: string;
|
||||
workspace: string;
|
||||
user: string;
|
||||
user_details?: RateUser;
|
||||
hourly_rate: string;
|
||||
currency: string;
|
||||
price_unit?: PriceUnit | null;
|
||||
effective_from: string;
|
||||
}
|
||||
|
||||
interface PaginatedResponse<T> {
|
||||
count: number;
|
||||
next: string | null;
|
||||
previous: string | null;
|
||||
results: T[];
|
||||
}
|
||||
|
||||
const ensurePaginated = async <T>(response: Response): Promise<PaginatedResponse<T>> => {
|
||||
if (!response.ok) {
|
||||
const errorData = await response.json().catch(() => null);
|
||||
throw new Error(errorData?.detail || errorData?.message || "Rate request failed");
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
if (Array.isArray(data)) {
|
||||
return { count: data.length, next: null, previous: null, results: data };
|
||||
}
|
||||
return {
|
||||
count: data.count || data.results?.length || 0,
|
||||
next: data.next || null,
|
||||
previous: data.previous || null,
|
||||
results: data.results || [],
|
||||
};
|
||||
};
|
||||
|
||||
export const getPriceUnits = async () => {
|
||||
const response = await authFetch("/api/price-units/");
|
||||
return ensurePaginated<PriceUnit>(response);
|
||||
};
|
||||
|
||||
export const getWorkspaceUserRates = async (workspaceId: string) => {
|
||||
const response = await authFetch(`/api/workspace-user-rates/?workspace=${workspaceId}`);
|
||||
return ensurePaginated<WorkspaceUserRate>(response);
|
||||
};
|
||||
|
||||
export const createWorkspaceUserRate = async (data: {
|
||||
workspace_id: string;
|
||||
user_id: string;
|
||||
hourly_rate: string;
|
||||
currency: string;
|
||||
}) => {
|
||||
const response = await authFetch("/api/workspace-user-rates/", {
|
||||
method: "POST",
|
||||
body: JSON.stringify(data),
|
||||
});
|
||||
if (!response.ok) {
|
||||
const errorData = await response.json().catch(() => null);
|
||||
throw new Error(errorData?.detail || errorData?.message || "Failed to save workspace user rate");
|
||||
}
|
||||
return response.json() as Promise<WorkspaceUserRate>;
|
||||
};
|
||||
|
||||
export const updateWorkspaceUserRate = async (
|
||||
rateId: string,
|
||||
data: Partial<Pick<WorkspaceUserRate, "hourly_rate" | "currency">>,
|
||||
) => {
|
||||
const response = await authFetch(`/api/workspace-user-rates/${rateId}/`, {
|
||||
method: "PATCH",
|
||||
body: JSON.stringify(data),
|
||||
});
|
||||
if (!response.ok) {
|
||||
const errorData = await response.json().catch(() => null);
|
||||
throw new Error(errorData?.detail || errorData?.message || "Failed to update workspace user rate");
|
||||
}
|
||||
return response.json() as Promise<WorkspaceUserRate>;
|
||||
};
|
||||
|
||||
export const deleteWorkspaceUserRate = async (rateId: string) => {
|
||||
const response = await authFetch(`/api/workspace-user-rates/${rateId}/`, {
|
||||
method: "DELETE",
|
||||
});
|
||||
if (!response.ok) {
|
||||
const errorData = await response.json().catch(() => null);
|
||||
throw new Error(errorData?.detail || errorData?.message || "Failed to delete workspace user rate");
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user