@adventurelabs/scout-core 1.2.1 → 1.2.4
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/index.d.ts +1 -0
- package/dist/helpers/index.js +1 -0
- package/dist/helpers/pins.d.ts +11 -0
- package/dist/helpers/pins.js +142 -0
- package/dist/hooks/index.d.ts +4 -0
- package/dist/hooks/index.js +4 -0
- package/dist/hooks/useScoutRealtimeConnectivity.d.ts +1 -1
- package/dist/hooks/useScoutRealtimeConnectivity.js +9 -9
- package/dist/hooks/useScoutRealtimeDevices.d.ts +1 -1
- package/dist/hooks/useScoutRealtimeDevices.js +9 -9
- package/dist/hooks/useScoutRealtimeEvents.d.ts +5 -0
- package/dist/hooks/useScoutRealtimeEvents.js +96 -0
- package/dist/hooks/useScoutRealtimePins.d.ts +5 -0
- package/dist/hooks/useScoutRealtimePins.js +80 -0
- package/dist/hooks/useScoutRealtimePlans.d.ts +5 -0
- package/dist/hooks/useScoutRealtimePlans.js +83 -0
- package/dist/hooks/useScoutRealtimeSessions.d.ts +5 -0
- package/dist/hooks/useScoutRealtimeSessions.js +83 -0
- package/dist/hooks/useScoutRealtimeTags.d.ts +5 -0
- package/dist/hooks/useScoutRealtimeTags.js +85 -0
- package/dist/hooks/useScoutRealtimeVersionsSoftware.d.ts +1 -1
- package/dist/hooks/useScoutRealtimeVersionsSoftware.js +9 -9
- package/dist/index.d.ts +5 -0
- package/dist/index.js +5 -0
- package/dist/providers/ScoutRefreshProvider.d.ts +75 -0
- package/dist/types/db.d.ts +2 -0
- package/dist/types/supabase.d.ts +78 -0
- package/package.json +1 -1
package/dist/helpers/index.d.ts
CHANGED
package/dist/helpers/index.js
CHANGED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Database } from "../types/supabase";
|
|
2
|
+
import { IPin, PinInsert } from "../types/db";
|
|
3
|
+
import { IWebResponseCompatible } from "../types/requests";
|
|
4
|
+
import { SupabaseClient } from "@supabase/supabase-js";
|
|
5
|
+
export declare function get_pins_for_herd(client: SupabaseClient<Database>, herd_id: number): Promise<IWebResponseCompatible<IPin[]>>;
|
|
6
|
+
export declare function get_pin_by_id(client: SupabaseClient<Database>, pin_id: number): Promise<IWebResponseCompatible<IPin | null>>;
|
|
7
|
+
export declare function create_pin(client: SupabaseClient<Database>, newPin: PinInsert): Promise<IWebResponseCompatible<IPin | null>>;
|
|
8
|
+
export declare function update_pin(client: SupabaseClient<Database>, pin_id: number, updatedPin: Partial<PinInsert>): Promise<IWebResponseCompatible<IPin | null>>;
|
|
9
|
+
export declare function delete_pin(client: SupabaseClient<Database>, pin_id: number): Promise<IWebResponseCompatible<IPin | null>>;
|
|
10
|
+
export declare function get_pins_by_created_by(client: SupabaseClient<Database>, user_id: string): Promise<IWebResponseCompatible<IPin[]>>;
|
|
11
|
+
export declare function get_pins_by_color(client: SupabaseClient<Database>, herd_id: number, color: string): Promise<IWebResponseCompatible<IPin[]>>;
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import { IWebResponse } from "../types/requests";
|
|
2
|
+
export async function get_pins_for_herd(client, herd_id) {
|
|
3
|
+
// Call get_pins_for_herd with rpc
|
|
4
|
+
const { data, error } = await client.rpc("get_pins_for_herd", {
|
|
5
|
+
herd_id_caller: herd_id,
|
|
6
|
+
});
|
|
7
|
+
if (error) {
|
|
8
|
+
return IWebResponse.error(error.message).to_compatible();
|
|
9
|
+
}
|
|
10
|
+
if (!data) {
|
|
11
|
+
return IWebResponse.error("No pins found for herd").to_compatible();
|
|
12
|
+
}
|
|
13
|
+
return IWebResponse.success(data).to_compatible();
|
|
14
|
+
}
|
|
15
|
+
export async function get_pin_by_id(client, pin_id) {
|
|
16
|
+
const { data, error } = await client
|
|
17
|
+
.from("pins")
|
|
18
|
+
.select("*")
|
|
19
|
+
.eq("id", pin_id)
|
|
20
|
+
.single();
|
|
21
|
+
if (error) {
|
|
22
|
+
return IWebResponse.error(error.message).to_compatible();
|
|
23
|
+
}
|
|
24
|
+
if (!data) {
|
|
25
|
+
return IWebResponse.error("Pin not found").to_compatible();
|
|
26
|
+
}
|
|
27
|
+
// Convert to pretty location format with coordinates
|
|
28
|
+
const pinWithCoords = {
|
|
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();
|
|
34
|
+
}
|
|
35
|
+
export async function create_pin(client, newPin) {
|
|
36
|
+
const { data, error } = await client
|
|
37
|
+
.from("pins")
|
|
38
|
+
.insert([newPin])
|
|
39
|
+
.select("*")
|
|
40
|
+
.single();
|
|
41
|
+
if (error) {
|
|
42
|
+
return IWebResponse.error(error.message).to_compatible();
|
|
43
|
+
}
|
|
44
|
+
if (!data) {
|
|
45
|
+
return IWebResponse.error("Failed to create pin").to_compatible();
|
|
46
|
+
}
|
|
47
|
+
// Convert to pretty location format with coordinates
|
|
48
|
+
const pinWithCoords = {
|
|
49
|
+
...data,
|
|
50
|
+
latitude: data.latitude ? parseFloat(data.latitude.toString()) : 0,
|
|
51
|
+
longitude: data.longitude ? parseFloat(data.longitude.toString()) : 0,
|
|
52
|
+
};
|
|
53
|
+
return IWebResponse.success(pinWithCoords).to_compatible();
|
|
54
|
+
}
|
|
55
|
+
export async function update_pin(client, pin_id, updatedPin) {
|
|
56
|
+
// Remove fields that shouldn't be updated
|
|
57
|
+
const updateData = { ...updatedPin };
|
|
58
|
+
delete updateData.id;
|
|
59
|
+
delete updateData.created_at;
|
|
60
|
+
delete updateData.created_by; // RLS handles permissions
|
|
61
|
+
const { data, error } = await client
|
|
62
|
+
.from("pins")
|
|
63
|
+
.update(updateData)
|
|
64
|
+
.eq("id", pin_id)
|
|
65
|
+
.select("*")
|
|
66
|
+
.single();
|
|
67
|
+
if (error) {
|
|
68
|
+
return IWebResponse.error(error.message).to_compatible();
|
|
69
|
+
}
|
|
70
|
+
if (!data) {
|
|
71
|
+
return IWebResponse.error("Pin not found or update failed").to_compatible();
|
|
72
|
+
}
|
|
73
|
+
// Convert to pretty location format with coordinates
|
|
74
|
+
const pinWithCoords = {
|
|
75
|
+
...data,
|
|
76
|
+
latitude: data.latitude ? parseFloat(data.latitude.toString()) : 0,
|
|
77
|
+
longitude: data.longitude ? parseFloat(data.longitude.toString()) : 0,
|
|
78
|
+
};
|
|
79
|
+
return IWebResponse.success(pinWithCoords).to_compatible();
|
|
80
|
+
}
|
|
81
|
+
export async function delete_pin(client, pin_id) {
|
|
82
|
+
const { data, error } = await client
|
|
83
|
+
.from("pins")
|
|
84
|
+
.delete()
|
|
85
|
+
.eq("id", pin_id)
|
|
86
|
+
.select("*")
|
|
87
|
+
.single();
|
|
88
|
+
if (error) {
|
|
89
|
+
return IWebResponse.error(error.message).to_compatible();
|
|
90
|
+
}
|
|
91
|
+
if (!data) {
|
|
92
|
+
return IWebResponse.error("Pin not found or deletion failed").to_compatible();
|
|
93
|
+
}
|
|
94
|
+
// Convert to pretty location format with coordinates
|
|
95
|
+
const pinWithCoords = {
|
|
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();
|
|
101
|
+
}
|
|
102
|
+
export async function get_pins_by_created_by(client, user_id) {
|
|
103
|
+
const { data, error } = await client
|
|
104
|
+
.from("pins")
|
|
105
|
+
.select("*")
|
|
106
|
+
.eq("created_by", user_id)
|
|
107
|
+
.order("created_at", { ascending: false });
|
|
108
|
+
if (error) {
|
|
109
|
+
return IWebResponse.error(error.message).to_compatible();
|
|
110
|
+
}
|
|
111
|
+
if (!data) {
|
|
112
|
+
return IWebResponse.error("No pins found for user").to_compatible();
|
|
113
|
+
}
|
|
114
|
+
// Convert to pretty location format with coordinates
|
|
115
|
+
const pinsWithCoords = data.map((pin) => ({
|
|
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();
|
|
121
|
+
}
|
|
122
|
+
export async function get_pins_by_color(client, herd_id, color) {
|
|
123
|
+
const { data, error } = await client
|
|
124
|
+
.from("pins")
|
|
125
|
+
.select("*")
|
|
126
|
+
.eq("herd_id", herd_id)
|
|
127
|
+
.eq("color", color)
|
|
128
|
+
.order("created_at", { ascending: false });
|
|
129
|
+
if (error) {
|
|
130
|
+
return IWebResponse.error(error.message).to_compatible();
|
|
131
|
+
}
|
|
132
|
+
if (!data) {
|
|
133
|
+
return IWebResponse.error(`No pins found with color: ${color}`).to_compatible();
|
|
134
|
+
}
|
|
135
|
+
// Convert to pretty location format with coordinates
|
|
136
|
+
const pinsWithCoords = data.map((pin) => ({
|
|
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();
|
|
142
|
+
}
|
package/dist/hooks/index.d.ts
CHANGED
|
@@ -2,3 +2,7 @@ export { useScoutRefresh, type UseScoutRefreshOptions, } from "./useScoutRefresh
|
|
|
2
2
|
export { useScoutRealtimeConnectivity } from "./useScoutRealtimeConnectivity";
|
|
3
3
|
export { useScoutRealtimeDevices } from "./useScoutRealtimeDevices";
|
|
4
4
|
export { useScoutRealtimeVersionsSoftware } from "./useScoutRealtimeVersionsSoftware";
|
|
5
|
+
export { useScoutRealtimeEvents } from "./useScoutRealtimeEvents";
|
|
6
|
+
export { useScoutRealtimeTags } from "./useScoutRealtimeTags";
|
|
7
|
+
export { useScoutRealtimeSessions } from "./useScoutRealtimeSessions";
|
|
8
|
+
export { useScoutRealtimePlans } from "./useScoutRealtimePlans";
|
package/dist/hooks/index.js
CHANGED
|
@@ -2,3 +2,7 @@ export { useScoutRefresh, } from "./useScoutRefresh";
|
|
|
2
2
|
export { useScoutRealtimeConnectivity } from "./useScoutRealtimeConnectivity";
|
|
3
3
|
export { useScoutRealtimeDevices } from "./useScoutRealtimeDevices";
|
|
4
4
|
export { useScoutRealtimeVersionsSoftware } from "./useScoutRealtimeVersionsSoftware";
|
|
5
|
+
export { useScoutRealtimeEvents } from "./useScoutRealtimeEvents";
|
|
6
|
+
export { useScoutRealtimeTags } from "./useScoutRealtimeTags";
|
|
7
|
+
export { useScoutRealtimeSessions } from "./useScoutRealtimeSessions";
|
|
8
|
+
export { useScoutRealtimePlans } from "./useScoutRealtimePlans";
|
|
@@ -2,4 +2,4 @@ import { SupabaseClient } from "@supabase/supabase-js";
|
|
|
2
2
|
import { Database } from "../types/supabase";
|
|
3
3
|
import { IConnectivityWithCoordinates } from "../types/db";
|
|
4
4
|
import { RealtimeData } from "../types/realtime";
|
|
5
|
-
export declare function useScoutRealtimeConnectivity(scoutSupabase: SupabaseClient<Database>): RealtimeData<IConnectivityWithCoordinates>
|
|
5
|
+
export declare function useScoutRealtimeConnectivity(scoutSupabase: SupabaseClient<Database>): [RealtimeData<IConnectivityWithCoordinates> | null, () => void];
|
|
@@ -4,7 +4,7 @@ import { useEffect, useRef, useCallback, useState, useMemo } from "react";
|
|
|
4
4
|
import { EnumRealtimeOperation } from "../types/realtime";
|
|
5
5
|
export function useScoutRealtimeConnectivity(scoutSupabase) {
|
|
6
6
|
const channels = useRef([]);
|
|
7
|
-
const [
|
|
7
|
+
const [latestConnectivityUpdate, setLatestConnectivityUpdate] = useState(null);
|
|
8
8
|
const activeHerdId = useSelector((state) => state.scout.active_herd_id);
|
|
9
9
|
const herdModules = useSelector((state) => state.scout.herd_modules);
|
|
10
10
|
// Create stable reference for GPS device IDs to prevent unnecessary refetching
|
|
@@ -49,11 +49,11 @@ export function useScoutRealtimeConnectivity(scoutSupabase) {
|
|
|
49
49
|
data: connectivityData,
|
|
50
50
|
operation,
|
|
51
51
|
};
|
|
52
|
-
|
|
52
|
+
setLatestConnectivityUpdate(realtimeData);
|
|
53
53
|
}, []);
|
|
54
|
-
// Clear
|
|
55
|
-
const
|
|
56
|
-
|
|
54
|
+
// Clear latest update
|
|
55
|
+
const clearLatestUpdate = useCallback(() => {
|
|
56
|
+
setLatestConnectivityUpdate(null);
|
|
57
57
|
}, []);
|
|
58
58
|
useEffect(() => {
|
|
59
59
|
if (!scoutSupabase || gpsDeviceIds === "")
|
|
@@ -61,8 +61,8 @@ export function useScoutRealtimeConnectivity(scoutSupabase) {
|
|
|
61
61
|
// Clean up existing channels
|
|
62
62
|
channels.current.forEach((channel) => scoutSupabase.removeChannel(channel));
|
|
63
63
|
channels.current = [];
|
|
64
|
-
// Clear previous
|
|
65
|
-
|
|
64
|
+
// Clear previous update when switching herds
|
|
65
|
+
clearLatestUpdate();
|
|
66
66
|
// Create connectivity channel
|
|
67
67
|
const channel = scoutSupabase
|
|
68
68
|
.channel(`${activeHerdId}-connectivity`, { config: { private: true } })
|
|
@@ -78,7 +78,7 @@ export function useScoutRealtimeConnectivity(scoutSupabase) {
|
|
|
78
78
|
gpsDeviceIds,
|
|
79
79
|
activeHerdId,
|
|
80
80
|
handleConnectivityBroadcast,
|
|
81
|
-
|
|
81
|
+
clearLatestUpdate,
|
|
82
82
|
]);
|
|
83
|
-
return
|
|
83
|
+
return [latestConnectivityUpdate, clearLatestUpdate];
|
|
84
84
|
}
|
|
@@ -2,4 +2,4 @@ import { SupabaseClient } from "@supabase/supabase-js";
|
|
|
2
2
|
import { Database } from "../types/supabase";
|
|
3
3
|
import { IDevicePrettyLocation } from "../types/db";
|
|
4
4
|
import { RealtimeData } from "../types/realtime";
|
|
5
|
-
export declare function useScoutRealtimeDevices(scoutSupabase: SupabaseClient<Database>): RealtimeData<IDevicePrettyLocation>
|
|
5
|
+
export declare function useScoutRealtimeDevices(scoutSupabase: SupabaseClient<Database>): [RealtimeData<IDevicePrettyLocation> | null, () => void];
|
|
@@ -7,7 +7,7 @@ import { EnumRealtimeOperation } from "../types/realtime";
|
|
|
7
7
|
export function useScoutRealtimeDevices(scoutSupabase) {
|
|
8
8
|
const channels = useRef([]);
|
|
9
9
|
const dispatch = useAppDispatch();
|
|
10
|
-
const [
|
|
10
|
+
const [latestDeviceUpdate, setLatestDeviceUpdate] = useState(null);
|
|
11
11
|
const activeHerdId = useSelector((state) => state.scout.active_herd_id);
|
|
12
12
|
// Device broadcast handler
|
|
13
13
|
const handleDeviceBroadcast = useCallback((payload) => {
|
|
@@ -45,11 +45,11 @@ export function useScoutRealtimeDevices(scoutSupabase) {
|
|
|
45
45
|
operation,
|
|
46
46
|
};
|
|
47
47
|
console.log(`[scout-core realtime] DEVICE ${data.operation} received:`, JSON.stringify(realtimeData));
|
|
48
|
-
|
|
48
|
+
setLatestDeviceUpdate(realtimeData);
|
|
49
49
|
}, [dispatch]);
|
|
50
|
-
// Clear
|
|
51
|
-
const
|
|
52
|
-
|
|
50
|
+
// Clear latest update
|
|
51
|
+
const clearLatestUpdate = useCallback(() => {
|
|
52
|
+
setLatestDeviceUpdate(null);
|
|
53
53
|
}, []);
|
|
54
54
|
const cleanupChannels = () => {
|
|
55
55
|
channels.current.forEach((channel) => scoutSupabase.removeChannel(channel));
|
|
@@ -70,14 +70,14 @@ export function useScoutRealtimeDevices(scoutSupabase) {
|
|
|
70
70
|
};
|
|
71
71
|
useEffect(() => {
|
|
72
72
|
cleanupChannels();
|
|
73
|
-
// Clear previous
|
|
74
|
-
|
|
73
|
+
// Clear previous update when switching herds
|
|
74
|
+
clearLatestUpdate();
|
|
75
75
|
// Create devices channel for active herd
|
|
76
76
|
if (activeHerdId) {
|
|
77
77
|
const channel = createDevicesChannel(activeHerdId);
|
|
78
78
|
channels.current.push(channel);
|
|
79
79
|
}
|
|
80
80
|
return cleanupChannels;
|
|
81
|
-
}, [activeHerdId,
|
|
82
|
-
return
|
|
81
|
+
}, [activeHerdId, clearLatestUpdate]);
|
|
82
|
+
return [latestDeviceUpdate, clearLatestUpdate];
|
|
83
83
|
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { SupabaseClient } from "@supabase/supabase-js";
|
|
2
|
+
import { Database } from "../types/supabase";
|
|
3
|
+
import { IEventAndTagsPrettyLocation } from "../types/db";
|
|
4
|
+
import { RealtimeData } from "../types/realtime";
|
|
5
|
+
export declare function useScoutRealtimeEvents(scoutSupabase: SupabaseClient<Database>, shouldUpdateGlobalStateOnChanges: boolean): [RealtimeData<IEventAndTagsPrettyLocation> | null, () => void];
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { useAppDispatch } from "../store/hooks";
|
|
3
|
+
import { useSelector } from "react-redux";
|
|
4
|
+
import { useEffect, useRef, useCallback, useState } from "react";
|
|
5
|
+
import { updateEventValuesForHerdModule } from "../store/scout";
|
|
6
|
+
import { EnumRealtimeOperation } from "../types/realtime";
|
|
7
|
+
export function useScoutRealtimeEvents(scoutSupabase, shouldUpdateGlobalStateOnChanges) {
|
|
8
|
+
const channels = useRef([]);
|
|
9
|
+
const dispatch = useAppDispatch();
|
|
10
|
+
const [latestEventUpdate, setLatestEventUpdate] = useState(null);
|
|
11
|
+
const activeHerdId = useSelector((state) => state.scout.active_herd_id);
|
|
12
|
+
// Event broadcast handler
|
|
13
|
+
const handleEventBroadcast = useCallback((payload) => {
|
|
14
|
+
console.log("[Events] Broadcast received:", payload.payload.operation);
|
|
15
|
+
const data = payload.payload;
|
|
16
|
+
const eventData = data.record || data.old_record;
|
|
17
|
+
if (!eventData)
|
|
18
|
+
return;
|
|
19
|
+
let operation;
|
|
20
|
+
// TODO: UNCOMMENT GLOBAL STORE OPERATIONS IF OKAY WITH FREQUENT
|
|
21
|
+
switch (data.operation) {
|
|
22
|
+
case "INSERT":
|
|
23
|
+
operation = EnumRealtimeOperation.INSERT;
|
|
24
|
+
if (data.record && activeHerdId && shouldUpdateGlobalStateOnChanges) {
|
|
25
|
+
console.log("[Events] New event received:", data.record);
|
|
26
|
+
// For events, we need to update the event values in the herd module
|
|
27
|
+
dispatch(updateEventValuesForHerdModule({
|
|
28
|
+
herd_id: activeHerdId,
|
|
29
|
+
events: [data.record],
|
|
30
|
+
}));
|
|
31
|
+
}
|
|
32
|
+
break;
|
|
33
|
+
case "UPDATE":
|
|
34
|
+
operation = EnumRealtimeOperation.UPDATE;
|
|
35
|
+
if (data.record && activeHerdId && shouldUpdateGlobalStateOnChanges) {
|
|
36
|
+
console.log("[Events] Event updated:", data.record);
|
|
37
|
+
dispatch(updateEventValuesForHerdModule({
|
|
38
|
+
herd_id: activeHerdId,
|
|
39
|
+
events: [data.record],
|
|
40
|
+
}));
|
|
41
|
+
}
|
|
42
|
+
break;
|
|
43
|
+
case "DELETE":
|
|
44
|
+
operation = EnumRealtimeOperation.DELETE;
|
|
45
|
+
if (data.old_record &&
|
|
46
|
+
activeHerdId &&
|
|
47
|
+
shouldUpdateGlobalStateOnChanges) {
|
|
48
|
+
console.log("[Events] Event deleted:", data.old_record);
|
|
49
|
+
// TODO: WRITE DELETION STORE ACTION
|
|
50
|
+
console.log("[Events] Event deletion detected - manual refresh may be needed");
|
|
51
|
+
}
|
|
52
|
+
break;
|
|
53
|
+
default:
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
const realtimeData = {
|
|
57
|
+
data: eventData,
|
|
58
|
+
operation,
|
|
59
|
+
};
|
|
60
|
+
console.log(`[scout-core realtime] EVENT ${data.operation} received:`, JSON.stringify(realtimeData));
|
|
61
|
+
setLatestEventUpdate(realtimeData);
|
|
62
|
+
}, [dispatch, activeHerdId]);
|
|
63
|
+
// Clear latest update
|
|
64
|
+
const clearLatestUpdate = useCallback(() => {
|
|
65
|
+
setLatestEventUpdate(null);
|
|
66
|
+
}, []);
|
|
67
|
+
const cleanupChannels = () => {
|
|
68
|
+
channels.current.forEach((channel) => scoutSupabase.removeChannel(channel));
|
|
69
|
+
channels.current = [];
|
|
70
|
+
};
|
|
71
|
+
const createEventsChannel = (herdId) => {
|
|
72
|
+
return scoutSupabase
|
|
73
|
+
.channel(`${herdId}-events`, { config: { private: true } })
|
|
74
|
+
.on("broadcast", { event: "*" }, handleEventBroadcast)
|
|
75
|
+
.subscribe((status) => {
|
|
76
|
+
if (status === "SUBSCRIBED") {
|
|
77
|
+
console.log(`[Events] ✅ Connected to herd ${herdId}`);
|
|
78
|
+
}
|
|
79
|
+
else if (status === "CHANNEL_ERROR") {
|
|
80
|
+
console.warn(`[Events] 🟡 Failed to connect to herd ${herdId}`);
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
};
|
|
84
|
+
useEffect(() => {
|
|
85
|
+
cleanupChannels();
|
|
86
|
+
// Clear previous update when switching herds
|
|
87
|
+
clearLatestUpdate();
|
|
88
|
+
// Create events channel for active herd
|
|
89
|
+
if (activeHerdId) {
|
|
90
|
+
const channel = createEventsChannel(activeHerdId);
|
|
91
|
+
channels.current.push(channel);
|
|
92
|
+
}
|
|
93
|
+
return cleanupChannels;
|
|
94
|
+
}, [activeHerdId, clearLatestUpdate]);
|
|
95
|
+
return [latestEventUpdate, clearLatestUpdate];
|
|
96
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { SupabaseClient } from "@supabase/supabase-js";
|
|
2
|
+
import { Database } from "../types/supabase";
|
|
3
|
+
import { IPin } from "../types/db";
|
|
4
|
+
import { RealtimeData } from "../types/realtime";
|
|
5
|
+
export declare function useScoutRealtimePins(scoutSupabase: SupabaseClient<Database>, shouldUpdateGlobalStateOnChanges?: boolean): [RealtimeData<IPin> | null, () => void];
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { useSelector } from "react-redux";
|
|
3
|
+
import { useEffect, useRef, useCallback, useState } from "react";
|
|
4
|
+
import { EnumRealtimeOperation } from "../types/realtime";
|
|
5
|
+
export function useScoutRealtimePins(scoutSupabase, shouldUpdateGlobalStateOnChanges) {
|
|
6
|
+
const channels = useRef([]);
|
|
7
|
+
const [latestPinUpdate, setLatestPinUpdate] = useState(null);
|
|
8
|
+
const activeHerdId = useSelector((state) => state.scout.active_herd_id);
|
|
9
|
+
// Pin broadcast handler
|
|
10
|
+
const handlePinBroadcast = useCallback((payload) => {
|
|
11
|
+
console.log("[Pins] Broadcast received:", payload.payload.operation);
|
|
12
|
+
const data = payload.payload;
|
|
13
|
+
const pinData = data.record || data.old_record;
|
|
14
|
+
if (!pinData)
|
|
15
|
+
return;
|
|
16
|
+
let operation;
|
|
17
|
+
switch (data.operation) {
|
|
18
|
+
case "INSERT":
|
|
19
|
+
operation = EnumRealtimeOperation.INSERT;
|
|
20
|
+
if (data.record && shouldUpdateGlobalStateOnChanges) {
|
|
21
|
+
console.log("[Pins] New pin received:", data.record);
|
|
22
|
+
// TODO: dispatch(addPinToStore(data.record));
|
|
23
|
+
}
|
|
24
|
+
break;
|
|
25
|
+
case "UPDATE":
|
|
26
|
+
operation = EnumRealtimeOperation.UPDATE;
|
|
27
|
+
if (data.record && shouldUpdateGlobalStateOnChanges) {
|
|
28
|
+
// TODO: dispatch(updatePinInStore(data.record));
|
|
29
|
+
}
|
|
30
|
+
break;
|
|
31
|
+
case "DELETE":
|
|
32
|
+
operation = EnumRealtimeOperation.DELETE;
|
|
33
|
+
if (data.old_record && shouldUpdateGlobalStateOnChanges) {
|
|
34
|
+
// TODO: dispatch(deletePinFromStore(data.old_record));
|
|
35
|
+
}
|
|
36
|
+
break;
|
|
37
|
+
default:
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
const realtimeData = {
|
|
41
|
+
data: pinData,
|
|
42
|
+
operation,
|
|
43
|
+
};
|
|
44
|
+
console.log(`[scout-core realtime] PIN ${data.operation} received for pin "${pinData.name}" (${pinData.id}):`, JSON.stringify(realtimeData));
|
|
45
|
+
setLatestPinUpdate(realtimeData);
|
|
46
|
+
}, [shouldUpdateGlobalStateOnChanges]);
|
|
47
|
+
// Clear latest update
|
|
48
|
+
const clearLatestUpdate = useCallback(() => {
|
|
49
|
+
setLatestPinUpdate(null);
|
|
50
|
+
}, []);
|
|
51
|
+
const cleanupChannels = () => {
|
|
52
|
+
channels.current.forEach((channel) => scoutSupabase.removeChannel(channel));
|
|
53
|
+
channels.current = [];
|
|
54
|
+
};
|
|
55
|
+
const createPinsChannel = (herdId) => {
|
|
56
|
+
return scoutSupabase
|
|
57
|
+
.channel(`${herdId}-pins`, { config: { private: true } })
|
|
58
|
+
.on("broadcast", { event: "*" }, handlePinBroadcast)
|
|
59
|
+
.subscribe((status) => {
|
|
60
|
+
if (status === "SUBSCRIBED") {
|
|
61
|
+
console.log(`[Pins] ✅ Connected to herd ${herdId} pins broadcasts`);
|
|
62
|
+
}
|
|
63
|
+
else if (status === "CHANNEL_ERROR") {
|
|
64
|
+
console.warn(`[Pins] 🟡 Failed to connect to herd ${herdId} pins broadcasts`);
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
};
|
|
68
|
+
useEffect(() => {
|
|
69
|
+
cleanupChannels();
|
|
70
|
+
// Clear previous update when switching herds
|
|
71
|
+
clearLatestUpdate();
|
|
72
|
+
// Create pins channel for active herd
|
|
73
|
+
if (activeHerdId) {
|
|
74
|
+
const channel = createPinsChannel(activeHerdId);
|
|
75
|
+
channels.current.push(channel);
|
|
76
|
+
}
|
|
77
|
+
return cleanupChannels;
|
|
78
|
+
}, [activeHerdId, clearLatestUpdate]);
|
|
79
|
+
return [latestPinUpdate, clearLatestUpdate];
|
|
80
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { SupabaseClient } from "@supabase/supabase-js";
|
|
2
|
+
import { Database } from "../types/supabase";
|
|
3
|
+
import { IPlan } from "../types/db";
|
|
4
|
+
import { RealtimeData } from "../types/realtime";
|
|
5
|
+
export declare function useScoutRealtimePlans(scoutSupabase: SupabaseClient<Database>, shouldUpdateGlobalStateOnChanges: boolean): [RealtimeData<IPlan> | null, () => void];
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { useAppDispatch } from "../store/hooks";
|
|
3
|
+
import { useSelector } from "react-redux";
|
|
4
|
+
import { useEffect, useRef, useCallback, useState } from "react";
|
|
5
|
+
import { addPlan, deletePlan, updatePlan } from "../store/scout";
|
|
6
|
+
import { EnumRealtimeOperation } from "../types/realtime";
|
|
7
|
+
export function useScoutRealtimePlans(scoutSupabase, shouldUpdateGlobalStateOnChanges) {
|
|
8
|
+
const channels = useRef([]);
|
|
9
|
+
const dispatch = useAppDispatch();
|
|
10
|
+
const [latestPlanUpdate, setLatestPlanUpdate] = useState(null);
|
|
11
|
+
const activeHerdId = useSelector((state) => state.scout.active_herd_id);
|
|
12
|
+
// Plan broadcast handler
|
|
13
|
+
const handlePlanBroadcast = useCallback((payload) => {
|
|
14
|
+
console.log("[Plans] Broadcast received:", payload.payload.operation);
|
|
15
|
+
const data = payload.payload;
|
|
16
|
+
const planData = data.record || data.old_record;
|
|
17
|
+
if (!planData)
|
|
18
|
+
return;
|
|
19
|
+
let operation;
|
|
20
|
+
switch (data.operation) {
|
|
21
|
+
case "INSERT":
|
|
22
|
+
operation = EnumRealtimeOperation.INSERT;
|
|
23
|
+
if (data.record && shouldUpdateGlobalStateOnChanges) {
|
|
24
|
+
console.log("[Plans] New plan received:", data.record);
|
|
25
|
+
dispatch(addPlan(data.record));
|
|
26
|
+
}
|
|
27
|
+
break;
|
|
28
|
+
case "UPDATE":
|
|
29
|
+
operation = EnumRealtimeOperation.UPDATE;
|
|
30
|
+
if (data.record && shouldUpdateGlobalStateOnChanges) {
|
|
31
|
+
dispatch(updatePlan(data.record));
|
|
32
|
+
}
|
|
33
|
+
break;
|
|
34
|
+
case "DELETE":
|
|
35
|
+
operation = EnumRealtimeOperation.DELETE;
|
|
36
|
+
if (data.old_record && shouldUpdateGlobalStateOnChanges) {
|
|
37
|
+
dispatch(deletePlan(data.old_record));
|
|
38
|
+
}
|
|
39
|
+
break;
|
|
40
|
+
default:
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
const realtimeData = {
|
|
44
|
+
data: planData,
|
|
45
|
+
operation,
|
|
46
|
+
};
|
|
47
|
+
console.log(`[scout-core realtime] PLAN ${data.operation} received:`, JSON.stringify(realtimeData));
|
|
48
|
+
setLatestPlanUpdate(realtimeData);
|
|
49
|
+
}, [dispatch]);
|
|
50
|
+
// Clear latest update
|
|
51
|
+
const clearLatestUpdate = useCallback(() => {
|
|
52
|
+
setLatestPlanUpdate(null);
|
|
53
|
+
}, []);
|
|
54
|
+
const cleanupChannels = () => {
|
|
55
|
+
channels.current.forEach((channel) => scoutSupabase.removeChannel(channel));
|
|
56
|
+
channels.current = [];
|
|
57
|
+
};
|
|
58
|
+
const createPlansChannel = (herdId) => {
|
|
59
|
+
return scoutSupabase
|
|
60
|
+
.channel(`${herdId}-plans`, { config: { private: true } })
|
|
61
|
+
.on("broadcast", { event: "*" }, handlePlanBroadcast)
|
|
62
|
+
.subscribe((status) => {
|
|
63
|
+
if (status === "SUBSCRIBED") {
|
|
64
|
+
console.log(`[Plans] ✅ Connected to herd ${herdId}`);
|
|
65
|
+
}
|
|
66
|
+
else if (status === "CHANNEL_ERROR") {
|
|
67
|
+
console.warn(`[Plans] 🟡 Failed to connect to herd ${herdId}`);
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
};
|
|
71
|
+
useEffect(() => {
|
|
72
|
+
cleanupChannels();
|
|
73
|
+
// Clear previous update when switching herds
|
|
74
|
+
clearLatestUpdate();
|
|
75
|
+
// Create plans channel for active herd
|
|
76
|
+
if (activeHerdId) {
|
|
77
|
+
const channel = createPlansChannel(activeHerdId);
|
|
78
|
+
channels.current.push(channel);
|
|
79
|
+
}
|
|
80
|
+
return cleanupChannels;
|
|
81
|
+
}, [activeHerdId, clearLatestUpdate]);
|
|
82
|
+
return [latestPlanUpdate, clearLatestUpdate];
|
|
83
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { SupabaseClient } from "@supabase/supabase-js";
|
|
2
|
+
import { Database } from "../types/supabase";
|
|
3
|
+
import { ISessionWithCoordinates } from "../types/db";
|
|
4
|
+
import { RealtimeData } from "../types/realtime";
|
|
5
|
+
export declare function useScoutRealtimeSessions(scoutSupabase: SupabaseClient<Database>, shouldUpdateGlobalStateOnChanges: boolean): [RealtimeData<ISessionWithCoordinates> | null, () => void];
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { useAppDispatch } from "../store/hooks";
|
|
3
|
+
import { useSelector } from "react-redux";
|
|
4
|
+
import { useEffect, useRef, useCallback, useState } from "react";
|
|
5
|
+
import { addSessionToStore, deleteSessionFromStore, updateSessionInStore, } from "../store/scout";
|
|
6
|
+
import { EnumRealtimeOperation } from "../types/realtime";
|
|
7
|
+
export function useScoutRealtimeSessions(scoutSupabase, shouldUpdateGlobalStateOnChanges) {
|
|
8
|
+
const channels = useRef([]);
|
|
9
|
+
const dispatch = useAppDispatch();
|
|
10
|
+
const [latestSessionUpdate, setLatestSessionUpdate] = useState(null);
|
|
11
|
+
const activeHerdId = useSelector((state) => state.scout.active_herd_id);
|
|
12
|
+
// Session broadcast handler
|
|
13
|
+
const handleSessionBroadcast = useCallback((payload) => {
|
|
14
|
+
console.log("[Sessions] Broadcast received:", payload.payload.operation);
|
|
15
|
+
const data = payload.payload;
|
|
16
|
+
const sessionData = data.record || data.old_record;
|
|
17
|
+
if (!sessionData)
|
|
18
|
+
return;
|
|
19
|
+
let operation;
|
|
20
|
+
switch (data.operation) {
|
|
21
|
+
case "INSERT":
|
|
22
|
+
operation = EnumRealtimeOperation.INSERT;
|
|
23
|
+
if (data.record && shouldUpdateGlobalStateOnChanges) {
|
|
24
|
+
console.log("[Sessions] New session received:", data.record);
|
|
25
|
+
dispatch(addSessionToStore(data.record));
|
|
26
|
+
}
|
|
27
|
+
break;
|
|
28
|
+
case "UPDATE":
|
|
29
|
+
operation = EnumRealtimeOperation.UPDATE;
|
|
30
|
+
if (data.record && shouldUpdateGlobalStateOnChanges) {
|
|
31
|
+
dispatch(updateSessionInStore(data.record));
|
|
32
|
+
}
|
|
33
|
+
break;
|
|
34
|
+
case "DELETE":
|
|
35
|
+
operation = EnumRealtimeOperation.DELETE;
|
|
36
|
+
if (data.old_record && shouldUpdateGlobalStateOnChanges) {
|
|
37
|
+
dispatch(deleteSessionFromStore(data.old_record));
|
|
38
|
+
}
|
|
39
|
+
break;
|
|
40
|
+
default:
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
const realtimeData = {
|
|
44
|
+
data: sessionData,
|
|
45
|
+
operation,
|
|
46
|
+
};
|
|
47
|
+
console.log(`[scout-core realtime] SESSION ${data.operation} received:`, JSON.stringify(realtimeData));
|
|
48
|
+
setLatestSessionUpdate(realtimeData);
|
|
49
|
+
}, [dispatch]);
|
|
50
|
+
// Clear latest update
|
|
51
|
+
const clearLatestUpdate = useCallback(() => {
|
|
52
|
+
setLatestSessionUpdate(null);
|
|
53
|
+
}, []);
|
|
54
|
+
const cleanupChannels = () => {
|
|
55
|
+
channels.current.forEach((channel) => scoutSupabase.removeChannel(channel));
|
|
56
|
+
channels.current = [];
|
|
57
|
+
};
|
|
58
|
+
const createSessionsChannel = (herdId) => {
|
|
59
|
+
return scoutSupabase
|
|
60
|
+
.channel(`${herdId}-sessions`, { config: { private: true } })
|
|
61
|
+
.on("broadcast", { event: "*" }, handleSessionBroadcast)
|
|
62
|
+
.subscribe((status) => {
|
|
63
|
+
if (status === "SUBSCRIBED") {
|
|
64
|
+
console.log(`[Sessions] ✅ Connected to herd ${herdId}`);
|
|
65
|
+
}
|
|
66
|
+
else if (status === "CHANNEL_ERROR") {
|
|
67
|
+
console.warn(`[Sessions] 🟡 Failed to connect to herd ${herdId}`);
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
};
|
|
71
|
+
useEffect(() => {
|
|
72
|
+
cleanupChannels();
|
|
73
|
+
// Clear previous update when switching herds
|
|
74
|
+
clearLatestUpdate();
|
|
75
|
+
// Create sessions channel for active herd
|
|
76
|
+
if (activeHerdId) {
|
|
77
|
+
const channel = createSessionsChannel(activeHerdId);
|
|
78
|
+
channels.current.push(channel);
|
|
79
|
+
}
|
|
80
|
+
return cleanupChannels;
|
|
81
|
+
}, [activeHerdId, clearLatestUpdate]);
|
|
82
|
+
return [latestSessionUpdate, clearLatestUpdate];
|
|
83
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { SupabaseClient } from "@supabase/supabase-js";
|
|
2
|
+
import { Database } from "../types/supabase";
|
|
3
|
+
import { ITagPrettyLocation } from "../types/db";
|
|
4
|
+
import { RealtimeData } from "../types/realtime";
|
|
5
|
+
export declare function useScoutRealtimeTags(scoutSupabase: SupabaseClient<Database>, shouldUpdateGlobalStateOnChanges: boolean): [RealtimeData<ITagPrettyLocation> | null, () => void];
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { useAppDispatch } from "../store/hooks";
|
|
3
|
+
import { useSelector } from "react-redux";
|
|
4
|
+
import { useEffect, useRef, useCallback, useState } from "react";
|
|
5
|
+
import { addTag, deleteTag, updateTag } from "../store/scout";
|
|
6
|
+
import { EnumRealtimeOperation } from "../types/realtime";
|
|
7
|
+
export function useScoutRealtimeTags(scoutSupabase, shouldUpdateGlobalStateOnChanges) {
|
|
8
|
+
const channels = useRef([]);
|
|
9
|
+
const dispatch = useAppDispatch();
|
|
10
|
+
const [latestTagUpdate, setLatestTagUpdate] = useState(null);
|
|
11
|
+
const activeHerdId = useSelector((state) => state.scout.active_herd_id);
|
|
12
|
+
// Tag broadcast handler
|
|
13
|
+
const handleTagBroadcast = useCallback((payload) => {
|
|
14
|
+
console.log("[Tags] Broadcast received:", payload.payload.operation);
|
|
15
|
+
const data = payload.payload;
|
|
16
|
+
const tagData = data.record || data.old_record;
|
|
17
|
+
if (!tagData)
|
|
18
|
+
return;
|
|
19
|
+
let operation;
|
|
20
|
+
switch (data.operation) {
|
|
21
|
+
case "INSERT":
|
|
22
|
+
operation = EnumRealtimeOperation.INSERT;
|
|
23
|
+
if (data.record && shouldUpdateGlobalStateOnChanges) {
|
|
24
|
+
console.log("[Tags] New tag received:", data.record);
|
|
25
|
+
dispatch(addTag(data.record));
|
|
26
|
+
}
|
|
27
|
+
break;
|
|
28
|
+
case "UPDATE":
|
|
29
|
+
operation = EnumRealtimeOperation.UPDATE;
|
|
30
|
+
if (data.record && shouldUpdateGlobalStateOnChanges) {
|
|
31
|
+
console.log("[Tags] Tag updated:", data.record);
|
|
32
|
+
dispatch(updateTag(data.record));
|
|
33
|
+
}
|
|
34
|
+
break;
|
|
35
|
+
case "DELETE":
|
|
36
|
+
operation = EnumRealtimeOperation.DELETE;
|
|
37
|
+
if (data.old_record && shouldUpdateGlobalStateOnChanges) {
|
|
38
|
+
console.log("[Tags] Tag deleted:", data.old_record);
|
|
39
|
+
dispatch(deleteTag(data.old_record));
|
|
40
|
+
}
|
|
41
|
+
break;
|
|
42
|
+
default:
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
const realtimeData = {
|
|
46
|
+
data: tagData,
|
|
47
|
+
operation,
|
|
48
|
+
};
|
|
49
|
+
console.log(`[scout-core realtime] TAG ${data.operation} received:`, JSON.stringify(realtimeData));
|
|
50
|
+
setLatestTagUpdate(realtimeData);
|
|
51
|
+
}, [dispatch]);
|
|
52
|
+
// Clear latest update
|
|
53
|
+
const clearLatestUpdate = useCallback(() => {
|
|
54
|
+
setLatestTagUpdate(null);
|
|
55
|
+
}, []);
|
|
56
|
+
const cleanupChannels = () => {
|
|
57
|
+
channels.current.forEach((channel) => scoutSupabase.removeChannel(channel));
|
|
58
|
+
channels.current = [];
|
|
59
|
+
};
|
|
60
|
+
const createTagsChannel = (herdId) => {
|
|
61
|
+
return scoutSupabase
|
|
62
|
+
.channel(`${herdId}-tags`, { config: { private: true } })
|
|
63
|
+
.on("broadcast", { event: "*" }, handleTagBroadcast)
|
|
64
|
+
.subscribe((status) => {
|
|
65
|
+
if (status === "SUBSCRIBED") {
|
|
66
|
+
console.log(`[Tags] ✅ Connected to herd ${herdId}`);
|
|
67
|
+
}
|
|
68
|
+
else if (status === "CHANNEL_ERROR") {
|
|
69
|
+
console.warn(`[Tags] 🟡 Failed to connect to herd ${herdId}`);
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
};
|
|
73
|
+
useEffect(() => {
|
|
74
|
+
cleanupChannels();
|
|
75
|
+
// Clear previous update when switching herds
|
|
76
|
+
clearLatestUpdate();
|
|
77
|
+
// Create tags channel for active herd
|
|
78
|
+
if (activeHerdId) {
|
|
79
|
+
const channel = createTagsChannel(activeHerdId);
|
|
80
|
+
channels.current.push(channel);
|
|
81
|
+
}
|
|
82
|
+
return cleanupChannels;
|
|
83
|
+
}, [activeHerdId, clearLatestUpdate]);
|
|
84
|
+
return [latestTagUpdate, clearLatestUpdate];
|
|
85
|
+
}
|
|
@@ -2,4 +2,4 @@ import { SupabaseClient } from "@supabase/supabase-js";
|
|
|
2
2
|
import { Database } from "../types/supabase";
|
|
3
3
|
import { IVersionsSoftware } from "../types/db";
|
|
4
4
|
import { RealtimeData } from "../types/realtime";
|
|
5
|
-
export declare function useScoutRealtimeVersionsSoftware(scoutSupabase: SupabaseClient<Database>): RealtimeData<IVersionsSoftware>
|
|
5
|
+
export declare function useScoutRealtimeVersionsSoftware(scoutSupabase: SupabaseClient<Database>): [RealtimeData<IVersionsSoftware> | null, () => void];
|
|
@@ -3,7 +3,7 @@ import { useEffect, useRef, useCallback, useState } from "react";
|
|
|
3
3
|
import { EnumRealtimeOperation } from "../types/realtime";
|
|
4
4
|
export function useScoutRealtimeVersionsSoftware(scoutSupabase) {
|
|
5
5
|
const channels = useRef([]);
|
|
6
|
-
const [
|
|
6
|
+
const [latestVersionUpdate, setLatestVersionUpdate] = useState(null);
|
|
7
7
|
// Handle versions software broadcasts
|
|
8
8
|
const handleVersionsSoftwareBroadcast = useCallback((payload) => {
|
|
9
9
|
const { event, payload: data } = payload;
|
|
@@ -30,11 +30,11 @@ export function useScoutRealtimeVersionsSoftware(scoutSupabase) {
|
|
|
30
30
|
data: versionData,
|
|
31
31
|
operation,
|
|
32
32
|
};
|
|
33
|
-
|
|
33
|
+
setLatestVersionUpdate(realtimeData);
|
|
34
34
|
}, []);
|
|
35
|
-
// Clear
|
|
36
|
-
const
|
|
37
|
-
|
|
35
|
+
// Clear latest update
|
|
36
|
+
const clearLatestUpdate = useCallback(() => {
|
|
37
|
+
setLatestVersionUpdate(null);
|
|
38
38
|
}, []);
|
|
39
39
|
useEffect(() => {
|
|
40
40
|
if (!scoutSupabase)
|
|
@@ -42,8 +42,8 @@ export function useScoutRealtimeVersionsSoftware(scoutSupabase) {
|
|
|
42
42
|
// Clean up existing channels
|
|
43
43
|
channels.current.forEach((channel) => scoutSupabase.removeChannel(channel));
|
|
44
44
|
channels.current = [];
|
|
45
|
-
// Clear previous
|
|
46
|
-
|
|
45
|
+
// Clear previous update when setting up
|
|
46
|
+
clearLatestUpdate();
|
|
47
47
|
// Create versions_software channel
|
|
48
48
|
const channel = scoutSupabase
|
|
49
49
|
.channel("versions_software_changes", { config: { private: true } })
|
|
@@ -61,6 +61,6 @@ export function useScoutRealtimeVersionsSoftware(scoutSupabase) {
|
|
|
61
61
|
channels.current.forEach((ch) => scoutSupabase.removeChannel(ch));
|
|
62
62
|
channels.current = [];
|
|
63
63
|
};
|
|
64
|
-
}, [scoutSupabase, handleVersionsSoftwareBroadcast,
|
|
65
|
-
return
|
|
64
|
+
}, [scoutSupabase, handleVersionsSoftwareBroadcast, clearLatestUpdate]);
|
|
65
|
+
return [latestVersionUpdate, clearLatestUpdate];
|
|
66
66
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -21,6 +21,7 @@ export * from "./helpers/events";
|
|
|
21
21
|
export * from "./helpers/gps";
|
|
22
22
|
export * from "./helpers/herds";
|
|
23
23
|
export * from "./helpers/location";
|
|
24
|
+
export * from "./helpers/pins";
|
|
24
25
|
export * from "./helpers/plans";
|
|
25
26
|
export * from "./helpers/layers";
|
|
26
27
|
export * from "./helpers/sessions";
|
|
@@ -41,6 +42,10 @@ export * from "./helpers/components";
|
|
|
41
42
|
export * from "./hooks/useScoutRealtimeConnectivity";
|
|
42
43
|
export * from "./hooks/useScoutRealtimeDevices";
|
|
43
44
|
export * from "./hooks/useScoutRealtimeVersionsSoftware";
|
|
45
|
+
export * from "./hooks/useScoutRealtimeEvents";
|
|
46
|
+
export * from "./hooks/useScoutRealtimeTags";
|
|
47
|
+
export * from "./hooks/useScoutRealtimeSessions";
|
|
48
|
+
export * from "./hooks/useScoutRealtimePlans";
|
|
44
49
|
export * from "./hooks/useScoutRefresh";
|
|
45
50
|
export * from "./providers";
|
|
46
51
|
export * from "./store/scout";
|
package/dist/index.js
CHANGED
|
@@ -24,6 +24,7 @@ export * from "./helpers/events";
|
|
|
24
24
|
export * from "./helpers/gps";
|
|
25
25
|
export * from "./helpers/herds";
|
|
26
26
|
export * from "./helpers/location";
|
|
27
|
+
export * from "./helpers/pins";
|
|
27
28
|
export * from "./helpers/plans";
|
|
28
29
|
export * from "./helpers/layers";
|
|
29
30
|
export * from "./helpers/sessions";
|
|
@@ -45,6 +46,10 @@ export * from "./helpers/components";
|
|
|
45
46
|
export * from "./hooks/useScoutRealtimeConnectivity";
|
|
46
47
|
export * from "./hooks/useScoutRealtimeDevices";
|
|
47
48
|
export * from "./hooks/useScoutRealtimeVersionsSoftware";
|
|
49
|
+
export * from "./hooks/useScoutRealtimeEvents";
|
|
50
|
+
export * from "./hooks/useScoutRealtimeTags";
|
|
51
|
+
export * from "./hooks/useScoutRealtimeSessions";
|
|
52
|
+
export * from "./hooks/useScoutRealtimePlans";
|
|
48
53
|
export * from "./hooks/useScoutRefresh";
|
|
49
54
|
// Providers
|
|
50
55
|
export * from "./providers";
|
|
@@ -547,6 +547,57 @@ export declare function useSupabase(): SupabaseClient<Database, "public", "publi
|
|
|
547
547
|
referencedColumns: ["id"];
|
|
548
548
|
}];
|
|
549
549
|
};
|
|
550
|
+
pins: {
|
|
551
|
+
Row: {
|
|
552
|
+
altitude_relative_to_ground: number;
|
|
553
|
+
color: string;
|
|
554
|
+
created_at: string;
|
|
555
|
+
created_by: string | null;
|
|
556
|
+
description: string | null;
|
|
557
|
+
herd_id: number;
|
|
558
|
+
id: number;
|
|
559
|
+
latitude: unknown;
|
|
560
|
+
longitude: unknown;
|
|
561
|
+
name: string;
|
|
562
|
+
};
|
|
563
|
+
Insert: {
|
|
564
|
+
altitude_relative_to_ground: number;
|
|
565
|
+
color: string;
|
|
566
|
+
created_at?: string;
|
|
567
|
+
created_by?: string | null;
|
|
568
|
+
description?: string | null;
|
|
569
|
+
herd_id: number;
|
|
570
|
+
id?: number;
|
|
571
|
+
latitude: unknown;
|
|
572
|
+
longitude: unknown;
|
|
573
|
+
name: string;
|
|
574
|
+
};
|
|
575
|
+
Update: {
|
|
576
|
+
altitude_relative_to_ground?: number;
|
|
577
|
+
color?: string;
|
|
578
|
+
created_at?: string;
|
|
579
|
+
created_by?: string | null;
|
|
580
|
+
description?: string | null;
|
|
581
|
+
herd_id?: number;
|
|
582
|
+
id?: number;
|
|
583
|
+
latitude?: unknown;
|
|
584
|
+
longitude?: unknown;
|
|
585
|
+
name?: string;
|
|
586
|
+
};
|
|
587
|
+
Relationships: [{
|
|
588
|
+
foreignKeyName: "pins_created_by_fkey";
|
|
589
|
+
columns: ["created_by"];
|
|
590
|
+
isOneToOne: false;
|
|
591
|
+
referencedRelation: "users";
|
|
592
|
+
referencedColumns: ["id"];
|
|
593
|
+
}, {
|
|
594
|
+
foreignKeyName: "pins_herd_id_fkey";
|
|
595
|
+
columns: ["herd_id"];
|
|
596
|
+
isOneToOne: false;
|
|
597
|
+
referencedRelation: "herds";
|
|
598
|
+
referencedColumns: ["id"];
|
|
599
|
+
}];
|
|
600
|
+
};
|
|
550
601
|
plans: {
|
|
551
602
|
Row: {
|
|
552
603
|
herd_id: number;
|
|
@@ -1265,6 +1316,18 @@ export declare function useSupabase(): SupabaseClient<Database, "public", "publi
|
|
|
1265
1316
|
total_heartbeats: number;
|
|
1266
1317
|
}[];
|
|
1267
1318
|
};
|
|
1319
|
+
get_pins_for_herd: {
|
|
1320
|
+
Args: {
|
|
1321
|
+
herd_id_caller: number;
|
|
1322
|
+
};
|
|
1323
|
+
Returns: Database["public"]["CompositeTypes"]["pins_pretty_location"][];
|
|
1324
|
+
SetofOptions: {
|
|
1325
|
+
from: "*";
|
|
1326
|
+
to: "pins_pretty_location";
|
|
1327
|
+
isOneToOne: false;
|
|
1328
|
+
isSetofReturn: true;
|
|
1329
|
+
};
|
|
1330
|
+
};
|
|
1268
1331
|
get_sessions_with_coordinates: {
|
|
1269
1332
|
Args: {
|
|
1270
1333
|
herd_id_caller: number;
|
|
@@ -1484,6 +1547,18 @@ export declare function useSupabase(): SupabaseClient<Database, "public", "publi
|
|
|
1484
1547
|
is_public: boolean | null;
|
|
1485
1548
|
tags: Database["public"]["Tables"]["tags"]["Row"][] | null;
|
|
1486
1549
|
};
|
|
1550
|
+
pins_pretty_location: {
|
|
1551
|
+
id: number | null;
|
|
1552
|
+
created_at: string | null;
|
|
1553
|
+
altitude_relative_to_ground: number | null;
|
|
1554
|
+
color: string | null;
|
|
1555
|
+
name: string | null;
|
|
1556
|
+
description: string | null;
|
|
1557
|
+
herd_id: number | null;
|
|
1558
|
+
created_by: string | null;
|
|
1559
|
+
latitude: number | null;
|
|
1560
|
+
longitude: number | null;
|
|
1561
|
+
};
|
|
1487
1562
|
session_with_coordinates: {
|
|
1488
1563
|
id: number | null;
|
|
1489
1564
|
device_id: number | null;
|
package/dist/types/db.d.ts
CHANGED
|
@@ -9,6 +9,7 @@ export type IUser = User;
|
|
|
9
9
|
export type IDevice = Database["public"]["CompositeTypes"]["device_pretty_location"] & {
|
|
10
10
|
api_keys_scout?: IApiKeyScout[];
|
|
11
11
|
};
|
|
12
|
+
export type IPin = Database["public"]["CompositeTypes"]["pins_pretty_location"];
|
|
12
13
|
export type IEvent = Database["public"]["Tables"]["events"]["Row"];
|
|
13
14
|
export type ITag = Database["public"]["Tables"]["tags"]["Row"];
|
|
14
15
|
export type ITagPrettyLocation = Database["public"]["CompositeTypes"]["tags_pretty_location"];
|
|
@@ -32,6 +33,7 @@ export type IArtifactWithMediaUrl = IArtifact & {
|
|
|
32
33
|
export type ComponentInsert = Database["public"]["Tables"]["components"]["Insert"];
|
|
33
34
|
export type VersionsSoftwareInsert = Database["public"]["Tables"]["versions_software"]["Insert"];
|
|
34
35
|
export type ArtifactInsert = Database["public"]["Tables"]["artifacts"]["Insert"];
|
|
36
|
+
export type PinInsert = Database["public"]["Tables"]["pins"]["Insert"];
|
|
35
37
|
export type IEventWithTags = Database["public"]["CompositeTypes"]["event_with_tags"] & {
|
|
36
38
|
earthranger_url: string | null;
|
|
37
39
|
file_path: string | null;
|
package/dist/types/supabase.d.ts
CHANGED
|
@@ -574,6 +574,60 @@ export type Database = {
|
|
|
574
574
|
}
|
|
575
575
|
];
|
|
576
576
|
};
|
|
577
|
+
pins: {
|
|
578
|
+
Row: {
|
|
579
|
+
altitude_relative_to_ground: number;
|
|
580
|
+
color: string;
|
|
581
|
+
created_at: string;
|
|
582
|
+
created_by: string | null;
|
|
583
|
+
description: string | null;
|
|
584
|
+
herd_id: number;
|
|
585
|
+
id: number;
|
|
586
|
+
latitude: unknown;
|
|
587
|
+
longitude: unknown;
|
|
588
|
+
name: string;
|
|
589
|
+
};
|
|
590
|
+
Insert: {
|
|
591
|
+
altitude_relative_to_ground: number;
|
|
592
|
+
color: string;
|
|
593
|
+
created_at?: string;
|
|
594
|
+
created_by?: string | null;
|
|
595
|
+
description?: string | null;
|
|
596
|
+
herd_id: number;
|
|
597
|
+
id?: number;
|
|
598
|
+
latitude: unknown;
|
|
599
|
+
longitude: unknown;
|
|
600
|
+
name: string;
|
|
601
|
+
};
|
|
602
|
+
Update: {
|
|
603
|
+
altitude_relative_to_ground?: number;
|
|
604
|
+
color?: string;
|
|
605
|
+
created_at?: string;
|
|
606
|
+
created_by?: string | null;
|
|
607
|
+
description?: string | null;
|
|
608
|
+
herd_id?: number;
|
|
609
|
+
id?: number;
|
|
610
|
+
latitude?: unknown;
|
|
611
|
+
longitude?: unknown;
|
|
612
|
+
name?: string;
|
|
613
|
+
};
|
|
614
|
+
Relationships: [
|
|
615
|
+
{
|
|
616
|
+
foreignKeyName: "pins_created_by_fkey";
|
|
617
|
+
columns: ["created_by"];
|
|
618
|
+
isOneToOne: false;
|
|
619
|
+
referencedRelation: "users";
|
|
620
|
+
referencedColumns: ["id"];
|
|
621
|
+
},
|
|
622
|
+
{
|
|
623
|
+
foreignKeyName: "pins_herd_id_fkey";
|
|
624
|
+
columns: ["herd_id"];
|
|
625
|
+
isOneToOne: false;
|
|
626
|
+
referencedRelation: "herds";
|
|
627
|
+
referencedColumns: ["id"];
|
|
628
|
+
}
|
|
629
|
+
];
|
|
630
|
+
};
|
|
577
631
|
plans: {
|
|
578
632
|
Row: {
|
|
579
633
|
herd_id: number;
|
|
@@ -1317,6 +1371,18 @@ export type Database = {
|
|
|
1317
1371
|
total_heartbeats: number;
|
|
1318
1372
|
}[];
|
|
1319
1373
|
};
|
|
1374
|
+
get_pins_for_herd: {
|
|
1375
|
+
Args: {
|
|
1376
|
+
herd_id_caller: number;
|
|
1377
|
+
};
|
|
1378
|
+
Returns: Database["public"]["CompositeTypes"]["pins_pretty_location"][];
|
|
1379
|
+
SetofOptions: {
|
|
1380
|
+
from: "*";
|
|
1381
|
+
to: "pins_pretty_location";
|
|
1382
|
+
isOneToOne: false;
|
|
1383
|
+
isSetofReturn: true;
|
|
1384
|
+
};
|
|
1385
|
+
};
|
|
1320
1386
|
get_sessions_with_coordinates: {
|
|
1321
1387
|
Args: {
|
|
1322
1388
|
herd_id_caller: number;
|
|
@@ -1536,6 +1602,18 @@ export type Database = {
|
|
|
1536
1602
|
is_public: boolean | null;
|
|
1537
1603
|
tags: Database["public"]["Tables"]["tags"]["Row"][] | null;
|
|
1538
1604
|
};
|
|
1605
|
+
pins_pretty_location: {
|
|
1606
|
+
id: number | null;
|
|
1607
|
+
created_at: string | null;
|
|
1608
|
+
altitude_relative_to_ground: number | null;
|
|
1609
|
+
color: string | null;
|
|
1610
|
+
name: string | null;
|
|
1611
|
+
description: string | null;
|
|
1612
|
+
herd_id: number | null;
|
|
1613
|
+
created_by: string | null;
|
|
1614
|
+
latitude: number | null;
|
|
1615
|
+
longitude: number | null;
|
|
1616
|
+
};
|
|
1539
1617
|
session_with_coordinates: {
|
|
1540
1618
|
id: number | null;
|
|
1541
1619
|
device_id: number | null;
|