@adventurelabs/scout-core 1.2.5 → 1.3.1
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.
- package/dist/helpers/cache.js +3 -1
- package/dist/helpers/pins.d.ts +2 -0
- package/dist/helpers/pins.js +58 -42
- package/dist/helpers/session_summaries.d.ts +6 -0
- package/dist/helpers/session_summaries.js +51 -0
- package/dist/hooks/index.d.ts +2 -0
- package/dist/hooks/index.js +4 -0
- package/dist/hooks/useHerdData.d.ts +167 -0
- package/dist/hooks/useHerdData.js +153 -0
- package/dist/hooks/useInfiniteQuery.d.ts +24 -0
- package/dist/hooks/useInfiniteQuery.js +360 -0
- package/dist/hooks/useScoutRealtimeEvents.d.ts +1 -1
- package/dist/hooks/useScoutRealtimeEvents.js +18 -23
- package/dist/hooks/useScoutRealtimeSessions.d.ts +1 -1
- package/dist/hooks/useScoutRealtimeSessions.js +20 -12
- package/dist/hooks/useScoutRealtimeTags.d.ts +1 -1
- package/dist/hooks/useScoutRealtimeTags.js +15 -12
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/providers/ScoutRefreshProvider.d.ts +123 -6
- package/dist/store/api.d.ts +968 -0
- package/dist/store/api.js +377 -0
- package/dist/store/configureStore.d.ts +96 -0
- package/dist/store/configureStore.js +40 -0
- package/dist/store/hooks.d.ts +5 -0
- package/dist/store/hooks.js +21 -3
- package/dist/store/index.d.ts +1 -0
- package/dist/store/index.js +1 -0
- package/dist/store/scout.d.ts +13 -50
- package/dist/store/scout.js +33 -141
- package/dist/types/db.d.ts +18 -0
- package/dist/types/herd_module.d.ts +4 -16
- package/dist/types/herd_module.js +17 -23
- package/dist/types/supabase.d.ts +123 -6
- package/package.json +1 -1
package/dist/helpers/cache.js
CHANGED
|
@@ -225,8 +225,10 @@ export class ScoutCache {
|
|
|
225
225
|
const result = await this.getHerdModules();
|
|
226
226
|
const totalRequests = this.stats.hits + this.stats.misses;
|
|
227
227
|
const hitRate = totalRequests > 0 ? this.stats.hits / totalRequests : 0;
|
|
228
|
+
// Calculate size based on herd modules count (no longer including events/sessions/artifacts arrays)
|
|
229
|
+
const size = result.data?.length || 0;
|
|
228
230
|
return {
|
|
229
|
-
size
|
|
231
|
+
size,
|
|
230
232
|
lastUpdated: result.data ? Date.now() - result.age : 0,
|
|
231
233
|
isStale: result.isStale,
|
|
232
234
|
hitRate: Math.round(hitRate * 100) / 100,
|
package/dist/helpers/pins.d.ts
CHANGED
|
@@ -5,7 +5,9 @@ import { SupabaseClient } from "@supabase/supabase-js";
|
|
|
5
5
|
export declare function get_pins_for_herd(client: SupabaseClient<Database>, herd_id: number): Promise<IWebResponseCompatible<IPin[]>>;
|
|
6
6
|
export declare function get_pin_by_id(client: SupabaseClient<Database>, pin_id: number): Promise<IWebResponseCompatible<IPin | null>>;
|
|
7
7
|
export declare function create_pin(client: SupabaseClient<Database>, newPin: PinInsert): Promise<IWebResponseCompatible<IPin | null>>;
|
|
8
|
+
export declare function create_pin_with_coordinates(client: SupabaseClient<Database>, latitude: number, longitude: number, pinData: Omit<PinInsert, "location">): Promise<IWebResponseCompatible<IPin | null>>;
|
|
8
9
|
export declare function update_pin(client: SupabaseClient<Database>, pin_id: number, updatedPin: Partial<PinInsert>): Promise<IWebResponseCompatible<IPin | null>>;
|
|
10
|
+
export declare function update_pin_location(client: SupabaseClient<Database>, pin_id: number, latitude: number, longitude: number, updatedPin?: Partial<Omit<PinInsert, "location">>): Promise<IWebResponseCompatible<IPin | null>>;
|
|
9
11
|
export declare function delete_pin(client: SupabaseClient<Database>, pin_id: number): Promise<IWebResponseCompatible<IPin | null>>;
|
|
10
12
|
export declare function get_pins_by_created_by(client: SupabaseClient<Database>, user_id: string): Promise<IWebResponseCompatible<IPin[]>>;
|
|
11
13
|
export declare function get_pins_by_color(client: SupabaseClient<Database>, herd_id: number, color: string): Promise<IWebResponseCompatible<IPin[]>>;
|
package/dist/helpers/pins.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { IWebResponse } from "../types/requests";
|
|
2
2
|
export async function get_pins_for_herd(client, herd_id) {
|
|
3
|
-
// Call get_pins_for_herd with rpc
|
|
3
|
+
// Call get_pins_for_herd with rpc - returns pins_pretty_location with extracted coordinates
|
|
4
4
|
const { data, error } = await client.rpc("get_pins_for_herd", {
|
|
5
5
|
herd_id_caller: herd_id,
|
|
6
6
|
});
|
|
@@ -24,13 +24,8 @@ export async function get_pin_by_id(client, pin_id) {
|
|
|
24
24
|
if (!data) {
|
|
25
25
|
return IWebResponse.error("Pin not found").to_compatible();
|
|
26
26
|
}
|
|
27
|
-
//
|
|
28
|
-
|
|
29
|
-
...data,
|
|
30
|
-
latitude: data.latitude ? parseFloat(data.latitude.toString()) : 0,
|
|
31
|
-
longitude: data.longitude ? parseFloat(data.longitude.toString()) : 0,
|
|
32
|
-
};
|
|
33
|
-
return IWebResponse.success(pinWithCoords).to_compatible();
|
|
27
|
+
// Raw table data - no coordinate extraction (use get_pins_for_herd for coordinates)
|
|
28
|
+
return IWebResponse.success(data).to_compatible();
|
|
34
29
|
}
|
|
35
30
|
export async function create_pin(client, newPin) {
|
|
36
31
|
const { data, error } = await client
|
|
@@ -44,13 +39,30 @@ export async function create_pin(client, newPin) {
|
|
|
44
39
|
if (!data) {
|
|
45
40
|
return IWebResponse.error("Failed to create pin").to_compatible();
|
|
46
41
|
}
|
|
47
|
-
//
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
}
|
|
53
|
-
|
|
42
|
+
// Raw table data - coordinates extracted by RPC function or realtime broadcasts
|
|
43
|
+
return IWebResponse.success(data).to_compatible();
|
|
44
|
+
}
|
|
45
|
+
export async function create_pin_with_coordinates(client, latitude, longitude, pinData) {
|
|
46
|
+
// Create pin with PostGIS Point from lat/lng coordinates
|
|
47
|
+
const { data, error } = await client
|
|
48
|
+
.from("pins")
|
|
49
|
+
.insert([
|
|
50
|
+
{
|
|
51
|
+
...pinData,
|
|
52
|
+
// Use PostGIS ST_MakePoint to create geography from coordinates
|
|
53
|
+
// Note: PostGIS Point format is (longitude, latitude)
|
|
54
|
+
location: `SRID=4326;POINT(${longitude} ${latitude})`,
|
|
55
|
+
},
|
|
56
|
+
])
|
|
57
|
+
.select("*")
|
|
58
|
+
.single();
|
|
59
|
+
if (error) {
|
|
60
|
+
return IWebResponse.error(error.message).to_compatible();
|
|
61
|
+
}
|
|
62
|
+
if (!data) {
|
|
63
|
+
return IWebResponse.error("Failed to create pin").to_compatible();
|
|
64
|
+
}
|
|
65
|
+
return IWebResponse.success(data).to_compatible();
|
|
54
66
|
}
|
|
55
67
|
export async function update_pin(client, pin_id, updatedPin) {
|
|
56
68
|
// Remove fields that shouldn't be updated
|
|
@@ -70,13 +82,32 @@ export async function update_pin(client, pin_id, updatedPin) {
|
|
|
70
82
|
if (!data) {
|
|
71
83
|
return IWebResponse.error("Pin not found or update failed").to_compatible();
|
|
72
84
|
}
|
|
73
|
-
//
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
85
|
+
// Raw table data - coordinates extracted by RPC function or realtime broadcasts
|
|
86
|
+
return IWebResponse.success(data).to_compatible();
|
|
87
|
+
}
|
|
88
|
+
export async function update_pin_location(client, pin_id, latitude, longitude, updatedPin) {
|
|
89
|
+
const updateData = {
|
|
90
|
+
...updatedPin,
|
|
91
|
+
// Use PostGIS format to update location
|
|
92
|
+
location: `SRID=4326;POINT(${longitude} ${latitude})`,
|
|
78
93
|
};
|
|
79
|
-
|
|
94
|
+
// Remove fields that shouldn't be updated
|
|
95
|
+
delete updateData.id;
|
|
96
|
+
delete updateData.created_at;
|
|
97
|
+
delete updateData.created_by;
|
|
98
|
+
const { data, error } = await client
|
|
99
|
+
.from("pins")
|
|
100
|
+
.update(updateData)
|
|
101
|
+
.eq("id", pin_id)
|
|
102
|
+
.select("*")
|
|
103
|
+
.single();
|
|
104
|
+
if (error) {
|
|
105
|
+
return IWebResponse.error(error.message).to_compatible();
|
|
106
|
+
}
|
|
107
|
+
if (!data) {
|
|
108
|
+
return IWebResponse.error("Pin not found or update failed").to_compatible();
|
|
109
|
+
}
|
|
110
|
+
return IWebResponse.success(data).to_compatible();
|
|
80
111
|
}
|
|
81
112
|
export async function delete_pin(client, pin_id) {
|
|
82
113
|
const { data, error } = await client
|
|
@@ -91,13 +122,8 @@ export async function delete_pin(client, pin_id) {
|
|
|
91
122
|
if (!data) {
|
|
92
123
|
return IWebResponse.error("Pin not found or deletion failed").to_compatible();
|
|
93
124
|
}
|
|
94
|
-
//
|
|
95
|
-
|
|
96
|
-
...data,
|
|
97
|
-
latitude: data.latitude ? parseFloat(data.latitude.toString()) : 0,
|
|
98
|
-
longitude: data.longitude ? parseFloat(data.longitude.toString()) : 0,
|
|
99
|
-
};
|
|
100
|
-
return IWebResponse.success(pinWithCoords).to_compatible();
|
|
125
|
+
// Raw table data - coordinates extracted by realtime broadcasts
|
|
126
|
+
return IWebResponse.success(data).to_compatible();
|
|
101
127
|
}
|
|
102
128
|
export async function get_pins_by_created_by(client, user_id) {
|
|
103
129
|
const { data, error } = await client
|
|
@@ -111,13 +137,8 @@ export async function get_pins_by_created_by(client, user_id) {
|
|
|
111
137
|
if (!data) {
|
|
112
138
|
return IWebResponse.error("No pins found for user").to_compatible();
|
|
113
139
|
}
|
|
114
|
-
//
|
|
115
|
-
|
|
116
|
-
...pin,
|
|
117
|
-
latitude: pin.latitude ? parseFloat(pin.latitude.toString()) : 0,
|
|
118
|
-
longitude: pin.longitude ? parseFloat(pin.longitude.toString()) : 0,
|
|
119
|
-
}));
|
|
120
|
-
return IWebResponse.success(pinsWithCoords).to_compatible();
|
|
140
|
+
// Raw table data without extracted coordinates - use get_pins_for_herd for coordinates
|
|
141
|
+
return IWebResponse.success(data).to_compatible();
|
|
121
142
|
}
|
|
122
143
|
export async function get_pins_by_color(client, herd_id, color) {
|
|
123
144
|
const { data, error } = await client
|
|
@@ -132,11 +153,6 @@ export async function get_pins_by_color(client, herd_id, color) {
|
|
|
132
153
|
if (!data) {
|
|
133
154
|
return IWebResponse.error(`No pins found with color: ${color}`).to_compatible();
|
|
134
155
|
}
|
|
135
|
-
//
|
|
136
|
-
|
|
137
|
-
...pin,
|
|
138
|
-
latitude: pin.latitude ? parseFloat(pin.latitude.toString()) : 0,
|
|
139
|
-
longitude: pin.longitude ? parseFloat(pin.longitude.toString()) : 0,
|
|
140
|
-
}));
|
|
141
|
-
return IWebResponse.success(pinsWithCoords).to_compatible();
|
|
156
|
+
// Raw table data without extracted coordinates - use get_pins_for_herd for coordinates
|
|
157
|
+
return IWebResponse.success(data).to_compatible();
|
|
142
158
|
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { ISessionSummary } from "../types/db";
|
|
2
|
+
import { IWebResponseCompatible } from "../types/requests";
|
|
3
|
+
import { SupabaseClient } from "@supabase/supabase-js";
|
|
4
|
+
export declare function server_get_session_summaries_by_herd(herd_id: number, client?: SupabaseClient): Promise<IWebResponseCompatible<ISessionSummary>>;
|
|
5
|
+
export declare function server_get_session_summaries_by_device(device_id: number, client?: SupabaseClient): Promise<IWebResponseCompatible<ISessionSummary>>;
|
|
6
|
+
export declare function server_get_session_summaries_with_filters(herd_id?: number, device_id?: number, start_date?: string, end_date?: string, client?: SupabaseClient): Promise<IWebResponseCompatible<ISessionSummary>>;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"use server";
|
|
2
|
+
import { newServerClient } from "../supabase/server";
|
|
3
|
+
import { IWebResponse, } from "../types/requests";
|
|
4
|
+
export async function server_get_session_summaries_by_herd(herd_id, client) {
|
|
5
|
+
const supabase = client || (await newServerClient());
|
|
6
|
+
const { data, error } = await supabase.rpc("get_session_summaries", {
|
|
7
|
+
start_date_caller: undefined,
|
|
8
|
+
end_date_caller: undefined,
|
|
9
|
+
device_id_caller: undefined,
|
|
10
|
+
herd_id_caller: herd_id,
|
|
11
|
+
});
|
|
12
|
+
if (error) {
|
|
13
|
+
return IWebResponse.error(error.message).to_compatible();
|
|
14
|
+
}
|
|
15
|
+
if (!data) {
|
|
16
|
+
return IWebResponse.error("No session summary data returned").to_compatible();
|
|
17
|
+
}
|
|
18
|
+
return IWebResponse.success(data).to_compatible();
|
|
19
|
+
}
|
|
20
|
+
export async function server_get_session_summaries_by_device(device_id, client) {
|
|
21
|
+
const supabase = client || (await newServerClient());
|
|
22
|
+
const { data, error } = await supabase.rpc("get_session_summaries", {
|
|
23
|
+
start_date_caller: undefined,
|
|
24
|
+
end_date_caller: undefined,
|
|
25
|
+
device_id_caller: device_id,
|
|
26
|
+
herd_id_caller: undefined,
|
|
27
|
+
});
|
|
28
|
+
if (error) {
|
|
29
|
+
return IWebResponse.error(error.message).to_compatible();
|
|
30
|
+
}
|
|
31
|
+
if (!data) {
|
|
32
|
+
return IWebResponse.error("No session summary data returned").to_compatible();
|
|
33
|
+
}
|
|
34
|
+
return IWebResponse.success(data).to_compatible();
|
|
35
|
+
}
|
|
36
|
+
export async function server_get_session_summaries_with_filters(herd_id, device_id, start_date, end_date, client) {
|
|
37
|
+
const supabase = client || (await newServerClient());
|
|
38
|
+
const { data, error } = await supabase.rpc("get_session_summaries", {
|
|
39
|
+
start_date_caller: start_date || undefined,
|
|
40
|
+
end_date_caller: end_date || undefined,
|
|
41
|
+
device_id_caller: device_id || undefined,
|
|
42
|
+
herd_id_caller: herd_id || undefined,
|
|
43
|
+
});
|
|
44
|
+
if (error) {
|
|
45
|
+
return IWebResponse.error(error.message).to_compatible();
|
|
46
|
+
}
|
|
47
|
+
if (!data) {
|
|
48
|
+
return IWebResponse.error("No session summary data returned").to_compatible();
|
|
49
|
+
}
|
|
50
|
+
return IWebResponse.success(data).to_compatible();
|
|
51
|
+
}
|
package/dist/hooks/index.d.ts
CHANGED
|
@@ -7,3 +7,5 @@ export { useScoutRealtimeTags } from "./useScoutRealtimeTags";
|
|
|
7
7
|
export { useScoutRealtimeSessions } from "./useScoutRealtimeSessions";
|
|
8
8
|
export { useScoutRealtimePlans } from "./useScoutRealtimePlans";
|
|
9
9
|
export { useScoutRealtimePins } from "./useScoutRealtimePins";
|
|
10
|
+
export { useInfiniteSessionsByHerd, useInfiniteSessionsByDevice, useInfiniteEventsByHerd, useInfiniteEventsByDevice, useInfiniteArtifactsByHerd, useInfiniteArtifactsByDevice, useIntersectionObserver, } from "./useInfiniteQuery";
|
|
11
|
+
export { useLoadingPerformance, useSessionSummariesByHerd, useHasSessionSummaries, } from "../store/hooks";
|
package/dist/hooks/index.js
CHANGED
|
@@ -7,3 +7,7 @@ export { useScoutRealtimeTags } from "./useScoutRealtimeTags";
|
|
|
7
7
|
export { useScoutRealtimeSessions } from "./useScoutRealtimeSessions";
|
|
8
8
|
export { useScoutRealtimePlans } from "./useScoutRealtimePlans";
|
|
9
9
|
export { useScoutRealtimePins } from "./useScoutRealtimePins";
|
|
10
|
+
// RTK Query infinite scroll hooks
|
|
11
|
+
export { useInfiniteSessionsByHerd, useInfiniteSessionsByDevice, useInfiniteEventsByHerd, useInfiniteEventsByDevice, useInfiniteArtifactsByHerd, useInfiniteArtifactsByDevice, useIntersectionObserver, } from "./useInfiniteQuery";
|
|
12
|
+
// Session summaries and performance hooks
|
|
13
|
+
export { useLoadingPerformance, useSessionSummariesByHerd, useHasSessionSummaries, } from "../store/hooks";
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
import { SupabaseClient } from "@supabase/supabase-js";
|
|
2
|
+
import { useInfiniteSessionsByHerd, useInfiniteEventsByHerd, useInfiniteArtifactsByHerd } from "./useInfiniteQuery";
|
|
3
|
+
import { IHerdModule } from "../types/herd_module";
|
|
4
|
+
import { ISessionSummary } from "../types/db";
|
|
5
|
+
interface UseHerdDataOptions {
|
|
6
|
+
sessionsLimit?: number;
|
|
7
|
+
eventsLimit?: number;
|
|
8
|
+
artifactsLimit?: number;
|
|
9
|
+
enableSessions?: boolean;
|
|
10
|
+
enableEvents?: boolean;
|
|
11
|
+
enableArtifacts?: boolean;
|
|
12
|
+
supabase: SupabaseClient;
|
|
13
|
+
}
|
|
14
|
+
interface UseHerdDataReturn {
|
|
15
|
+
herdModule: IHerdModule | undefined;
|
|
16
|
+
herd: IHerdModule["herd"] | undefined;
|
|
17
|
+
devices: IHerdModule["devices"];
|
|
18
|
+
zones: IHerdModule["zones"];
|
|
19
|
+
plans: IHerdModule["plans"];
|
|
20
|
+
layers: IHerdModule["layers"];
|
|
21
|
+
providers: IHerdModule["providers"];
|
|
22
|
+
labels: IHerdModule["labels"];
|
|
23
|
+
userRoles: IHerdModule["user_roles"];
|
|
24
|
+
sessionSummaries: ISessionSummary | null;
|
|
25
|
+
timestampLastRefreshed: number | null;
|
|
26
|
+
sessions: {
|
|
27
|
+
items: ReturnType<typeof useInfiniteSessionsByHerd>["items"];
|
|
28
|
+
isLoading: boolean;
|
|
29
|
+
isLoadingMore: boolean;
|
|
30
|
+
hasMore: boolean;
|
|
31
|
+
loadMore: () => void;
|
|
32
|
+
refetch: () => void;
|
|
33
|
+
error: any;
|
|
34
|
+
};
|
|
35
|
+
events: {
|
|
36
|
+
items: ReturnType<typeof useInfiniteEventsByHerd>["items"];
|
|
37
|
+
isLoading: boolean;
|
|
38
|
+
isLoadingMore: boolean;
|
|
39
|
+
hasMore: boolean;
|
|
40
|
+
loadMore: () => void;
|
|
41
|
+
refetch: () => void;
|
|
42
|
+
error: any;
|
|
43
|
+
};
|
|
44
|
+
artifacts: {
|
|
45
|
+
items: ReturnType<typeof useInfiniteArtifactsByHerd>["items"];
|
|
46
|
+
isLoading: boolean;
|
|
47
|
+
isLoadingMore: boolean;
|
|
48
|
+
hasMore: boolean;
|
|
49
|
+
loadMore: () => void;
|
|
50
|
+
refetch: () => void;
|
|
51
|
+
error: any;
|
|
52
|
+
};
|
|
53
|
+
isInitialLoading: boolean;
|
|
54
|
+
hasAnyError: boolean;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Comprehensive hook for accessing herd data from both global store and RTK Query
|
|
58
|
+
*
|
|
59
|
+
* @param herdId - The herd ID to fetch data for
|
|
60
|
+
* @param options - Configuration options for data fetching
|
|
61
|
+
* @returns Complete herd data with both structural and paginated content
|
|
62
|
+
*
|
|
63
|
+
* @example
|
|
64
|
+
* ```tsx
|
|
65
|
+
* const {
|
|
66
|
+
* herd,
|
|
67
|
+
* devices,
|
|
68
|
+
* events,
|
|
69
|
+
* sessions,
|
|
70
|
+
* artifacts,
|
|
71
|
+
* sessionSummaries
|
|
72
|
+
* } = useHerdData(123, {
|
|
73
|
+
* supabase,
|
|
74
|
+
* eventsLimit: 20,
|
|
75
|
+
* enableSessions: true
|
|
76
|
+
* });
|
|
77
|
+
*
|
|
78
|
+
* // Use structural data from global store
|
|
79
|
+
* console.log(herd.name, devices.length);
|
|
80
|
+
*
|
|
81
|
+
* // Use paginated data from RTK Query
|
|
82
|
+
* console.log(events.items.length, events.hasMore);
|
|
83
|
+
* if (events.hasMore) {
|
|
84
|
+
* events.loadMore();
|
|
85
|
+
* }
|
|
86
|
+
*
|
|
87
|
+
* // Use session summaries
|
|
88
|
+
* console.log(sessionSummaries?.total_sessions, sessionSummaries?.total_distance_meters);
|
|
89
|
+
* ```
|
|
90
|
+
*/
|
|
91
|
+
export declare const useHerdData: (herdId: number, options: UseHerdDataOptions) => UseHerdDataReturn;
|
|
92
|
+
/**
|
|
93
|
+
* Hook for getting just the structural herd data from global store
|
|
94
|
+
* Useful when you only need basic herd info without paginated content
|
|
95
|
+
*/
|
|
96
|
+
export declare const useHerdStructure: (herdId: number) => {
|
|
97
|
+
herdModule: IHerdModule | undefined;
|
|
98
|
+
herd: {
|
|
99
|
+
created_by: string;
|
|
100
|
+
description: string;
|
|
101
|
+
earthranger_domain: string | null;
|
|
102
|
+
earthranger_token: string | null;
|
|
103
|
+
id: number;
|
|
104
|
+
inserted_at: string;
|
|
105
|
+
is_public: boolean;
|
|
106
|
+
slug: string;
|
|
107
|
+
video_publisher_token: string | null;
|
|
108
|
+
video_server_url: string | null;
|
|
109
|
+
video_subscriber_token: string | null;
|
|
110
|
+
} | undefined;
|
|
111
|
+
devices: import("../types/db").IDevice[];
|
|
112
|
+
zones: import("../types/db").IZoneWithActions[];
|
|
113
|
+
plans: {
|
|
114
|
+
herd_id: number;
|
|
115
|
+
id: number;
|
|
116
|
+
inserted_at: string | null;
|
|
117
|
+
instructions: string;
|
|
118
|
+
name: string;
|
|
119
|
+
plan_type: import("..").Database["public"]["Enums"]["plan_type"];
|
|
120
|
+
}[];
|
|
121
|
+
layers: {
|
|
122
|
+
created_at: string;
|
|
123
|
+
features: import("..").Json;
|
|
124
|
+
herd_id: number;
|
|
125
|
+
id: number;
|
|
126
|
+
}[];
|
|
127
|
+
providers: {
|
|
128
|
+
created_at: string;
|
|
129
|
+
herd_id: number;
|
|
130
|
+
id: number;
|
|
131
|
+
key: string | null;
|
|
132
|
+
source: string;
|
|
133
|
+
type: string;
|
|
134
|
+
}[];
|
|
135
|
+
labels: string[];
|
|
136
|
+
userRoles: import("../types/db").IUserAndRole[] | null;
|
|
137
|
+
sessionSummaries: ISessionSummary | null;
|
|
138
|
+
timestampLastRefreshed: number | null;
|
|
139
|
+
};
|
|
140
|
+
/**
|
|
141
|
+
* Hook for getting all herd structures (without paginated data)
|
|
142
|
+
* Useful for dashboard/overview components
|
|
143
|
+
*/
|
|
144
|
+
export declare const useAllHerds: () => {
|
|
145
|
+
herdModules: IHerdModule[];
|
|
146
|
+
herds: {
|
|
147
|
+
created_by: string;
|
|
148
|
+
description: string;
|
|
149
|
+
earthranger_domain: string | null;
|
|
150
|
+
earthranger_token: string | null;
|
|
151
|
+
id: number;
|
|
152
|
+
inserted_at: string;
|
|
153
|
+
is_public: boolean;
|
|
154
|
+
slug: string;
|
|
155
|
+
video_publisher_token: string | null;
|
|
156
|
+
video_server_url: string | null;
|
|
157
|
+
video_subscriber_token: string | null;
|
|
158
|
+
}[];
|
|
159
|
+
totalHerds: number;
|
|
160
|
+
totalDevices: number;
|
|
161
|
+
sessionSummaries: {
|
|
162
|
+
herdId: number;
|
|
163
|
+
herdSlug: string;
|
|
164
|
+
summaries: ISessionSummary | null;
|
|
165
|
+
}[];
|
|
166
|
+
};
|
|
167
|
+
export {};
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import { useSelector } from "react-redux";
|
|
2
|
+
import { useInfiniteSessionsByHerd, useInfiniteEventsByHerd, useInfiniteArtifactsByHerd, } from "./useInfiniteQuery";
|
|
3
|
+
/**
|
|
4
|
+
* Comprehensive hook for accessing herd data from both global store and RTK Query
|
|
5
|
+
*
|
|
6
|
+
* @param herdId - The herd ID to fetch data for
|
|
7
|
+
* @param options - Configuration options for data fetching
|
|
8
|
+
* @returns Complete herd data with both structural and paginated content
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```tsx
|
|
12
|
+
* const {
|
|
13
|
+
* herd,
|
|
14
|
+
* devices,
|
|
15
|
+
* events,
|
|
16
|
+
* sessions,
|
|
17
|
+
* artifacts,
|
|
18
|
+
* sessionSummaries
|
|
19
|
+
* } = useHerdData(123, {
|
|
20
|
+
* supabase,
|
|
21
|
+
* eventsLimit: 20,
|
|
22
|
+
* enableSessions: true
|
|
23
|
+
* });
|
|
24
|
+
*
|
|
25
|
+
* // Use structural data from global store
|
|
26
|
+
* console.log(herd.name, devices.length);
|
|
27
|
+
*
|
|
28
|
+
* // Use paginated data from RTK Query
|
|
29
|
+
* console.log(events.items.length, events.hasMore);
|
|
30
|
+
* if (events.hasMore) {
|
|
31
|
+
* events.loadMore();
|
|
32
|
+
* }
|
|
33
|
+
*
|
|
34
|
+
* // Use session summaries
|
|
35
|
+
* console.log(sessionSummaries?.total_sessions, sessionSummaries?.total_distance_meters);
|
|
36
|
+
* ```
|
|
37
|
+
*/
|
|
38
|
+
export const useHerdData = (herdId, options) => {
|
|
39
|
+
const { sessionsLimit = 20, eventsLimit = 20, artifactsLimit = 20, enableSessions = true, enableEvents = true, enableArtifacts = true, supabase, } = options;
|
|
40
|
+
// Get structural data from global store
|
|
41
|
+
const herdModule = useSelector((state) => state.scout.herd_modules.find((hm) => hm.herd.id === herdId));
|
|
42
|
+
// RTK Query infinite data hooks
|
|
43
|
+
const sessionsQuery = useInfiniteSessionsByHerd(herdId, {
|
|
44
|
+
limit: sessionsLimit,
|
|
45
|
+
enabled: enableSessions,
|
|
46
|
+
supabase,
|
|
47
|
+
});
|
|
48
|
+
const eventsQuery = useInfiniteEventsByHerd(herdId, {
|
|
49
|
+
limit: eventsLimit,
|
|
50
|
+
enabled: enableEvents,
|
|
51
|
+
supabase,
|
|
52
|
+
});
|
|
53
|
+
const artifactsQuery = useInfiniteArtifactsByHerd(herdId, {
|
|
54
|
+
limit: artifactsLimit,
|
|
55
|
+
enabled: enableArtifacts,
|
|
56
|
+
supabase,
|
|
57
|
+
});
|
|
58
|
+
// Overall loading state - true if any enabled query is loading for the first time
|
|
59
|
+
const isInitialLoading = (enableSessions &&
|
|
60
|
+
sessionsQuery.isLoading &&
|
|
61
|
+
sessionsQuery.items.length === 0) ||
|
|
62
|
+
(enableEvents && eventsQuery.isLoading && eventsQuery.items.length === 0) ||
|
|
63
|
+
(enableArtifacts &&
|
|
64
|
+
artifactsQuery.isLoading &&
|
|
65
|
+
artifactsQuery.items.length === 0);
|
|
66
|
+
// Overall error state - true if any enabled query has an error
|
|
67
|
+
const hasAnyError = (enableSessions && !!sessionsQuery.error) ||
|
|
68
|
+
(enableEvents && !!eventsQuery.error) ||
|
|
69
|
+
(enableArtifacts && !!artifactsQuery.error);
|
|
70
|
+
return {
|
|
71
|
+
// Global store structural data
|
|
72
|
+
herdModule,
|
|
73
|
+
herd: herdModule?.herd,
|
|
74
|
+
devices: herdModule?.devices || [],
|
|
75
|
+
zones: herdModule?.zones || [],
|
|
76
|
+
plans: herdModule?.plans || [],
|
|
77
|
+
layers: herdModule?.layers || [],
|
|
78
|
+
providers: herdModule?.providers || [],
|
|
79
|
+
labels: herdModule?.labels || [],
|
|
80
|
+
userRoles: herdModule?.user_roles || null,
|
|
81
|
+
sessionSummaries: herdModule?.session_summaries || null,
|
|
82
|
+
timestampLastRefreshed: herdModule?.timestamp_last_refreshed || null,
|
|
83
|
+
// RTK Query paginated data
|
|
84
|
+
sessions: {
|
|
85
|
+
items: sessionsQuery.items,
|
|
86
|
+
isLoading: sessionsQuery.isLoading,
|
|
87
|
+
isLoadingMore: sessionsQuery.isLoadingMore,
|
|
88
|
+
hasMore: sessionsQuery.hasMore,
|
|
89
|
+
loadMore: sessionsQuery.loadMore,
|
|
90
|
+
refetch: sessionsQuery.refetch,
|
|
91
|
+
error: sessionsQuery.error,
|
|
92
|
+
},
|
|
93
|
+
events: {
|
|
94
|
+
items: eventsQuery.items,
|
|
95
|
+
isLoading: eventsQuery.isLoading,
|
|
96
|
+
isLoadingMore: eventsQuery.isLoadingMore,
|
|
97
|
+
hasMore: eventsQuery.hasMore,
|
|
98
|
+
loadMore: eventsQuery.loadMore,
|
|
99
|
+
refetch: eventsQuery.refetch,
|
|
100
|
+
error: eventsQuery.error,
|
|
101
|
+
},
|
|
102
|
+
artifacts: {
|
|
103
|
+
items: artifactsQuery.items,
|
|
104
|
+
isLoading: artifactsQuery.isLoading,
|
|
105
|
+
isLoadingMore: artifactsQuery.isLoadingMore,
|
|
106
|
+
hasMore: artifactsQuery.hasMore,
|
|
107
|
+
loadMore: artifactsQuery.loadMore,
|
|
108
|
+
refetch: artifactsQuery.refetch,
|
|
109
|
+
error: artifactsQuery.error,
|
|
110
|
+
},
|
|
111
|
+
// Overall states
|
|
112
|
+
isInitialLoading,
|
|
113
|
+
hasAnyError,
|
|
114
|
+
};
|
|
115
|
+
};
|
|
116
|
+
/**
|
|
117
|
+
* Hook for getting just the structural herd data from global store
|
|
118
|
+
* Useful when you only need basic herd info without paginated content
|
|
119
|
+
*/
|
|
120
|
+
export const useHerdStructure = (herdId) => {
|
|
121
|
+
const herdModule = useSelector((state) => state.scout.herd_modules.find((hm) => hm.herd.id === herdId));
|
|
122
|
+
return {
|
|
123
|
+
herdModule,
|
|
124
|
+
herd: herdModule?.herd,
|
|
125
|
+
devices: herdModule?.devices || [],
|
|
126
|
+
zones: herdModule?.zones || [],
|
|
127
|
+
plans: herdModule?.plans || [],
|
|
128
|
+
layers: herdModule?.layers || [],
|
|
129
|
+
providers: herdModule?.providers || [],
|
|
130
|
+
labels: herdModule?.labels || [],
|
|
131
|
+
userRoles: herdModule?.user_roles || null,
|
|
132
|
+
sessionSummaries: herdModule?.session_summaries || null,
|
|
133
|
+
timestampLastRefreshed: herdModule?.timestamp_last_refreshed || null,
|
|
134
|
+
};
|
|
135
|
+
};
|
|
136
|
+
/**
|
|
137
|
+
* Hook for getting all herd structures (without paginated data)
|
|
138
|
+
* Useful for dashboard/overview components
|
|
139
|
+
*/
|
|
140
|
+
export const useAllHerds = () => {
|
|
141
|
+
const herdModules = useSelector((state) => state.scout.herd_modules);
|
|
142
|
+
return {
|
|
143
|
+
herdModules,
|
|
144
|
+
herds: herdModules.map((hm) => hm.herd),
|
|
145
|
+
totalHerds: herdModules.length,
|
|
146
|
+
totalDevices: herdModules.reduce((sum, hm) => sum + hm.devices.length, 0),
|
|
147
|
+
sessionSummaries: herdModules.map((hm) => ({
|
|
148
|
+
herdId: hm.herd.id,
|
|
149
|
+
herdSlug: hm.herd.slug,
|
|
150
|
+
summaries: hm.session_summaries,
|
|
151
|
+
})),
|
|
152
|
+
};
|
|
153
|
+
};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { SupabaseClient } from "@supabase/supabase-js";
|
|
2
|
+
import { IArtifactWithMediaUrl, ISessionWithCoordinates, IEventAndTagsPrettyLocation } from "../types/db";
|
|
3
|
+
interface UseInfiniteScrollOptions {
|
|
4
|
+
limit?: number;
|
|
5
|
+
enabled?: boolean;
|
|
6
|
+
supabase: SupabaseClient;
|
|
7
|
+
}
|
|
8
|
+
interface InfiniteScrollData<T> {
|
|
9
|
+
items: T[];
|
|
10
|
+
isLoading: boolean;
|
|
11
|
+
isLoadingMore: boolean;
|
|
12
|
+
hasMore: boolean;
|
|
13
|
+
loadMore: () => void;
|
|
14
|
+
refetch: () => void;
|
|
15
|
+
error: any;
|
|
16
|
+
}
|
|
17
|
+
export declare const useInfiniteSessionsByHerd: (herdId: number, options: UseInfiniteScrollOptions) => InfiniteScrollData<ISessionWithCoordinates>;
|
|
18
|
+
export declare const useInfiniteSessionsByDevice: (deviceId: number, options: UseInfiniteScrollOptions) => InfiniteScrollData<ISessionWithCoordinates>;
|
|
19
|
+
export declare const useInfiniteEventsByHerd: (herdId: number, options: UseInfiniteScrollOptions) => InfiniteScrollData<IEventAndTagsPrettyLocation>;
|
|
20
|
+
export declare const useInfiniteEventsByDevice: (deviceId: number, options: UseInfiniteScrollOptions) => InfiniteScrollData<IEventAndTagsPrettyLocation>;
|
|
21
|
+
export declare const useInfiniteArtifactsByHerd: (herdId: number, options: UseInfiniteScrollOptions) => InfiniteScrollData<IArtifactWithMediaUrl>;
|
|
22
|
+
export declare const useInfiniteArtifactsByDevice: (deviceId: number, options: UseInfiniteScrollOptions) => InfiniteScrollData<IArtifactWithMediaUrl>;
|
|
23
|
+
export declare const useIntersectionObserver: (callback: () => void, options?: IntersectionObserverInit) => import("react").Dispatch<import("react").SetStateAction<Element | null>>;
|
|
24
|
+
export {};
|