@elevasis/ui 1.25.1 → 1.26.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,9 +1,8 @@
1
- import { useSupabase } from './chunk-NJJ3NQ7B.js';
2
1
  import { getTimeRangeDates, observabilityKeys } from './chunk-LXHZYSMQ.js';
3
2
  import { GRAPH_CONSTANTS } from './chunk-F6RBK7NJ.js';
4
3
  import { useNotificationAdapter } from './chunk-R7WLWGPO.js';
5
4
  import { HTTP_HEADERS } from './chunk-NVOCKXUQ.js';
6
- import { STALE_TIME_MONITORING, REFETCH_INTERVAL_DASHBOARD, REFETCH_INTERVAL_RUNNING, WS_MAX_RETRIES_BEFORE_ERROR, WS_RECONNECT_BASE_DELAY, WS_RECONNECT_MAX_DELAY, getErrorInfo, formatErrorMessage, getErrorTitle, STALE_TIME_DEFAULT, STALE_TIME_ADMIN } from './chunk-IOKL7BKE.js';
5
+ import { STALE_TIME_MONITORING, REFETCH_INTERVAL_DASHBOARD, REFETCH_INTERVAL_RUNNING, WS_MAX_RETRIES_BEFORE_ERROR, WS_RECONNECT_BASE_DELAY, WS_RECONNECT_MAX_DELAY, getErrorInfo, formatErrorMessage, getErrorTitle, STALE_TIME_DEFAULT, STALE_TIME_ADMIN, APIClientError } from './chunk-IOKL7BKE.js';
7
6
  import { useStableAccessToken } from './chunk-ALA56RGZ.js';
8
7
  import { useOrganization } from './chunk-DD3CCMCZ.js';
9
8
  import { useElevasisServices } from './chunk-QEPXAWE2.js';
@@ -682,6 +681,9 @@ z.object({
682
681
  message: z.string().trim().min(1).max(1e3),
683
682
  actionUrl: z.string().url().optional()
684
683
  }).strict();
684
+ z.object({
685
+ ids: z.array(UuidSchema).min(1).max(500)
686
+ }).strict();
685
687
 
686
688
  // src/hooks/monitoring/useNotifications.ts
687
689
  function useNotifications({ limit = 20, offset = 0 } = {}) {
@@ -998,15 +1000,18 @@ function useWarningNotification() {
998
1000
  const adapter = useNotificationAdapter();
999
1001
  return useCallback((title, message) => adapter.warning(title, message), [adapter]);
1000
1002
  }
1001
- function useBatchDelete(tableName, invalidateQueryKeys) {
1002
- const supabase = useSupabase();
1003
+ function useBatchDelete(invalidateQueryKeys) {
1004
+ const { apiRequest } = useElevasisServices();
1003
1005
  const queryClient = useQueryClient();
1004
1006
  const adapter = useNotificationAdapter();
1005
1007
  return useMutation({
1006
1008
  mutationFn: async (ids) => {
1007
1009
  if (ids.length === 0) return;
1008
- const { error } = await supabase.from(tableName).delete().in("id", ids);
1009
- if (error) throw error;
1010
+ const body = { ids };
1011
+ await apiRequest("/notifications/batch", {
1012
+ method: "DELETE",
1013
+ body: JSON.stringify(body)
1014
+ });
1010
1015
  },
1011
1016
  onSuccess: () => {
1012
1017
  for (const key of invalidateQueryKeys) {
@@ -3008,57 +3013,34 @@ function useCalibrationSSE({ runId, manager, apiUrl, enabled = true }) {
3008
3013
  };
3009
3014
  }
3010
3015
  function useDealDetail(acqDealId) {
3011
- const supabase = useSupabase();
3012
- const { currentSupabaseOrganizationId: organizationId, isInitializing, isOrgRefreshing } = useOrganization();
3013
- const isReady = !!organizationId && !isInitializing && !isOrgRefreshing;
3016
+ const { apiRequest, isReady, organizationId } = useElevasisServices();
3014
3017
  return useQuery({
3015
- queryKey: [...dealKeys.detail(acqDealId), organizationId],
3018
+ queryKey: ["deal-detail", organizationId, acqDealId],
3016
3019
  queryFn: async () => {
3017
- if (!organizationId || !acqDealId) return null;
3018
- const { data, error } = await supabase.from("acq_deals").select(
3019
- `
3020
- *,
3021
- contact:acq_contacts(
3022
- id,
3023
- first_name,
3024
- last_name,
3025
- email,
3026
- title,
3027
- headline,
3028
- linkedin_url,
3029
- pipeline_status,
3030
- enrichment_data,
3031
- company:acq_companies(
3032
- id,
3033
- name,
3034
- domain,
3035
- website,
3036
- linkedin_url,
3037
- segment,
3038
- category,
3039
- num_employees
3040
- )
3041
- )
3042
- `
3043
- ).eq("id", acqDealId).eq("organization_id", organizationId).single();
3044
- if (error) {
3045
- if (error.code === "PGRST116") return null;
3046
- throw error;
3020
+ if (!acqDealId) return null;
3021
+ try {
3022
+ return await apiRequest(`/deals/${acqDealId}`);
3023
+ } catch (err) {
3024
+ if (err instanceof APIClientError && err.statusCode === 404) return null;
3025
+ throw err;
3047
3026
  }
3048
- return data;
3049
3027
  },
3050
3028
  enabled: isReady && !!acqDealId
3051
3029
  });
3052
3030
  }
3053
3031
  function useSyncDealStage() {
3054
- const supabase = useSupabase();
3032
+ const { apiRequest, organizationId } = useElevasisServices();
3055
3033
  const queryClient = useQueryClient();
3056
- const { currentSupabaseOrganizationId: organizationId } = useOrganization();
3057
3034
  return useMutation({
3058
3035
  mutationFn: async ({ dealId, stage }) => {
3059
- if (!organizationId) throw new Error("No organization context");
3060
- const { error } = await supabase.from("acq_deals").update({ cached_stage: stage }).eq("id", dealId).eq("organization_id", organizationId);
3061
- if (error) throw error;
3036
+ await apiRequest(`/deals/${dealId}/sync-stage`, {
3037
+ method: "PATCH",
3038
+ body: JSON.stringify({ stage })
3039
+ });
3040
+ },
3041
+ onSuccess: (_, variables) => {
3042
+ queryClient.invalidateQueries({ queryKey: ["deals", organizationId] });
3043
+ queryClient.invalidateQueries({ queryKey: ["deal-detail", organizationId, variables.dealId] });
3062
3044
  },
3063
3045
  onError: (error) => {
3064
3046
  queryClient.invalidateQueries({ queryKey: dealKeys.all });
@@ -3067,58 +3049,32 @@ function useSyncDealStage() {
3067
3049
  });
3068
3050
  }
3069
3051
  var dealNoteKeys = {
3070
- all: ["dealNotes"],
3071
- list: (organizationId, dealId) => ["dealNotes", organizationId, dealId]
3052
+ all: ["deal-notes"],
3053
+ list: (organizationId, dealId) => ["deal-notes", organizationId, dealId]
3072
3054
  };
3073
3055
  function useDealNotes(dealId) {
3074
- const supabase = useSupabase();
3075
- const { currentSupabaseOrganizationId: organizationId, isInitializing, isOrgRefreshing } = useOrganization();
3076
- const isReady = !!organizationId && !isInitializing && !isOrgRefreshing;
3056
+ const { apiRequest, isReady, organizationId } = useElevasisServices();
3077
3057
  return useQuery({
3078
3058
  queryKey: dealNoteKeys.list(organizationId, dealId),
3079
3059
  queryFn: async () => {
3080
- if (!organizationId || !dealId) return [];
3081
- const { data, error } = await supabase.from("acq_deal_notes").select("*").eq("deal_id", dealId).eq("organization_id", organizationId).order("created_at", { ascending: false });
3082
- if (error) throw error;
3083
- return (data || []).map((row) => ({
3084
- id: row.id,
3085
- dealId: row.deal_id,
3086
- organizationId: row.organization_id,
3087
- authorUserId: row.author_user_id,
3088
- body: row.body,
3089
- createdAt: row.created_at,
3090
- updatedAt: row.updated_at
3091
- }));
3060
+ return apiRequest(`/deals/${dealId}/notes`);
3092
3061
  },
3093
3062
  enabled: isReady && !!dealId
3094
3063
  });
3095
3064
  }
3096
3065
  function useCreateDealNote() {
3097
- const supabase = useSupabase();
3066
+ const { apiRequest, organizationId } = useElevasisServices();
3098
3067
  const queryClient = useQueryClient();
3099
- const { currentSupabaseOrganizationId: organizationId } = useOrganization();
3100
3068
  return useMutation({
3101
- mutationFn: async ({ dealId, body, authorUserId }) => {
3102
- if (!organizationId) throw new Error("No organization context");
3103
- const { data, error } = await supabase.from("acq_deal_notes").insert({
3104
- deal_id: dealId,
3105
- organization_id: organizationId,
3106
- body,
3107
- author_user_id: authorUserId ?? null
3108
- }).select().single();
3109
- if (error) throw error;
3110
- return {
3111
- id: data.id,
3112
- dealId: data.deal_id,
3113
- organizationId: data.organization_id,
3114
- authorUserId: data.author_user_id,
3115
- body: data.body,
3116
- createdAt: data.created_at,
3117
- updatedAt: data.updated_at
3118
- };
3069
+ mutationFn: async ({ dealId, body }) => {
3070
+ return apiRequest(`/deals/${dealId}/notes`, {
3071
+ method: "POST",
3072
+ body: JSON.stringify({ body })
3073
+ });
3119
3074
  },
3120
3075
  onSuccess: (_, variables) => {
3121
3076
  queryClient.invalidateQueries({ queryKey: dealNoteKeys.list(organizationId, variables.dealId) });
3077
+ queryClient.invalidateQueries({ queryKey: ["recent-crm-activity", organizationId] });
3122
3078
  showSuccessNotification("Note added");
3123
3079
  },
3124
3080
  onError: (error) => {
@@ -3131,97 +3087,50 @@ var dealTaskKeys = {
3131
3087
  list: (orgId, dealId) => ["deal-tasks", orgId, dealId],
3132
3088
  due: (orgId, window, assigneeUserId) => ["deal-tasks-due", orgId, window, assigneeUserId]
3133
3089
  };
3134
- function transformTaskRow(row) {
3135
- return {
3136
- id: row.id,
3137
- organizationId: row.organization_id,
3138
- dealId: row.deal_id,
3139
- title: row.title,
3140
- description: row.description,
3141
- kind: row.kind,
3142
- dueAt: row.due_at,
3143
- assigneeUserId: row.assignee_user_id,
3144
- completedAt: row.completed_at,
3145
- completedByUserId: row.completed_by_user_id,
3146
- createdAt: row.created_at,
3147
- updatedAt: row.updated_at,
3148
- createdByUserId: row.created_by_user_id
3149
- };
3150
- }
3151
3090
  function useDealTasks(dealId) {
3152
- const supabase = useSupabase();
3153
- const { currentSupabaseOrganizationId: organizationId, isInitializing, isOrgRefreshing } = useOrganization();
3154
- const isReady = !!organizationId && !isInitializing && !isOrgRefreshing;
3091
+ const { apiRequest, isReady, organizationId } = useElevasisServices();
3155
3092
  return useQuery({
3156
3093
  queryKey: dealTaskKeys.list(organizationId, dealId ?? ""),
3157
3094
  queryFn: async () => {
3158
- if (!organizationId || !dealId) return [];
3159
- const { data, error } = await supabase.from("acq_deal_tasks").select("*").eq("deal_id", dealId).eq("organization_id", organizationId).order("due_at", { ascending: true, nullsFirst: false });
3160
- if (error) throw error;
3161
- return (data || []).map(transformTaskRow);
3095
+ return apiRequest(`/deals/${dealId}/tasks`);
3162
3096
  },
3163
3097
  enabled: isReady && !!dealId
3164
3098
  });
3165
3099
  }
3166
3100
  function useDealTasksDue(opts) {
3167
- const supabase = useSupabase();
3168
- const { currentSupabaseOrganizationId: organizationId, isInitializing, isOrgRefreshing } = useOrganization();
3169
- const isReady = !!organizationId && !isInitializing && !isOrgRefreshing;
3101
+ const { apiRequest, isReady, organizationId } = useElevasisServices();
3170
3102
  const window = opts?.window ?? "today_and_overdue";
3171
3103
  const assigneeUserId = opts?.assigneeUserId ?? null;
3172
3104
  return useQuery({
3173
3105
  queryKey: dealTaskKeys.due(organizationId, window, assigneeUserId),
3174
3106
  queryFn: async () => {
3175
- if (!organizationId) return [];
3176
- const now = /* @__PURE__ */ new Date();
3177
- const todayStart = new Date(now.getFullYear(), now.getMonth(), now.getDate()).toISOString();
3178
- const todayEnd = new Date(now.getFullYear(), now.getMonth(), now.getDate() + 1).toISOString();
3179
- let query = supabase.from("acq_deal_tasks").select("*").eq("organization_id", organizationId).is("completed_at", null);
3180
- if (window === "overdue") {
3181
- query = query.lt("due_at", todayStart);
3182
- } else if (window === "today") {
3183
- query = query.gte("due_at", todayStart).lt("due_at", todayEnd);
3184
- } else if (window === "today_and_overdue") {
3185
- query = query.lt("due_at", todayEnd);
3186
- } else if (window === "upcoming") {
3187
- query = query.gte("due_at", todayEnd);
3188
- }
3189
- if (assigneeUserId !== null) {
3190
- query = query.eq("assignee_user_id", assigneeUserId);
3191
- }
3192
- query = query.order("due_at", { ascending: true, nullsFirst: false });
3193
- const { data, error } = await query;
3194
- if (error) throw error;
3195
- return (data || []).map(transformTaskRow);
3107
+ const params = new URLSearchParams({ window });
3108
+ if (assigneeUserId) params.set("assigneeUserId", assigneeUserId);
3109
+ return apiRequest(`/deals/tasks/due?${params.toString()}`);
3196
3110
  },
3197
3111
  enabled: isReady
3198
3112
  });
3199
3113
  }
3200
3114
  function useCreateDealTask() {
3201
- const supabase = useSupabase();
3202
- const { currentSupabaseOrganizationId: organizationId } = useOrganization();
3115
+ const { apiRequest, organizationId } = useElevasisServices();
3203
3116
  const queryClient = useQueryClient();
3204
3117
  return useMutation({
3205
3118
  mutationFn: async (params) => {
3206
- if (!organizationId) throw new Error("No organization context");
3207
- const { data, error } = await supabase.from("acq_deal_tasks").insert({
3208
- deal_id: params.dealId,
3209
- organization_id: organizationId,
3210
- title: params.title,
3211
- description: params.description ?? null,
3212
- kind: params.kind ?? "other",
3213
- due_at: params.dueAt ?? null,
3214
- assignee_user_id: params.assigneeUserId ?? null,
3215
- created_by_user_id: params.createdByUserId ?? null
3216
- }).select().single();
3217
- if (error) throw error;
3218
- return transformTaskRow(data);
3119
+ const { dealId, ...body } = params;
3120
+ return apiRequest(`/deals/${dealId}/tasks`, {
3121
+ method: "POST",
3122
+ body: JSON.stringify({
3123
+ title: body.title,
3124
+ description: body.description ?? null,
3125
+ kind: body.kind ?? "other",
3126
+ dueAt: body.dueAt ?? null,
3127
+ assigneeUserId: body.assigneeUserId ?? null
3128
+ })
3129
+ });
3219
3130
  },
3220
3131
  onSuccess: (_, variables) => {
3221
3132
  queryClient.invalidateQueries({ queryKey: dealTaskKeys.list(organizationId, variables.dealId) });
3222
- queryClient.invalidateQueries({
3223
- predicate: (query) => query.queryKey[0] === "deal-tasks-due"
3224
- });
3133
+ queryClient.invalidateQueries({ queryKey: ["deal-tasks-due", organizationId] });
3225
3134
  showSuccessNotification("Task created");
3226
3135
  },
3227
3136
  onError: (error) => {
@@ -3230,24 +3139,17 @@ function useCreateDealTask() {
3230
3139
  });
3231
3140
  }
3232
3141
  function useCompleteDealTask() {
3233
- const supabase = useSupabase();
3234
- const { currentSupabaseOrganizationId: organizationId } = useOrganization();
3142
+ const { apiRequest, organizationId } = useElevasisServices();
3235
3143
  const queryClient = useQueryClient();
3236
3144
  return useMutation({
3237
- mutationFn: async ({ taskId, completedByUserId }) => {
3238
- if (!organizationId) throw new Error("No organization context");
3239
- const { data, error } = await supabase.from("acq_deal_tasks").update({
3240
- completed_at: (/* @__PURE__ */ new Date()).toISOString(),
3241
- completed_by_user_id: completedByUserId ?? null
3242
- }).eq("id", taskId).eq("organization_id", organizationId).select().single();
3243
- if (error) throw error;
3244
- return transformTaskRow(data);
3145
+ mutationFn: async ({ taskId, dealId }) => {
3146
+ return apiRequest(`/deals/${dealId}/tasks/${taskId}/complete`, {
3147
+ method: "PATCH"
3148
+ });
3245
3149
  },
3246
3150
  onSuccess: (_, variables) => {
3247
3151
  queryClient.invalidateQueries({ queryKey: dealTaskKeys.list(organizationId, variables.dealId) });
3248
- queryClient.invalidateQueries({
3249
- predicate: (query) => query.queryKey[0] === "deal-tasks-due"
3250
- });
3152
+ queryClient.invalidateQueries({ queryKey: ["deal-tasks-due", organizationId] });
3251
3153
  showSuccessNotification("Task completed");
3252
3154
  },
3253
3155
  onError: (error) => {
@@ -3266,60 +3168,36 @@ function useBatchTelemetry() {
3266
3168
 
3267
3169
  // src/hooks/acquisition/useDeals.ts
3268
3170
  var dealKeys = {
3269
- all: ["acq-deals"],
3171
+ all: ["deals"],
3270
3172
  lists: () => [...dealKeys.all, "list"],
3271
3173
  list: (orgId, filters) => [...dealKeys.all, "list", orgId, filters],
3272
3174
  details: () => [...dealKeys.all, "detail"],
3273
3175
  detail: (id) => [...dealKeys.all, "detail", id]
3274
3176
  };
3275
3177
  function useDeals(filters = {}) {
3276
- const supabase = useSupabase();
3277
- const { currentSupabaseOrganizationId: organizationId, isInitializing, isOrgRefreshing } = useOrganization();
3278
- const isReady = !!organizationId && !isInitializing && !isOrgRefreshing;
3178
+ const { apiRequest, isReady, organizationId } = useElevasisServices();
3279
3179
  return useQuery({
3280
3180
  queryKey: dealKeys.list(organizationId, filters),
3281
3181
  queryFn: async () => {
3282
- if (!organizationId) return [];
3283
- let query = supabase.from("acq_deals").select(
3284
- `
3285
- *,
3286
- contact:acq_contacts(
3287
- id,
3288
- first_name,
3289
- last_name,
3290
- email,
3291
- title,
3292
- company:acq_companies(
3293
- id,
3294
- name,
3295
- domain
3296
- )
3297
- )
3298
- `
3299
- ).eq("organization_id", organizationId);
3300
- if (filters.stage) {
3301
- query = query.eq("cached_stage", filters.stage);
3302
- }
3303
- if (filters.search) {
3304
- query = query.ilike("contact_email", `%${filters.search}%`);
3305
- }
3306
- query = query.order("updated_at", { ascending: false });
3307
- const { data, error } = await query;
3308
- if (error) throw error;
3309
- return data || [];
3182
+ const params = new URLSearchParams();
3183
+ if (filters.stage) params.set("stage", filters.stage);
3184
+ if (filters.search) params.set("search", filters.search);
3185
+ const qs = params.toString();
3186
+ const data = await apiRequest(`/deals${qs ? `?${qs}` : ""}`);
3187
+ return data;
3310
3188
  },
3311
3189
  enabled: isReady
3312
3190
  });
3313
3191
  }
3314
3192
  function useDeleteDeal() {
3315
- const { apiRequest } = useElevasisServices();
3193
+ const { apiRequest, organizationId } = useElevasisServices();
3316
3194
  const queryClient = useQueryClient();
3317
3195
  return useMutation({
3318
3196
  mutationFn: async (dealId) => {
3319
3197
  await apiRequest(`/deals/${dealId}`, { method: "DELETE" });
3320
3198
  },
3321
3199
  onSuccess: () => {
3322
- queryClient.invalidateQueries({ queryKey: dealKeys.all });
3200
+ queryClient.invalidateQueries({ queryKey: ["deals", organizationId] });
3323
3201
  },
3324
3202
  onError: (error) => {
3325
3203
  showApiErrorNotification(error);
@@ -8365,26 +8365,26 @@ declare function useCrmQuickMetrics(): {
8365
8365
  error: unknown;
8366
8366
  };
8367
8367
 
8368
- type CrmActivityKind = 'note' | 'stage_change' | 'deal_created';
8369
- interface CrmActivityEntry {
8370
- id: string;
8371
- kind: CrmActivityKind;
8372
- dealId: string;
8373
- occurredAt: string;
8374
- description: string;
8375
- contactName?: string | null;
8376
- companyName?: string | null;
8377
- stage?: DealStage | null;
8378
- }
8368
+ // ---------------------------------------------------------------------------
8369
+ // Response schemas (no .strict() — forward-compatible)
8370
+ // ---------------------------------------------------------------------------
8371
+
8372
+ declare const GetRecentActivityResponseSchema = z.object({
8373
+ entries: z.array(RecentActivityEntrySchema)
8374
+ })
8375
+ type GetRecentActivityResponse = z.infer<typeof GetRecentActivityResponseSchema>
8376
+
8379
8377
  /**
8380
- * Composite hook that surfaces the most recent activity across all deals.
8381
- * Merges acq_deal_notes + activity_log entries from acq_deals, sorted newest-first.
8382
- * Org-scoped: all queries include organization_id filter.
8378
+ * Returns the most recent CRM activity entries (notes + stage changes + deal
8379
+ * creations) for the current organization, aggregated server-side.
8380
+ *
8381
+ * Replaces the previous client-side aggregation that joined acq_deal_notes
8382
+ * with useDeals(). Server now owns the join via GET /api/crm/recent-activity.
8383
8383
  */
8384
8384
  declare function useRecentCrmActivity(opts?: {
8385
8385
  limit?: number;
8386
8386
  }): {
8387
- data: CrmActivityEntry[];
8387
+ data: GetRecentActivityResponse['entries'];
8388
8388
  isLoading: boolean;
8389
8389
  error: unknown;
8390
8390
  };