@adventurelabs/scout-core 1.4.2 → 1.4.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/constants/env.d.ts +24 -0
- package/dist/constants/env.js +47 -0
- package/dist/constants/index.d.ts +1 -0
- package/dist/constants/index.js +1 -0
- package/dist/helpers/connectivity.d.ts +4 -1
- package/dist/helpers/connectivity.js +48 -0
- package/dist/helpers/db.js +3 -2
- package/dist/helpers/events.d.ts +4 -0
- package/dist/helpers/events.js +48 -0
- package/dist/helpers/sessions.d.ts +3 -1
- package/dist/helpers/sessions.js +48 -0
- package/dist/hooks/useScoutRealtimeDevices.js +5 -15
- package/dist/hooks/useScoutRealtimeEvents.d.ts +1 -1
- package/dist/hooks/useScoutRealtimeEvents.js +6 -24
- package/dist/hooks/useScoutRealtimeParts.js +5 -45
- package/dist/hooks/useScoutRealtimePins.d.ts +1 -1
- package/dist/hooks/useScoutRealtimePins.js +6 -13
- package/dist/hooks/useScoutRealtimePlans.d.ts +1 -1
- package/dist/hooks/useScoutRealtimePlans.js +6 -16
- package/dist/hooks/useScoutRealtimeSessions.d.ts +1 -1
- package/dist/hooks/useScoutRealtimeSessions.js +7 -25
- package/dist/hooks/useScoutRealtimeTags.d.ts +1 -1
- package/dist/hooks/useScoutRealtimeTags.js +6 -21
- package/dist/hooks/useScoutRefresh.js +3 -1
- package/dist/providers/ScoutRefreshProvider.js +4 -2
- package/dist/types/db.d.ts +6 -0
- package/package.json +1 -1
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This helper checks multiple possible environment variable names to support
|
|
3
|
+
* different frameworks and build tools:
|
|
4
|
+
* - NEXT_PUBLIC_* (Next.js convention, also works in other frameworks)
|
|
5
|
+
* - VITE_* (Vite convention)
|
|
6
|
+
* - REACT_APP_* (Create React App convention)
|
|
7
|
+
* - Direct access (for runtime configuration)
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Get an environment variable, checking multiple possible names
|
|
11
|
+
*
|
|
12
|
+
* @param name - The base name of the environment variable (without prefix)
|
|
13
|
+
* @param defaultValue - Optional default value if not found
|
|
14
|
+
* @returns The environment variable value or default
|
|
15
|
+
*/
|
|
16
|
+
export declare function getEnvVar(name: string, defaultValue?: string): string;
|
|
17
|
+
/**
|
|
18
|
+
* Get Supabase URL from environment variables
|
|
19
|
+
*/
|
|
20
|
+
export declare function getSupabaseUrl(): string;
|
|
21
|
+
/**
|
|
22
|
+
* Get Supabase anonymous key from environment variables
|
|
23
|
+
*/
|
|
24
|
+
export declare function getSupabaseAnonKey(): string;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This helper checks multiple possible environment variable names to support
|
|
3
|
+
* different frameworks and build tools:
|
|
4
|
+
* - NEXT_PUBLIC_* (Next.js convention, also works in other frameworks)
|
|
5
|
+
* - VITE_* (Vite convention)
|
|
6
|
+
* - REACT_APP_* (Create React App convention)
|
|
7
|
+
* - Direct access (for runtime configuration)
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Get an environment variable, checking multiple possible names
|
|
11
|
+
*
|
|
12
|
+
* @param name - The base name of the environment variable (without prefix)
|
|
13
|
+
* @param defaultValue - Optional default value if not found
|
|
14
|
+
* @returns The environment variable value or default
|
|
15
|
+
*/
|
|
16
|
+
export function getEnvVar(name, defaultValue = "") {
|
|
17
|
+
// Check multiple possible prefixes
|
|
18
|
+
const possibleNames = [
|
|
19
|
+
`NEXT_PUBLIC_${name}`, // Next.js (also works in other frameworks)
|
|
20
|
+
`VITE_${name}`, // Vite
|
|
21
|
+
`REACT_APP_${name}`, // Create React App
|
|
22
|
+
name, // Direct access (for runtime configuration)
|
|
23
|
+
];
|
|
24
|
+
// Try each possible name
|
|
25
|
+
for (const envName of possibleNames) {
|
|
26
|
+
if (typeof process !== "undefined" && process.env?.[envName]) {
|
|
27
|
+
return process.env[envName];
|
|
28
|
+
}
|
|
29
|
+
// Also check window object for runtime configuration (PWA use case)
|
|
30
|
+
if (typeof window !== "undefined" && window.__SCOUT_CONFIG__?.[name]) {
|
|
31
|
+
return window.__SCOUT_CONFIG__[name];
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return defaultValue;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Get Supabase URL from environment variables
|
|
38
|
+
*/
|
|
39
|
+
export function getSupabaseUrl() {
|
|
40
|
+
return getEnvVar("SUPABASE_URL", "");
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Get Supabase anonymous key from environment variables
|
|
44
|
+
*/
|
|
45
|
+
export function getSupabaseAnonKey() {
|
|
46
|
+
return getEnvVar("SUPABASE_ANON_KEY", "");
|
|
47
|
+
}
|
package/dist/constants/index.js
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
import { IWebResponseCompatible } from "../types/requests";
|
|
2
|
-
import { IConnectivityWithCoordinates } from "../types/db";
|
|
2
|
+
import { IConnectivityWithCoordinates, IConnectivity, ConnectivityInsert, ConnectivityUpdate } from "../types/db";
|
|
3
|
+
import { SupabaseClient } from "@supabase/supabase-js";
|
|
3
4
|
export declare function server_get_connectivity_by_session_id(sessionId: number): Promise<IWebResponseCompatible<IConnectivityWithCoordinates[]>>;
|
|
4
5
|
export declare function server_get_connectivity_by_device_id(deviceId: number, timestamp: string): Promise<IWebResponseCompatible<IConnectivityWithCoordinates[]>>;
|
|
6
|
+
export declare function server_insert_connectivity(connectivity: ConnectivityInsert, client?: SupabaseClient): Promise<IWebResponseCompatible<IConnectivity | null>>;
|
|
7
|
+
export declare function server_update_connectivity(connectivityId: number, updates: ConnectivityUpdate, client?: SupabaseClient): Promise<IWebResponseCompatible<IConnectivity | null>>;
|
|
@@ -44,3 +44,51 @@ export async function server_get_connectivity_by_device_id(deviceId, timestamp)
|
|
|
44
44
|
});
|
|
45
45
|
return IWebResponse.success(sortedConnectivity).to_compatible();
|
|
46
46
|
}
|
|
47
|
+
// Insert a new connectivity record
|
|
48
|
+
export async function server_insert_connectivity(connectivity, client) {
|
|
49
|
+
const supabase = client || (await newServerClient());
|
|
50
|
+
const { data, error } = await supabase
|
|
51
|
+
.from("connectivity")
|
|
52
|
+
.insert([connectivity])
|
|
53
|
+
.select("*")
|
|
54
|
+
.single();
|
|
55
|
+
if (error) {
|
|
56
|
+
console.warn("Error inserting connectivity:", error.message);
|
|
57
|
+
return {
|
|
58
|
+
status: EnumWebResponse.ERROR,
|
|
59
|
+
msg: error.message,
|
|
60
|
+
data: null,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
return IWebResponse.success(data).to_compatible();
|
|
64
|
+
}
|
|
65
|
+
// Update an existing connectivity record
|
|
66
|
+
export async function server_update_connectivity(connectivityId, updates, client) {
|
|
67
|
+
const supabase = client || (await newServerClient());
|
|
68
|
+
// Remove fields that shouldn't be updated
|
|
69
|
+
const updateData = { ...updates };
|
|
70
|
+
delete updateData.id;
|
|
71
|
+
delete updateData.inserted_at;
|
|
72
|
+
const { data, error } = await supabase
|
|
73
|
+
.from("connectivity")
|
|
74
|
+
.update(updateData)
|
|
75
|
+
.eq("id", connectivityId)
|
|
76
|
+
.select("*")
|
|
77
|
+
.single();
|
|
78
|
+
if (error) {
|
|
79
|
+
console.warn("Error updating connectivity:", error.message);
|
|
80
|
+
return {
|
|
81
|
+
status: EnumWebResponse.ERROR,
|
|
82
|
+
msg: error.message,
|
|
83
|
+
data: null,
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
if (!data) {
|
|
87
|
+
return {
|
|
88
|
+
status: EnumWebResponse.ERROR,
|
|
89
|
+
msg: "Connectivity record not found or update failed",
|
|
90
|
+
data: null,
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
return IWebResponse.success(data).to_compatible();
|
|
94
|
+
}
|
package/dist/helpers/db.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { createClient } from "@supabase/supabase-js";
|
|
2
|
+
import { getSupabaseUrl, getSupabaseAnonKey } from "../constants/env";
|
|
2
3
|
export function createClientWithApiKey(user_api_key) {
|
|
3
|
-
const supabase_url =
|
|
4
|
-
const supabase_anon_key =
|
|
4
|
+
const supabase_url = getSupabaseUrl();
|
|
5
|
+
const supabase_anon_key = getSupabaseAnonKey();
|
|
5
6
|
if (!supabase_url || !supabase_anon_key) {
|
|
6
7
|
return null;
|
|
7
8
|
}
|
package/dist/helpers/events.d.ts
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
1
|
import { IWebResponseCompatible } from "../types/requests";
|
|
2
2
|
import { EnumSessionsVisibility } from "../types/events";
|
|
3
|
+
import { IEvent, EventInsert, EventUpdate } from "../types/db";
|
|
4
|
+
import { SupabaseClient } from "@supabase/supabase-js";
|
|
3
5
|
export declare function server_get_total_events_by_herd(herd_id: number, sessions_visibility: EnumSessionsVisibility): Promise<IWebResponseCompatible<number>>;
|
|
6
|
+
export declare function server_insert_event(event: EventInsert, client?: SupabaseClient): Promise<IWebResponseCompatible<IEvent | null>>;
|
|
7
|
+
export declare function server_update_event(eventId: number, updates: EventUpdate, client?: SupabaseClient): Promise<IWebResponseCompatible<IEvent | null>>;
|
package/dist/helpers/events.js
CHANGED
|
@@ -22,3 +22,51 @@ export async function server_get_total_events_by_herd(herd_id, sessions_visibili
|
|
|
22
22
|
return IWebResponse.success(data || 0).to_compatible();
|
|
23
23
|
}
|
|
24
24
|
}
|
|
25
|
+
// Insert a new event
|
|
26
|
+
export async function server_insert_event(event, client) {
|
|
27
|
+
const supabase = client || (await newServerClient());
|
|
28
|
+
const { data, error } = await supabase
|
|
29
|
+
.from("events")
|
|
30
|
+
.insert([event])
|
|
31
|
+
.select("*")
|
|
32
|
+
.single();
|
|
33
|
+
if (error) {
|
|
34
|
+
console.warn("Error inserting event:", error.message);
|
|
35
|
+
return {
|
|
36
|
+
status: EnumWebResponse.ERROR,
|
|
37
|
+
msg: error.message,
|
|
38
|
+
data: null,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
return IWebResponse.success(data).to_compatible();
|
|
42
|
+
}
|
|
43
|
+
// Update an existing event
|
|
44
|
+
export async function server_update_event(eventId, updates, client) {
|
|
45
|
+
const supabase = client || (await newServerClient());
|
|
46
|
+
// Remove fields that shouldn't be updated
|
|
47
|
+
const updateData = { ...updates };
|
|
48
|
+
delete updateData.id;
|
|
49
|
+
delete updateData.inserted_at;
|
|
50
|
+
const { data, error } = await supabase
|
|
51
|
+
.from("events")
|
|
52
|
+
.update(updateData)
|
|
53
|
+
.eq("id", eventId)
|
|
54
|
+
.select("*")
|
|
55
|
+
.single();
|
|
56
|
+
if (error) {
|
|
57
|
+
console.warn("Error updating event:", error.message);
|
|
58
|
+
return {
|
|
59
|
+
status: EnumWebResponse.ERROR,
|
|
60
|
+
msg: error.message,
|
|
61
|
+
data: null,
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
if (!data) {
|
|
65
|
+
return {
|
|
66
|
+
status: EnumWebResponse.ERROR,
|
|
67
|
+
msg: "Event not found or update failed",
|
|
68
|
+
data: null,
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
return IWebResponse.success(data).to_compatible();
|
|
72
|
+
}
|
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
import { ISessionWithCoordinates, ISessionUsageOverTime, IEventAndTagsPrettyLocation } from "../types/db";
|
|
1
|
+
import { ISessionWithCoordinates, ISessionUsageOverTime, IEventAndTagsPrettyLocation, ISession, SessionInsert, SessionUpdate } from "../types/db";
|
|
2
2
|
import { IWebResponseCompatible } from "../types/requests";
|
|
3
3
|
import { SupabaseClient } from "@supabase/supabase-js";
|
|
4
4
|
export declare function server_get_session_by_id(sessionId: number, client?: SupabaseClient): Promise<IWebResponseCompatible<ISessionWithCoordinates | null>>;
|
|
5
5
|
export declare function server_get_session_usage_over_time_by_herd(herd_id: number, client?: SupabaseClient): Promise<IWebResponseCompatible<ISessionUsageOverTime>>;
|
|
6
6
|
export declare function server_get_session_usage_over_time_by_device(device_id: number, client?: SupabaseClient): Promise<IWebResponseCompatible<ISessionUsageOverTime>>;
|
|
7
7
|
export declare function server_get_events_and_tags_by_session_id(sessionId: number, limit?: number, offset?: number): Promise<IWebResponseCompatible<IEventAndTagsPrettyLocation[]>>;
|
|
8
|
+
export declare function server_insert_session(session: SessionInsert, client?: SupabaseClient): Promise<IWebResponseCompatible<ISession | null>>;
|
|
9
|
+
export declare function server_update_session(sessionId: number, updates: SessionUpdate, client?: SupabaseClient): Promise<IWebResponseCompatible<ISession | null>>;
|
package/dist/helpers/sessions.js
CHANGED
|
@@ -71,3 +71,51 @@ export async function server_get_events_and_tags_by_session_id(sessionId, limit
|
|
|
71
71
|
}
|
|
72
72
|
return IWebResponse.success(data || []).to_compatible();
|
|
73
73
|
}
|
|
74
|
+
// Insert a new session
|
|
75
|
+
export async function server_insert_session(session, client) {
|
|
76
|
+
const supabase = client || (await newServerClient());
|
|
77
|
+
const { data, error } = await supabase
|
|
78
|
+
.from("sessions")
|
|
79
|
+
.insert([session])
|
|
80
|
+
.select("*")
|
|
81
|
+
.single();
|
|
82
|
+
if (error) {
|
|
83
|
+
console.warn("Error inserting session:", error.message);
|
|
84
|
+
return {
|
|
85
|
+
status: EnumWebResponse.ERROR,
|
|
86
|
+
msg: error.message,
|
|
87
|
+
data: null,
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
return IWebResponse.success(data).to_compatible();
|
|
91
|
+
}
|
|
92
|
+
// Update an existing session
|
|
93
|
+
export async function server_update_session(sessionId, updates, client) {
|
|
94
|
+
const supabase = client || (await newServerClient());
|
|
95
|
+
// Remove fields that shouldn't be updated
|
|
96
|
+
const updateData = { ...updates };
|
|
97
|
+
delete updateData.id;
|
|
98
|
+
delete updateData.inserted_at;
|
|
99
|
+
const { data, error } = await supabase
|
|
100
|
+
.from("sessions")
|
|
101
|
+
.update(updateData)
|
|
102
|
+
.eq("id", sessionId)
|
|
103
|
+
.select("*")
|
|
104
|
+
.single();
|
|
105
|
+
if (error) {
|
|
106
|
+
console.warn("Error updating session:", error.message);
|
|
107
|
+
return {
|
|
108
|
+
status: EnumWebResponse.ERROR,
|
|
109
|
+
msg: error.message,
|
|
110
|
+
data: null,
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
if (!data) {
|
|
114
|
+
return {
|
|
115
|
+
status: EnumWebResponse.ERROR,
|
|
116
|
+
msg: "Session not found or update failed",
|
|
117
|
+
data: null,
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
return IWebResponse.success(data).to_compatible();
|
|
121
|
+
}
|
|
@@ -1,15 +1,12 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { useAppDispatch } from "../store/hooks";
|
|
3
2
|
import { useSelector } from "react-redux";
|
|
4
3
|
import { useEffect, useRef, useCallback, useState } from "react";
|
|
5
|
-
import { addDevice, deleteDevice, updateDevice } from "../store/scout";
|
|
6
4
|
import { EnumRealtimeOperation } from "../types/realtime";
|
|
7
5
|
export function useScoutRealtimeDevices(scoutSupabase) {
|
|
8
6
|
const channels = useRef([]);
|
|
9
|
-
const dispatch = useAppDispatch();
|
|
10
7
|
const [latestDeviceUpdate, setLatestDeviceUpdate] = useState(null);
|
|
11
8
|
const activeHerdId = useSelector((state) => state.scout.active_herd_id);
|
|
12
|
-
// Device broadcast handler
|
|
9
|
+
// Device broadcast handler - just pass data, don't mutate state
|
|
13
10
|
const handleDeviceBroadcast = useCallback((payload) => {
|
|
14
11
|
console.log("[Devices] Broadcast received:", payload.payload.operation);
|
|
15
12
|
const data = payload.payload;
|
|
@@ -20,22 +17,15 @@ export function useScoutRealtimeDevices(scoutSupabase) {
|
|
|
20
17
|
switch (data.operation) {
|
|
21
18
|
case "INSERT":
|
|
22
19
|
operation = EnumRealtimeOperation.INSERT;
|
|
23
|
-
|
|
24
|
-
console.log("[Devices] New device received:", data.record);
|
|
25
|
-
dispatch(addDevice(data.record));
|
|
26
|
-
}
|
|
20
|
+
console.log("[Devices] New device received:", data.record);
|
|
27
21
|
break;
|
|
28
22
|
case "UPDATE":
|
|
29
23
|
operation = EnumRealtimeOperation.UPDATE;
|
|
30
|
-
|
|
31
|
-
dispatch(updateDevice(data.record));
|
|
32
|
-
}
|
|
24
|
+
console.log("[Devices] Device updated:", data.record);
|
|
33
25
|
break;
|
|
34
26
|
case "DELETE":
|
|
35
27
|
operation = EnumRealtimeOperation.DELETE;
|
|
36
|
-
|
|
37
|
-
dispatch(deleteDevice(data.old_record));
|
|
38
|
-
}
|
|
28
|
+
console.log("[Devices] Device deleted:", data.old_record);
|
|
39
29
|
break;
|
|
40
30
|
default:
|
|
41
31
|
return;
|
|
@@ -46,7 +36,7 @@ export function useScoutRealtimeDevices(scoutSupabase) {
|
|
|
46
36
|
};
|
|
47
37
|
console.log(`[scout-core realtime] DEVICE ${data.operation} received:`, JSON.stringify(realtimeData));
|
|
48
38
|
setLatestDeviceUpdate(realtimeData);
|
|
49
|
-
}, [
|
|
39
|
+
}, []);
|
|
50
40
|
// Clear latest update
|
|
51
41
|
const clearLatestUpdate = useCallback(() => {
|
|
52
42
|
setLatestDeviceUpdate(null);
|
|
@@ -2,4 +2,4 @@ import { SupabaseClient } from "@supabase/supabase-js";
|
|
|
2
2
|
import { Database } from "../types/supabase";
|
|
3
3
|
import { IEventAndTagsPrettyLocation } from "../types/db";
|
|
4
4
|
import { RealtimeData } from "../types/realtime";
|
|
5
|
-
export declare function useScoutRealtimeEvents(scoutSupabase: SupabaseClient<Database
|
|
5
|
+
export declare function useScoutRealtimeEvents(scoutSupabase: SupabaseClient<Database>): [RealtimeData<IEventAndTagsPrettyLocation> | null, () => void];
|
|
@@ -1,15 +1,12 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { useAppDispatch } from "../store/hooks";
|
|
3
2
|
import { useSelector } from "react-redux";
|
|
4
3
|
import { useEffect, useRef, useCallback, useState } from "react";
|
|
5
4
|
import { EnumRealtimeOperation } from "../types/realtime";
|
|
6
|
-
|
|
7
|
-
export function useScoutRealtimeEvents(scoutSupabase, invalidateRTKQuery = true) {
|
|
5
|
+
export function useScoutRealtimeEvents(scoutSupabase) {
|
|
8
6
|
const channels = useRef([]);
|
|
9
|
-
const dispatch = useAppDispatch();
|
|
10
7
|
const [latestEventUpdate, setLatestEventUpdate] = useState(null);
|
|
11
8
|
const activeHerdId = useSelector((state) => state.scout.active_herd_id);
|
|
12
|
-
// Event broadcast handler
|
|
9
|
+
// Event broadcast handler - just pass data, don't mutate state
|
|
13
10
|
const handleEventBroadcast = useCallback((payload) => {
|
|
14
11
|
console.log("[Events] Broadcast received:", payload.payload.operation);
|
|
15
12
|
const data = payload.payload;
|
|
@@ -20,30 +17,15 @@ export function useScoutRealtimeEvents(scoutSupabase, invalidateRTKQuery = true)
|
|
|
20
17
|
switch (data.operation) {
|
|
21
18
|
case "INSERT":
|
|
22
19
|
operation = EnumRealtimeOperation.INSERT;
|
|
23
|
-
|
|
24
|
-
console.log("[Events] New event received, invalidating RTK Query cache:", data.record);
|
|
25
|
-
// Invalidate all events queries to refetch fresh data
|
|
26
|
-
dispatch(scoutApi.util.invalidateTags(["Event"]));
|
|
27
|
-
}
|
|
20
|
+
console.log("[Events] New event received:", data.record);
|
|
28
21
|
break;
|
|
29
22
|
case "UPDATE":
|
|
30
23
|
operation = EnumRealtimeOperation.UPDATE;
|
|
31
|
-
|
|
32
|
-
console.log("[Events] Event updated, invalidating RTK Query cache:", data.record);
|
|
33
|
-
// Invalidate specific event and list queries
|
|
34
|
-
dispatch(scoutApi.util.invalidateTags([
|
|
35
|
-
{ type: "Event", id: data.record.id || "unknown" },
|
|
36
|
-
{ type: "Event", id: "LIST" },
|
|
37
|
-
]));
|
|
38
|
-
}
|
|
24
|
+
console.log("[Events] Event updated:", data.record);
|
|
39
25
|
break;
|
|
40
26
|
case "DELETE":
|
|
41
27
|
operation = EnumRealtimeOperation.DELETE;
|
|
42
|
-
|
|
43
|
-
console.log("[Events] Event deleted, invalidating RTK Query cache:", data.old_record);
|
|
44
|
-
// Invalidate all events queries since item was deleted
|
|
45
|
-
dispatch(scoutApi.util.invalidateTags(["Event"]));
|
|
46
|
-
}
|
|
28
|
+
console.log("[Events] Event deleted:", data.old_record);
|
|
47
29
|
break;
|
|
48
30
|
default:
|
|
49
31
|
return;
|
|
@@ -54,7 +36,7 @@ export function useScoutRealtimeEvents(scoutSupabase, invalidateRTKQuery = true)
|
|
|
54
36
|
};
|
|
55
37
|
console.log(`[scout-core realtime] EVENT ${data.operation} received:`, JSON.stringify(realtimeData));
|
|
56
38
|
setLatestEventUpdate(realtimeData);
|
|
57
|
-
}, [
|
|
39
|
+
}, []);
|
|
58
40
|
// Clear latest update
|
|
59
41
|
const clearLatestUpdate = useCallback(() => {
|
|
60
42
|
setLatestEventUpdate(null);
|
|
@@ -1,15 +1,12 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { useAppDispatch } from "../store/hooks";
|
|
3
2
|
import { useSelector } from "react-redux";
|
|
4
3
|
import { useEffect, useRef, useCallback, useState } from "react";
|
|
5
4
|
import { EnumRealtimeOperation } from "../types/realtime";
|
|
6
5
|
export function useScoutRealtimeParts(scoutSupabase) {
|
|
7
6
|
const channels = useRef([]);
|
|
8
|
-
const dispatch = useAppDispatch();
|
|
9
7
|
const [latestPartUpdate, setLatestPartUpdate] = useState(null);
|
|
10
8
|
const activeHerdId = useSelector((state) => state.scout.active_herd_id);
|
|
11
|
-
|
|
12
|
-
// Part broadcast handler
|
|
9
|
+
// Part broadcast handler - just pass data, don't mutate state
|
|
13
10
|
const handlePartBroadcast = useCallback((payload) => {
|
|
14
11
|
console.log("[Parts] Broadcast received:", payload.payload.operation);
|
|
15
12
|
const data = payload.payload;
|
|
@@ -17,55 +14,18 @@ export function useScoutRealtimeParts(scoutSupabase) {
|
|
|
17
14
|
if (!partData)
|
|
18
15
|
return;
|
|
19
16
|
let operation;
|
|
20
|
-
// Find the target herd module and device
|
|
21
|
-
const herdModule = herdModules.find((hm) => hm.herd.id.toString() === activeHerdId);
|
|
22
|
-
if (!herdModule) {
|
|
23
|
-
console.warn("[Parts] No herd module found for active herd");
|
|
24
|
-
return;
|
|
25
|
-
}
|
|
26
|
-
const targetDevice = herdModule.devices.find((device) => device.id === partData.device_id);
|
|
27
|
-
if (!targetDevice) {
|
|
28
|
-
console.warn(`[Parts] No device found with ID: ${partData.device_id}`);
|
|
29
|
-
return;
|
|
30
|
-
}
|
|
31
|
-
// Ensure device has parts array
|
|
32
|
-
if (!targetDevice.parts) {
|
|
33
|
-
targetDevice.parts = [];
|
|
34
|
-
}
|
|
35
17
|
switch (data.operation) {
|
|
36
18
|
case "INSERT":
|
|
37
19
|
operation = EnumRealtimeOperation.INSERT;
|
|
38
|
-
|
|
39
|
-
console.log("[Parts] New part received:", data.record);
|
|
40
|
-
// Add part to device's parts array if not already present
|
|
41
|
-
const existingPartIndex = targetDevice.parts.findIndex((p) => p.id === data.record.id);
|
|
42
|
-
if (existingPartIndex === -1) {
|
|
43
|
-
targetDevice.parts.push(data.record);
|
|
44
|
-
}
|
|
45
|
-
}
|
|
20
|
+
console.log("[Parts] New part received:", data.record);
|
|
46
21
|
break;
|
|
47
22
|
case "UPDATE":
|
|
48
23
|
operation = EnumRealtimeOperation.UPDATE;
|
|
49
|
-
|
|
50
|
-
console.log("[Parts] Part updated:", data.record);
|
|
51
|
-
// Update existing part in device's parts array
|
|
52
|
-
const partIndex = targetDevice.parts.findIndex((p) => p.id === data.record.id);
|
|
53
|
-
if (partIndex !== -1) {
|
|
54
|
-
targetDevice.parts[partIndex] = data.record;
|
|
55
|
-
}
|
|
56
|
-
else {
|
|
57
|
-
// Part not found, add it
|
|
58
|
-
targetDevice.parts.push(data.record);
|
|
59
|
-
}
|
|
60
|
-
}
|
|
24
|
+
console.log("[Parts] Part updated:", data.record);
|
|
61
25
|
break;
|
|
62
26
|
case "DELETE":
|
|
63
27
|
operation = EnumRealtimeOperation.DELETE;
|
|
64
|
-
|
|
65
|
-
console.log("[Parts] Part deleted:", data.old_record);
|
|
66
|
-
// Remove part from device's parts array
|
|
67
|
-
targetDevice.parts = targetDevice.parts.filter((p) => p.id !== data.old_record.id);
|
|
68
|
-
}
|
|
28
|
+
console.log("[Parts] Part deleted:", data.old_record);
|
|
69
29
|
break;
|
|
70
30
|
default:
|
|
71
31
|
return;
|
|
@@ -76,7 +36,7 @@ export function useScoutRealtimeParts(scoutSupabase) {
|
|
|
76
36
|
};
|
|
77
37
|
console.log(`[scout-core realtime] PART ${data.operation} received:`, JSON.stringify(realtimeData));
|
|
78
38
|
setLatestPartUpdate(realtimeData);
|
|
79
|
-
}, [
|
|
39
|
+
}, []);
|
|
80
40
|
// Clear latest update
|
|
81
41
|
const clearLatestUpdate = useCallback(() => {
|
|
82
42
|
setLatestPartUpdate(null);
|
|
@@ -2,4 +2,4 @@ import { SupabaseClient } from "@supabase/supabase-js";
|
|
|
2
2
|
import { Database } from "../types/supabase";
|
|
3
3
|
import { IPin } from "../types/db";
|
|
4
4
|
import { RealtimeData } from "../types/realtime";
|
|
5
|
-
export declare function useScoutRealtimePins(scoutSupabase: SupabaseClient<Database
|
|
5
|
+
export declare function useScoutRealtimePins(scoutSupabase: SupabaseClient<Database>): [RealtimeData<IPin> | null, () => void];
|
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
import { useSelector } from "react-redux";
|
|
3
3
|
import { useEffect, useRef, useCallback, useState } from "react";
|
|
4
4
|
import { EnumRealtimeOperation } from "../types/realtime";
|
|
5
|
-
export function useScoutRealtimePins(scoutSupabase
|
|
5
|
+
export function useScoutRealtimePins(scoutSupabase) {
|
|
6
6
|
const channels = useRef([]);
|
|
7
7
|
const [latestPinUpdate, setLatestPinUpdate] = useState(null);
|
|
8
8
|
const activeHerdId = useSelector((state) => state.scout.active_herd_id);
|
|
9
|
-
// Pin broadcast handler
|
|
9
|
+
// Pin broadcast handler - just pass data, don't mutate state
|
|
10
10
|
const handlePinBroadcast = useCallback((payload) => {
|
|
11
11
|
console.log("[Pins] Broadcast received:", payload.payload.operation);
|
|
12
12
|
const data = payload.payload;
|
|
@@ -17,22 +17,15 @@ export function useScoutRealtimePins(scoutSupabase, shouldUpdateGlobalStateOnCha
|
|
|
17
17
|
switch (data.operation) {
|
|
18
18
|
case "INSERT":
|
|
19
19
|
operation = EnumRealtimeOperation.INSERT;
|
|
20
|
-
|
|
21
|
-
console.log("[Pins] New pin received:", data.record);
|
|
22
|
-
// TODO: dispatch(addPinToStore(data.record));
|
|
23
|
-
}
|
|
20
|
+
console.log("[Pins] New pin received:", data.record);
|
|
24
21
|
break;
|
|
25
22
|
case "UPDATE":
|
|
26
23
|
operation = EnumRealtimeOperation.UPDATE;
|
|
27
|
-
|
|
28
|
-
// TODO: dispatch(updatePinInStore(data.record));
|
|
29
|
-
}
|
|
24
|
+
console.log("[Pins] Pin updated:", data.record);
|
|
30
25
|
break;
|
|
31
26
|
case "DELETE":
|
|
32
27
|
operation = EnumRealtimeOperation.DELETE;
|
|
33
|
-
|
|
34
|
-
// TODO: dispatch(deletePinFromStore(data.old_record));
|
|
35
|
-
}
|
|
28
|
+
console.log("[Pins] Pin deleted:", data.old_record);
|
|
36
29
|
break;
|
|
37
30
|
default:
|
|
38
31
|
return;
|
|
@@ -43,7 +36,7 @@ export function useScoutRealtimePins(scoutSupabase, shouldUpdateGlobalStateOnCha
|
|
|
43
36
|
};
|
|
44
37
|
console.log(`[scout-core realtime] PIN ${data.operation} received for pin "${pinData.name}" (${pinData.id}):`, JSON.stringify(realtimeData));
|
|
45
38
|
setLatestPinUpdate(realtimeData);
|
|
46
|
-
}, [
|
|
39
|
+
}, []);
|
|
47
40
|
// Clear latest update
|
|
48
41
|
const clearLatestUpdate = useCallback(() => {
|
|
49
42
|
setLatestPinUpdate(null);
|
|
@@ -2,4 +2,4 @@ import { SupabaseClient } from "@supabase/supabase-js";
|
|
|
2
2
|
import { Database } from "../types/supabase";
|
|
3
3
|
import { IPlan } from "../types/db";
|
|
4
4
|
import { RealtimeData } from "../types/realtime";
|
|
5
|
-
export declare function useScoutRealtimePlans(scoutSupabase: SupabaseClient<Database
|
|
5
|
+
export declare function useScoutRealtimePlans(scoutSupabase: SupabaseClient<Database>): [RealtimeData<IPlan> | null, () => void];
|
|
@@ -1,15 +1,12 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { useAppDispatch } from "../store/hooks";
|
|
3
2
|
import { useSelector } from "react-redux";
|
|
4
3
|
import { useEffect, useRef, useCallback, useState } from "react";
|
|
5
|
-
import { addPlan, deletePlan, updatePlan } from "../store/scout";
|
|
6
4
|
import { EnumRealtimeOperation } from "../types/realtime";
|
|
7
|
-
export function useScoutRealtimePlans(scoutSupabase
|
|
5
|
+
export function useScoutRealtimePlans(scoutSupabase) {
|
|
8
6
|
const channels = useRef([]);
|
|
9
|
-
const dispatch = useAppDispatch();
|
|
10
7
|
const [latestPlanUpdate, setLatestPlanUpdate] = useState(null);
|
|
11
8
|
const activeHerdId = useSelector((state) => state.scout.active_herd_id);
|
|
12
|
-
// Plan broadcast handler
|
|
9
|
+
// Plan broadcast handler - just pass data, don't mutate state
|
|
13
10
|
const handlePlanBroadcast = useCallback((payload) => {
|
|
14
11
|
console.log("[Plans] Broadcast received:", payload.payload.operation);
|
|
15
12
|
const data = payload.payload;
|
|
@@ -20,22 +17,15 @@ export function useScoutRealtimePlans(scoutSupabase, shouldUpdateGlobalStateOnCh
|
|
|
20
17
|
switch (data.operation) {
|
|
21
18
|
case "INSERT":
|
|
22
19
|
operation = EnumRealtimeOperation.INSERT;
|
|
23
|
-
|
|
24
|
-
console.log("[Plans] New plan received:", data.record);
|
|
25
|
-
dispatch(addPlan(data.record));
|
|
26
|
-
}
|
|
20
|
+
console.log("[Plans] New plan received:", data.record);
|
|
27
21
|
break;
|
|
28
22
|
case "UPDATE":
|
|
29
23
|
operation = EnumRealtimeOperation.UPDATE;
|
|
30
|
-
|
|
31
|
-
dispatch(updatePlan(data.record));
|
|
32
|
-
}
|
|
24
|
+
console.log("[Plans] Plan updated:", data.record);
|
|
33
25
|
break;
|
|
34
26
|
case "DELETE":
|
|
35
27
|
operation = EnumRealtimeOperation.DELETE;
|
|
36
|
-
|
|
37
|
-
dispatch(deletePlan(data.old_record));
|
|
38
|
-
}
|
|
28
|
+
console.log("[Plans] Plan deleted:", data.old_record);
|
|
39
29
|
break;
|
|
40
30
|
default:
|
|
41
31
|
return;
|
|
@@ -46,7 +36,7 @@ export function useScoutRealtimePlans(scoutSupabase, shouldUpdateGlobalStateOnCh
|
|
|
46
36
|
};
|
|
47
37
|
console.log(`[scout-core realtime] PLAN ${data.operation} received:`, JSON.stringify(realtimeData));
|
|
48
38
|
setLatestPlanUpdate(realtimeData);
|
|
49
|
-
}, [
|
|
39
|
+
}, []);
|
|
50
40
|
// Clear latest update
|
|
51
41
|
const clearLatestUpdate = useCallback(() => {
|
|
52
42
|
setLatestPlanUpdate(null);
|
|
@@ -2,4 +2,4 @@ import { SupabaseClient } from "@supabase/supabase-js";
|
|
|
2
2
|
import { Database } from "../types/supabase";
|
|
3
3
|
import { ISessionWithCoordinates } from "../types/db";
|
|
4
4
|
import { RealtimeData } from "../types/realtime";
|
|
5
|
-
export declare function useScoutRealtimeSessions(scoutSupabase: SupabaseClient<Database
|
|
5
|
+
export declare function useScoutRealtimeSessions(scoutSupabase: SupabaseClient<Database>): [RealtimeData<ISessionWithCoordinates> | null, () => void];
|
|
@@ -1,15 +1,12 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { useSelector } from "react-redux";
|
|
3
|
-
import { useAppDispatch } from "../store/hooks";
|
|
4
3
|
import { useEffect, useRef, useCallback, useState } from "react";
|
|
5
4
|
import { EnumRealtimeOperation } from "../types/realtime";
|
|
6
|
-
|
|
7
|
-
export function useScoutRealtimeSessions(scoutSupabase, invalidateRTKQuery = true) {
|
|
5
|
+
export function useScoutRealtimeSessions(scoutSupabase) {
|
|
8
6
|
const channels = useRef([]);
|
|
9
|
-
const dispatch = useAppDispatch();
|
|
10
7
|
const [latestSessionUpdate, setLatestSessionUpdate] = useState(null);
|
|
11
8
|
const activeHerdId = useSelector((state) => state.scout.active_herd_id);
|
|
12
|
-
// Session broadcast handler
|
|
9
|
+
// Session broadcast handler - just pass data, don't mutate state
|
|
13
10
|
const handleSessionBroadcast = useCallback((payload) => {
|
|
14
11
|
console.log("[Sessions] Broadcast received:", payload.payload.operation);
|
|
15
12
|
const data = payload.payload;
|
|
@@ -20,30 +17,15 @@ export function useScoutRealtimeSessions(scoutSupabase, invalidateRTKQuery = tru
|
|
|
20
17
|
switch (data.operation) {
|
|
21
18
|
case "INSERT":
|
|
22
19
|
operation = EnumRealtimeOperation.INSERT;
|
|
23
|
-
|
|
24
|
-
console.log("[Sessions] New session received, invalidating RTK Query cache:", data.record);
|
|
25
|
-
// Invalidate all sessions queries to refetch fresh data
|
|
26
|
-
dispatch(scoutApi.util.invalidateTags(["Session"]));
|
|
27
|
-
}
|
|
20
|
+
console.log("[Sessions] New session received:", data.record);
|
|
28
21
|
break;
|
|
29
22
|
case "UPDATE":
|
|
30
23
|
operation = EnumRealtimeOperation.UPDATE;
|
|
31
|
-
|
|
32
|
-
console.log("[Sessions] Session updated, invalidating RTK Query cache:", data.record);
|
|
33
|
-
// Invalidate specific session and list queries
|
|
34
|
-
dispatch(scoutApi.util.invalidateTags([
|
|
35
|
-
{ type: "Session", id: data.record.id || "unknown" },
|
|
36
|
-
{ type: "Session", id: "LIST" },
|
|
37
|
-
]));
|
|
38
|
-
}
|
|
24
|
+
console.log("[Sessions] Session updated:", data.record);
|
|
39
25
|
break;
|
|
40
26
|
case "DELETE":
|
|
41
27
|
operation = EnumRealtimeOperation.DELETE;
|
|
42
|
-
|
|
43
|
-
console.log("[Sessions] Session deleted, invalidating RTK Query cache:", data.old_record);
|
|
44
|
-
// Invalidate all sessions queries since item was deleted
|
|
45
|
-
dispatch(scoutApi.util.invalidateTags(["Session"]));
|
|
46
|
-
}
|
|
28
|
+
console.log("[Sessions] Session deleted:", data.old_record);
|
|
47
29
|
break;
|
|
48
30
|
default:
|
|
49
31
|
return;
|
|
@@ -54,7 +36,7 @@ export function useScoutRealtimeSessions(scoutSupabase, invalidateRTKQuery = tru
|
|
|
54
36
|
};
|
|
55
37
|
console.log(`[scout-core realtime] SESSION ${data.operation} received:`, JSON.stringify(realtimeData));
|
|
56
38
|
setLatestSessionUpdate(realtimeData);
|
|
57
|
-
}, [
|
|
39
|
+
}, []);
|
|
58
40
|
// Clear latest update
|
|
59
41
|
const clearLatestUpdate = useCallback(() => {
|
|
60
42
|
setLatestSessionUpdate(null);
|
|
@@ -86,6 +68,6 @@ export function useScoutRealtimeSessions(scoutSupabase, invalidateRTKQuery = tru
|
|
|
86
68
|
channels.current.push(channel);
|
|
87
69
|
}
|
|
88
70
|
return cleanupChannels;
|
|
89
|
-
}, [activeHerdId, clearLatestUpdate
|
|
71
|
+
}, [activeHerdId, clearLatestUpdate]);
|
|
90
72
|
return [latestSessionUpdate, clearLatestUpdate];
|
|
91
73
|
}
|
|
@@ -2,4 +2,4 @@ import { SupabaseClient } from "@supabase/supabase-js";
|
|
|
2
2
|
import { Database } from "../types/supabase";
|
|
3
3
|
import { ITagPrettyLocation } from "../types/db";
|
|
4
4
|
import { RealtimeData } from "../types/realtime";
|
|
5
|
-
export declare function useScoutRealtimeTags(scoutSupabase: SupabaseClient<Database
|
|
5
|
+
export declare function useScoutRealtimeTags(scoutSupabase: SupabaseClient<Database>): [RealtimeData<ITagPrettyLocation> | null, () => void];
|
|
@@ -1,15 +1,12 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { useAppDispatch } from "../store/hooks";
|
|
3
2
|
import { useSelector } from "react-redux";
|
|
4
3
|
import { useEffect, useRef, useCallback, useState } from "react";
|
|
5
4
|
import { EnumRealtimeOperation } from "../types/realtime";
|
|
6
|
-
|
|
7
|
-
export function useScoutRealtimeTags(scoutSupabase, invalidateRTKQuery = true) {
|
|
5
|
+
export function useScoutRealtimeTags(scoutSupabase) {
|
|
8
6
|
const channels = useRef([]);
|
|
9
|
-
const dispatch = useAppDispatch();
|
|
10
7
|
const [latestTagUpdate, setLatestTagUpdate] = useState(null);
|
|
11
8
|
const activeHerdId = useSelector((state) => state.scout.active_herd_id);
|
|
12
|
-
// Tag broadcast handler
|
|
9
|
+
// Tag broadcast handler - just pass data, don't mutate state
|
|
13
10
|
const handleTagBroadcast = useCallback((payload) => {
|
|
14
11
|
console.log("[Tags] Broadcast received:", payload.payload.operation);
|
|
15
12
|
const data = payload.payload;
|
|
@@ -20,27 +17,15 @@ export function useScoutRealtimeTags(scoutSupabase, invalidateRTKQuery = true) {
|
|
|
20
17
|
switch (data.operation) {
|
|
21
18
|
case "INSERT":
|
|
22
19
|
operation = EnumRealtimeOperation.INSERT;
|
|
23
|
-
|
|
24
|
-
console.log("[Tags] New tag received, invalidating RTK Query cache:", data.record);
|
|
25
|
-
// Tags are part of events, so invalidate events queries
|
|
26
|
-
dispatch(scoutApi.util.invalidateTags(["Event"]));
|
|
27
|
-
}
|
|
20
|
+
console.log("[Tags] New tag received:", data.record);
|
|
28
21
|
break;
|
|
29
22
|
case "UPDATE":
|
|
30
23
|
operation = EnumRealtimeOperation.UPDATE;
|
|
31
|
-
|
|
32
|
-
console.log("[Tags] Tag updated, invalidating RTK Query cache:", data.record);
|
|
33
|
-
// Invalidate events queries since tags are embedded in events
|
|
34
|
-
dispatch(scoutApi.util.invalidateTags(["Event"]));
|
|
35
|
-
}
|
|
24
|
+
console.log("[Tags] Tag updated:", data.record);
|
|
36
25
|
break;
|
|
37
26
|
case "DELETE":
|
|
38
27
|
operation = EnumRealtimeOperation.DELETE;
|
|
39
|
-
|
|
40
|
-
console.log("[Tags] Tag deleted, invalidating RTK Query cache:", data.old_record);
|
|
41
|
-
// Invalidate events queries since tags are embedded in events
|
|
42
|
-
dispatch(scoutApi.util.invalidateTags(["Event"]));
|
|
43
|
-
}
|
|
28
|
+
console.log("[Tags] Tag deleted:", data.old_record);
|
|
44
29
|
break;
|
|
45
30
|
default:
|
|
46
31
|
return;
|
|
@@ -51,7 +36,7 @@ export function useScoutRealtimeTags(scoutSupabase, invalidateRTKQuery = true) {
|
|
|
51
36
|
};
|
|
52
37
|
console.log(`[scout-core realtime] TAG ${data.operation} received:`, JSON.stringify(realtimeData));
|
|
53
38
|
setLatestTagUpdate(realtimeData);
|
|
54
|
-
}, [
|
|
39
|
+
}, []);
|
|
55
40
|
// Clear latest update
|
|
56
41
|
const clearLatestUpdate = useCallback(() => {
|
|
57
42
|
setLatestTagUpdate(null);
|
|
@@ -7,6 +7,7 @@ import { server_load_herd_modules } from "../helpers/herds";
|
|
|
7
7
|
import { scoutCache } from "../helpers/cache";
|
|
8
8
|
import { EnumDataSource } from "../types/data_source";
|
|
9
9
|
import { createBrowserClient } from "@supabase/ssr";
|
|
10
|
+
import { getSupabaseUrl, getSupabaseAnonKey } from "../constants/env";
|
|
10
11
|
/**
|
|
11
12
|
* Hook for refreshing scout data with detailed timing measurements and cache-first loading
|
|
12
13
|
*
|
|
@@ -37,8 +38,9 @@ export function useScoutRefresh(options = {}) {
|
|
|
37
38
|
const store = useStore();
|
|
38
39
|
const refreshInProgressRef = useRef(false);
|
|
39
40
|
// Create Supabase client directly to avoid circular dependency
|
|
41
|
+
// Uses flexible environment variable helper for better PWA compatibility
|
|
40
42
|
const supabase = useMemo(() => {
|
|
41
|
-
return createBrowserClient(
|
|
43
|
+
return createBrowserClient(getSupabaseUrl(), getSupabaseAnonKey());
|
|
42
44
|
}, []);
|
|
43
45
|
// Refs to store timing measurements
|
|
44
46
|
const timingRefs = useRef({
|
|
@@ -3,6 +3,7 @@ import { jsx as _jsx } from "react/jsx-runtime";
|
|
|
3
3
|
import { useScoutRefresh } from "../hooks/useScoutRefresh";
|
|
4
4
|
import { createContext, useContext, useMemo, useRef } from "react";
|
|
5
5
|
import { createBrowserClient } from "@supabase/ssr";
|
|
6
|
+
import { getSupabaseUrl, getSupabaseAnonKey } from "../constants/env";
|
|
6
7
|
// Create context for the Supabase client
|
|
7
8
|
const SupabaseContext = createContext(null);
|
|
8
9
|
const ConnectionStatusContext = createContext(null);
|
|
@@ -24,8 +25,9 @@ export function useConnectionStatus() {
|
|
|
24
25
|
}
|
|
25
26
|
export function ScoutRefreshProvider({ children }) {
|
|
26
27
|
// Use refs to store the URL and key to prevent unnecessary recreations
|
|
27
|
-
|
|
28
|
-
const
|
|
28
|
+
// Uses flexible environment variable helper for better PWA compatibility
|
|
29
|
+
const urlRef = useRef(getSupabaseUrl());
|
|
30
|
+
const anonKeyRef = useRef(getSupabaseAnonKey());
|
|
29
31
|
// Create a single Supabase client instance that only runs once
|
|
30
32
|
const supabaseClient = useMemo(() => {
|
|
31
33
|
console.log("[ScoutRefreshProvider] Creating Supabase client");
|
package/dist/types/db.d.ts
CHANGED
|
@@ -54,6 +54,12 @@ export type PartInsert = Database["public"]["Tables"]["parts"]["Insert"];
|
|
|
54
54
|
export type VersionsSoftwareInsert = Database["public"]["Tables"]["versions_software"]["Insert"];
|
|
55
55
|
export type ArtifactInsert = Database["public"]["Tables"]["artifacts"]["Insert"];
|
|
56
56
|
export type PinInsert = Database["public"]["Tables"]["pins"]["Insert"];
|
|
57
|
+
export type SessionInsert = Database["public"]["Tables"]["sessions"]["Insert"];
|
|
58
|
+
export type SessionUpdate = Database["public"]["Tables"]["sessions"]["Update"];
|
|
59
|
+
export type ConnectivityInsert = Database["public"]["Tables"]["connectivity"]["Insert"];
|
|
60
|
+
export type ConnectivityUpdate = Database["public"]["Tables"]["connectivity"]["Update"];
|
|
61
|
+
export type EventInsert = Database["public"]["Tables"]["events"]["Insert"];
|
|
62
|
+
export type EventUpdate = Database["public"]["Tables"]["events"]["Update"];
|
|
57
63
|
export type IEventWithTags = Database["public"]["CompositeTypes"]["event_with_tags"] & {
|
|
58
64
|
earthranger_url: string | null;
|
|
59
65
|
file_path: string | null;
|