import { useMutation, useQueryClient } from '@tanstack/react-query';
import api from './client';
import type { CompanySettings, SubscriptionInfo, UsageInfo } from '../types';
// ─── Team types ────────────────────────────────────────────────────────────
export type TeamRole = 'owner' | 'admin' | 'manager' | 'member' | 'viewer';
export interface TeamMember {
id: number;
name: string;
email: string;
role: TeamRole;
status: string;
lastLogin: string | null;
}
export interface Invite {
id: number;
email: string;
role: TeamRole;
status: string;
created_at: string;
expires_at: string;
}
// ─── Team API ──────────────────────────────────────────────────────────────
export const teamApi = {
getTeam: async (): Promise<{ items: TeamMember[]; total: number }> => {
const { data } = await api.get<{ success: boolean; data: { items: TeamMember[]; total: number } }>(
'/api/partner/team',
);
return data.data;
},
addTeamMember: async (data: {
email: string;
role: string;
}): Promise<{ success: boolean; member: TeamMember }> => {
const res = await api.post<{ success: boolean; member: TeamMember }>('/api/partner/team', data);
return res.data;
},
updateTeamMember: async (
userId: number,
data: { role: string },
): Promise<{ success: boolean; member: Partial<TeamMember> }> => {
const res = await api.put<
{ success: boolean; member: Partial<TeamMember> }
>(`/api/partner/team/${userId}`, data);
return res.data;
},
removeTeamMember: async (
userId: number,
): Promise<{ success: boolean; message: string }> => {
const res = await api.delete<{ success: boolean; message: string }>(
`/api/partner/team/${userId}`,
);
return res.data;
},
getInvites: async (): Promise<{ invites: Invite[] }> => {
const { data } = await api.get<{ success: boolean; data: { invites: Invite[] } }>(
'/api/user/invites',
);
return data.data;
},
sendInvite: async (data: {
email: string;
role: string;
}): Promise<{ success: boolean; invite: Invite }> => {
const res = await api.post<{ success: boolean; invite: Invite }>('/api/user/invites', data);
return res.data;
},
cancelInvite: async (
inviteId: number,
): Promise<{ success: boolean; message: string }> => {
const res = await api.delete<{ success: boolean; message: string }>(
`/api/user/invites/${inviteId}`,
);
return res.data;
},
};
export const settingsApi = {
getUserSettings: async (): Promise<Record<string, unknown>> => {
const { data } = await api.get<{ success: boolean; data: Record<string, unknown> }>('/api/user/settings');
return data.data;
},
updateUserSettings: async (settings: Record<string, unknown>): Promise<void> => {
await api.put('/api/user/settings', { settings });
},
getCompany: async (): Promise<CompanySettings> => {
const { data } = await api.get<{ success: boolean; data: CompanySettings }>('/api/user/company');
return data.data;
},
updateCompany: async (data: Partial<CompanySettings>): Promise<CompanySettings> => {
const res = await api.put<{ success: boolean; data: CompanySettings }>('/api/user/company', data);
return res.data.data;
},
getCompanySettings: async (): Promise<Record<string, unknown>> => {
const { data } = await api.get<{ success: boolean; data: Record<string, unknown> }>('/api/user/company-settings');
return data.data;
},
updateCompanySettings: async (settings: Record<string, unknown>): Promise<void> => {
await api.put('/api/user/company-settings', { settings });
},
getSubscription: async (): Promise<SubscriptionInfo> => {
const { data } = await api.get<{ success: boolean; data: SubscriptionInfo }>('/api/user/subscription');
return data.data;
},
getUsage: async (): Promise<UsageInfo> => {
const { data } = await api.get<{ success: boolean; data: UsageInfo }>('/api/user/usage');
return data.data;
},
upgradeSubscription: async (): Promise<void> => {
await api.put('/api/user/subscription');
},
};
// ─── Hook: company mutation with auth-user cache invalidation ──────────
// Invalidates both ['company'] and ['auth-user'] so that the sidebar and
// all auth-context consumers reactively update when company data changes.
export function useCompanyMutation() {
const queryClient = useQueryClient();
return useMutation({
mutationFn: (data: Partial<CompanySettings>) => settingsApi.updateCompany(data),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['company'] });
queryClient.invalidateQueries({ queryKey: ['auth-user'] });
},
});
}
// ─── Integration / Connector types ───────────────────────────────────────
export interface AvailableIntegration {
service: string;
display_name: string;
description: string;
logo_url?: string;
auth_type: 'oauth2' | 'manual';
features?: string[];
}
export interface ConnectorInfo {
id: string;
service: string;
serviceDisplayName: string;
status: string;
auth_type: string;
sync_frequency: string;
last_sync_at: string | null;
error_message: string | null;
created_at: string | null;
}
export interface ConnectorLog {
id: string;
event_type: string;
status: string;
record_count: number;
duration_ms: number | null;
error_message: string | null;
details: Record<string, unknown> | null;
created_at: string | null;
}
// ─── Connector API helpers ───────────────────────────────────────────────
export const connectorsApi = {
getAvailableIntegrations: async (): Promise<AvailableIntegration[]> => {
const { data } = await api.get<{ connectors: AvailableIntegration[] }>('/api/connectors/available');
return data.connectors;
},
getConnectedIntegrations: async (): Promise<{ connectors: ConnectorInfo[]; tier: string; connector_limit: number; connectors_used: number }> => {
const { data } = await api.get<{ connectors: ConnectorInfo[]; tier: string; connector_limit: number; connectors_used: number }>('/api/connectors');
return data;
},
connectIntegration: async (service: string): Promise<{ redirect_url: string }> => {
const { data } = await api.get<{ redirect_url: string }>(`/api/connectors/oauth/authorize/${service}`);
return data;
},
disconnectIntegration: async (connectorId: string): Promise<{ success: boolean }> => {
const { data } = await api.delete<{ success: boolean }>(`/api/connectors/${connectorId}`);
return data;
},
triggerSync: async (connectorId: string): Promise<{ success: boolean }> => {
const { data } = await api.post<{ success: boolean }>(`/api/connectors/${connectorId}/sync`);
return data;
},
getConnectorLogs: async (connectorId: string): Promise<{ logs: ConnectorLog[] }> => {
const { data } = await api.get<{ connector_id: string; logs: ConnectorLog[] }>(`/api/connectors/${connectorId}/logs`);
return { logs: data.logs };
},
};