@adventurelabs/scout-core 1.0.57 → 1.0.59

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/README.md CHANGED
@@ -1,7 +1,108 @@
1
- # @adventurelabs/scout-core
1
+ # Scout Core
2
2
 
3
3
  Core utilities and helpers for Adventure Labs Scout applications.
4
4
 
5
+ ## Features
6
+
7
+ - **Herd Management**: Comprehensive herd and device management
8
+ - **Event Tracking**: Wildlife event monitoring and tagging
9
+ - **Real-time Updates**: Supabase-powered real-time data synchronization
10
+ - **State Management**: Redux-based state management with loading states
11
+
12
+ ## Herd Modules Loading State
13
+
14
+ The core provides a global loading state for herd modules, which are essential for many consuming applications. This state tracks whether herd modules are currently loading, have loaded successfully, or failed to load.
15
+
16
+ ### Loading State Enum
17
+
18
+ ```typescript
19
+ import { EnumHerdModulesLoadingState } from "@adventurelabs/scout-core";
20
+
21
+ enum EnumHerdModulesLoadingState {
22
+ NOT_LOADING = "NOT_LOADING",
23
+ LOADING = "LOADING",
24
+ SUCCESSFULLY_LOADED = "SUCCESSFULLY_LOADED",
25
+ UNSUCCESSFULLY_LOADED = "UNSUCCESSFULLY_LOADED",
26
+ }
27
+
28
+ **Available Hooks:**
29
+ - `useHerdModulesLoadingState()` - Get current loading state
30
+ - `useIsHerdModulesLoading()` - Check if currently loading
31
+ - `useIsHerdModulesLoaded()` - Check if successfully loaded
32
+ - `useIsHerdModulesFailed()` - Check if loading failed
33
+ - `useHerdModulesLoadedAt()` - Get how long the last loading took (in milliseconds)
34
+ - `useHerdModulesLoadingDuration()` - Get loading duration in milliseconds
35
+ - `useHerdModulesLoadingTimeAgo()` - Get formatted time ago since last loaded (e.g., "2.5s ago")
36
+ ```
37
+
38
+ ### Usage in Components
39
+
40
+ ```typescript
41
+ import {
42
+ useHerdModulesLoadingState,
43
+ useIsHerdModulesLoading,
44
+ useIsHerdModulesLoaded,
45
+ useIsHerdModulesFailed,
46
+ useHerdModulesLoadedAt,
47
+ useHerdModulesLoadingTimeAgo,
48
+ useHerdModulesLoadingDuration,
49
+ } from "@adventurelabs/scout-core";
50
+
51
+ function MyComponent() {
52
+ const loadingState = useHerdModulesLoadingState();
53
+ const isLoading = useIsHerdModulesLoading();
54
+ const isLoaded = useIsHerdModulesLoaded();
55
+ const isFailed = useIsHerdModulesFailed();
56
+
57
+ if (isLoading) {
58
+ return <div>Loading herd modules...</div>;
59
+ }
60
+
61
+ if (isFailed) {
62
+ return <div>Failed to load herd modules</div>;
63
+ }
64
+
65
+ if (isLoaded) {
66
+ return <div>Herd modules loaded successfully!</div>;
67
+ }
68
+
69
+ return <div>Not loading</div>;
70
+ }
71
+
72
+ // Example with loading duration information
73
+ function HerdModulesStatus() {
74
+ const loadingState = useHerdModulesLoadingState();
75
+ const loadingTimeMs = useHerdModulesLoadedAt();
76
+ const timeAgo = useHerdModulesLoadingTimeAgo();
77
+ const loadingDuration = useHerdModulesLoadingDuration();
78
+
79
+ return (
80
+ <div>
81
+ <div>Status: {loadingState}</div>
82
+ {loadingTimeMs && (
83
+ <>
84
+ <div>Last loading took: {loadingTimeMs}ms</div>
85
+ <div>Loaded: {timeAgo}</div>
86
+ <div>Loading duration: {loadingDuration}ms</div>
87
+ </>
88
+ )}
89
+ </div>
90
+ );
91
+ }
92
+ ```
93
+
94
+ ### Manual Refresh
95
+
96
+ ```typescript
97
+ import { useScoutRefresh } from "@adventurelabs/scout-core";
98
+
99
+ function RefreshButton() {
100
+ const { handleRefresh } = useScoutRefresh({ autoRefresh: false });
101
+
102
+ return <button onClick={handleRefresh}>Refresh Data</button>;
103
+ }
104
+ ```
105
+
5
106
  ## Installation
6
107
 
7
108
  ```bash
@@ -10,9 +111,31 @@ npm install @adventurelabs/scout-core
10
111
  yarn add @adventurelabs/scout-core
11
112
  ```
12
113
 
13
- ## Usage
114
+ ## Setup
115
+
116
+ Wrap your app with the ScoutRefreshProvider:
14
117
 
15
118
  ```typescript
119
+ import { ScoutRefreshProvider } from "@adventurelabs/scout-core";
120
+
121
+ function App() {
122
+ return (
123
+ <ScoutRefreshProvider>{/* Your app components */}</ScoutRefreshProvider>
124
+ );
125
+ }
126
+ ```
127
+
128
+ ## Recent Updates
129
+
130
+ - **v1.0.58**: Added global herd modules loading state tracking with timestamps
131
+ - Fixed repeat Supabase client creation logs
132
+ - Enhanced loading state management for better UX
133
+ - Added loading duration and time-ago tracking
134
+ - Added comprehensive edge case handling and race condition prevention
135
+
136
+ ## Usage
137
+
138
+ ````typescript
16
139
  import "../../app/globals.css";
17
140
  import StoreProvider from "../../components/Store/StoreProvider";
18
141
  import { ScoutRefreshProvider } from "@adventurelabs/scout-core";
@@ -33,7 +156,6 @@ export default function ScoutLayout({
33
156
  </StoreProvider>
34
157
  );
35
158
  }
36
- ```
37
159
 
38
160
  ## Available Modules
39
161
 
@@ -42,6 +164,7 @@ export default function ScoutLayout({
42
164
  - Database types from Supabase
43
165
  - Herd, Device, Event, User interfaces
44
166
  - Request/Response types
167
+ - Herd module loading state enums (`EnumHerdModulesLoadingState`)
45
168
 
46
169
  ### Helpers
47
170
 
@@ -95,7 +218,7 @@ function ConnectionStatus() {
95
218
 
96
219
  return <div>Status: {isConnected ? "Connected" : "Disconnected"}</div>;
97
220
  }
98
- ```
221
+ ````
99
222
 
100
223
  ### Store
101
224
 
@@ -128,3 +251,10 @@ yarn clean
128
251
  ## License
129
252
 
130
253
  GPL-3.0
254
+
255
+ **New Hooks** (in `core/store/hooks.ts`):
256
+
257
+ - `useHerdModulesLoadingState()` - Get current loading state
258
+ - `useIsHerdModulesLoading()` - Check if currently loading
259
+ - `useIsHerdModulesLoaded()` - Check if successfully loaded
260
+ - `
@@ -1,44 +1,84 @@
1
- import { useEffect } from "react";
1
+ import { useEffect, useCallback, useRef } from "react";
2
2
  import { useAppDispatch } from "../store/hooks";
3
- import { EnumScoutStateStatus, setActiveHerdId, setHerdModules, setStatus, setUser, } from "../store/scout";
3
+ import { EnumScoutStateStatus, setActiveHerdId, setHerdModules, setStatus, setHerdModulesLoadingState, setHerdModulesLoadedInMs, setUser, } from "../store/scout";
4
+ import { EnumHerdModulesLoadingState } from "../types/herd_module";
4
5
  import { server_load_herd_modules } from "../helpers/herds";
5
6
  import { server_get_user } from "../helpers/users";
6
7
  export function useScoutRefresh(options = {}) {
7
8
  const { autoRefresh = true, onRefreshComplete } = options;
8
9
  const dispatch = useAppDispatch();
9
- const handleRefresh = async () => {
10
- dispatch(setStatus(EnumScoutStateStatus.LOADING));
10
+ const refreshInProgressRef = useRef(false);
11
+ const handleRefresh = useCallback(async () => {
12
+ // Prevent concurrent refresh calls
13
+ if (refreshInProgressRef.current) {
14
+ console.warn("[useScoutRefresh] Refresh already in progress, skipping");
15
+ return;
16
+ }
17
+ refreshInProgressRef.current = true;
18
+ const startTime = Date.now();
11
19
  try {
20
+ dispatch(setStatus(EnumScoutStateStatus.LOADING));
21
+ dispatch(setHerdModulesLoadingState(EnumHerdModulesLoadingState.LOADING));
12
22
  const compatible_new_herd_modules = await server_load_herd_modules();
13
23
  const res_new_user = await server_get_user();
24
+ // Validate API responses
25
+ if (!compatible_new_herd_modules ||
26
+ !Array.isArray(compatible_new_herd_modules)) {
27
+ throw new Error("Invalid herd modules response");
28
+ }
29
+ if (!res_new_user || !res_new_user.data) {
30
+ throw new Error("Invalid user response");
31
+ }
32
+ const loadingDuration = Date.now() - startTime;
14
33
  dispatch(setHerdModules(compatible_new_herd_modules));
15
34
  dispatch(setUser(res_new_user.data));
16
- // Check local storage for a last selected herd
17
- if (localStorage.getItem("last_selected_herd")) {
18
- const found_herd = compatible_new_herd_modules.find((hm) => hm.herd.id.toString() === localStorage.getItem("last_selected_herd"))?.herd;
19
- // If herd is found then set it
20
- if (found_herd) {
21
- dispatch(setActiveHerdId(found_herd.id.toString()));
35
+ dispatch(setHerdModulesLoadingState(EnumHerdModulesLoadingState.SUCCESSFULLY_LOADED));
36
+ dispatch(setHerdModulesLoadedInMs(loadingDuration));
37
+ // Safely handle localStorage operations
38
+ try {
39
+ // Check local storage for a last selected herd
40
+ const lastSelectedHerd = localStorage.getItem("last_selected_herd");
41
+ if (lastSelectedHerd) {
42
+ const found_herd = compatible_new_herd_modules.find((hm) => hm.herd.id.toString() === lastSelectedHerd)?.herd;
43
+ // If herd is found then set it
44
+ if (found_herd) {
45
+ dispatch(setActiveHerdId(found_herd.id.toString()));
46
+ }
47
+ }
48
+ // If there is no last selected herd then select the first one
49
+ else if (compatible_new_herd_modules.length > 0) {
50
+ const firstHerdId = compatible_new_herd_modules[0].herd.id.toString();
51
+ localStorage.setItem("last_selected_herd", firstHerdId);
52
+ dispatch(setActiveHerdId(firstHerdId));
22
53
  }
23
54
  }
24
- // If there is no last selected herd then select the first one
25
- else if (compatible_new_herd_modules.length > 0) {
26
- localStorage.setItem("last_selected_herd", compatible_new_herd_modules[0].herd.id.toString());
27
- dispatch(setActiveHerdId(compatible_new_herd_modules[0].herd.id.toString()));
55
+ catch (localStorageError) {
56
+ console.warn("[useScoutRefresh] localStorage not available:", localStorageError);
57
+ // Fallback: select first herd without localStorage
58
+ if (compatible_new_herd_modules.length > 0) {
59
+ dispatch(setActiveHerdId(compatible_new_herd_modules[0].herd.id.toString()));
60
+ }
28
61
  }
29
62
  dispatch(setStatus(EnumScoutStateStatus.DONE_LOADING));
30
63
  onRefreshComplete?.();
31
64
  }
32
65
  catch (error) {
66
+ const loadingDuration = Date.now() - startTime;
33
67
  console.error("Error refreshing scout data:", error);
68
+ // Ensure consistent state updates on error
69
+ dispatch(setHerdModulesLoadingState(EnumHerdModulesLoadingState.UNSUCCESSFULLY_LOADED));
70
+ dispatch(setHerdModulesLoadedInMs(loadingDuration));
34
71
  dispatch(setStatus(EnumScoutStateStatus.DONE_LOADING));
35
72
  }
36
- };
73
+ finally {
74
+ refreshInProgressRef.current = false;
75
+ }
76
+ }, [dispatch, onRefreshComplete]);
37
77
  useEffect(() => {
38
78
  if (autoRefresh) {
39
79
  handleRefresh();
40
80
  }
41
- }, [autoRefresh]);
81
+ }, [autoRefresh, handleRefresh]);
42
82
  return {
43
83
  handleRefresh,
44
84
  };
@@ -2,7 +2,7 @@
2
2
  import { jsx as _jsx } from "react/jsx-runtime";
3
3
  import { useScoutRefresh } from "../hooks/useScoutRefresh";
4
4
  import { useScoutDbListener } from "../hooks/useScoutDbListener";
5
- import { createContext, useContext, useRef } from "react";
5
+ import { createContext, useContext, useMemo } from "react";
6
6
  import { createBrowserClient } from "@supabase/ssr";
7
7
  // Create context for the Supabase client
8
8
  const SupabaseContext = createContext(null);
@@ -26,14 +26,13 @@ export function useConnectionStatus() {
26
26
  export function ScoutRefreshProvider({ children }) {
27
27
  const url = process.env.NEXT_PUBLIC_SUPABASE_URL || "";
28
28
  const anon_key = process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY || "";
29
- // Create a single Supabase client instance
30
- const supabaseRef = useRef(null);
31
- if (!supabaseRef.current) {
32
- supabaseRef.current = createBrowserClient(url, anon_key);
33
- console.log("[ScoutRefreshProvider] Created Supabase client");
34
- }
29
+ // Create a single Supabase client instance using useMemo to prevent recreation
30
+ const supabaseClient = useMemo(() => {
31
+ console.log("[ScoutRefreshProvider] Creating Supabase client");
32
+ return createBrowserClient(url, anon_key);
33
+ }, [url, anon_key]);
35
34
  // Use the enhanced DB listener with connection status
36
- useScoutDbListener(supabaseRef.current);
35
+ useScoutDbListener(supabaseClient);
37
36
  useScoutRefresh();
38
37
  // // Log connection status changes for debugging
39
38
  // if (connectionStatus.lastError) {
@@ -45,5 +44,5 @@ export function ScoutRefreshProvider({ children }) {
45
44
  // if (connectionStatus.isConnected) {
46
45
  // console.log("[ScoutRefreshProvider] ✅ DB Listener connected");
47
46
  // }
48
- return (_jsx(SupabaseContext.Provider, { value: supabaseRef.current, children: children }));
47
+ return (_jsx(SupabaseContext.Provider, { value: supabaseClient, children: children }));
49
48
  }
@@ -1 +1,8 @@
1
1
  export declare const useAppDispatch: <AppDispatch extends import("redux").Dispatch<import("redux").AnyAction> = import("redux").Dispatch<import("redux").AnyAction>>() => AppDispatch;
2
+ export declare const useHerdModulesLoadingState: () => any;
3
+ export declare const useIsHerdModulesLoading: () => boolean;
4
+ export declare const useIsHerdModulesLoaded: () => boolean;
5
+ export declare const useIsHerdModulesFailed: () => boolean;
6
+ export declare const useHerdModulesLoadedAt: () => any;
7
+ export declare const useHerdModulesLoadingDuration: () => any;
8
+ export declare const useHerdModulesLoadingTimeAgo: () => string | null;
@@ -1,3 +1,67 @@
1
- import { useDispatch } from "react-redux";
1
+ import { useDispatch, useSelector } from "react-redux";
2
+ import { EnumHerdModulesLoadingState } from "../types/herd_module";
2
3
  // Simple wrapper for useDispatch to maintain compatibility
3
4
  export const useAppDispatch = useDispatch;
5
+ // Selector hook for herd modules loading state
6
+ export const useHerdModulesLoadingState = () => {
7
+ return useSelector((state) => state.scout.herd_modules_loading_state);
8
+ };
9
+ // Selector hook for checking if herd modules are currently loading
10
+ export const useIsHerdModulesLoading = () => {
11
+ return useSelector((state) => state.scout.herd_modules_loading_state ===
12
+ EnumHerdModulesLoadingState.LOADING);
13
+ };
14
+ // Selector hook for checking if herd modules loaded successfully
15
+ export const useIsHerdModulesLoaded = () => {
16
+ return useSelector((state) => state.scout.herd_modules_loading_state ===
17
+ EnumHerdModulesLoadingState.SUCCESSFULLY_LOADED);
18
+ };
19
+ // Selector hook for checking if herd modules failed to load
20
+ export const useIsHerdModulesFailed = () => {
21
+ return useSelector((state) => state.scout.herd_modules_loading_state ===
22
+ EnumHerdModulesLoadingState.UNSUCCESSFULLY_LOADED);
23
+ };
24
+ // Selector hook for getting when herd modules were last loaded
25
+ export const useHerdModulesLoadedAt = () => {
26
+ return useSelector((state) => state.scout.herd_modules_loaded_in_ms);
27
+ };
28
+ // Selector hook for getting the loading duration in milliseconds
29
+ export const useHerdModulesLoadingDuration = () => {
30
+ return useSelector((state) => {
31
+ return state.scout.herd_modules_loaded_in_ms;
32
+ });
33
+ };
34
+ // Selector hook for getting formatted loading time (e.g., "2.5s ago")
35
+ export const useHerdModulesLoadingTimeAgo = () => {
36
+ return useSelector((state) => {
37
+ const loadingDuration = state.scout.herd_modules_loaded_in_ms;
38
+ if (!loadingDuration)
39
+ return null;
40
+ // Since we store the duration, we need to calculate when it was loaded
41
+ // We'll use the lastRefreshed timestamp from the store
42
+ const lastRefreshed = state.scout.lastRefreshed;
43
+ if (!lastRefreshed)
44
+ return null;
45
+ const now = Date.now();
46
+ const timeSinceLoaded = now - lastRefreshed;
47
+ // Handle edge case where timeSinceLoaded might be negative
48
+ if (timeSinceLoaded < 0) {
49
+ return "just now";
50
+ }
51
+ const diffSeconds = Math.floor(timeSinceLoaded / 1000);
52
+ const diffMinutes = Math.floor(diffSeconds / 60);
53
+ const diffHours = Math.floor(diffMinutes / 60);
54
+ if (diffHours > 0) {
55
+ return `${diffHours}h ago`;
56
+ }
57
+ else if (diffMinutes > 0) {
58
+ return `${diffMinutes}m ago`;
59
+ }
60
+ else if (diffSeconds > 0) {
61
+ return `${diffSeconds}s ago`;
62
+ }
63
+ else {
64
+ return "just now";
65
+ }
66
+ });
67
+ };
@@ -1,5 +1,5 @@
1
1
  import { IUser } from "../types/db";
2
- import { IHerdModule } from "../types/herd_module";
2
+ import { IHerdModule, EnumHerdModulesLoadingState } from "../types/herd_module";
3
3
  export declare enum EnumScoutStateStatus {
4
4
  LOADING = "LOADING",
5
5
  DONE_LOADING = "DONE_LOADING"
@@ -7,6 +7,8 @@ export declare enum EnumScoutStateStatus {
7
7
  export interface ScoutState {
8
8
  herd_modules: IHerdModule[];
9
9
  status: EnumScoutStateStatus;
10
+ herd_modules_loading_state: EnumHerdModulesLoadingState;
11
+ herd_modules_loaded_in_ms: number | null;
10
12
  active_herd_id: string | null;
11
13
  active_device_id: string | null;
12
14
  lastRefreshed: number;
@@ -21,6 +23,14 @@ export declare const scoutSlice: import("@reduxjs/toolkit").Slice<ScoutState, {
21
23
  payload: any;
22
24
  type: string;
23
25
  }) => void;
26
+ setHerdModulesLoadingState: (state: import("immer").WritableDraft<ScoutState>, action: {
27
+ payload: any;
28
+ type: string;
29
+ }) => void;
30
+ setHerdModulesLoadedInMs: (state: import("immer").WritableDraft<ScoutState>, action: {
31
+ payload: any;
32
+ type: string;
33
+ }) => void;
24
34
  setActiveHerdId: (state: import("immer").WritableDraft<ScoutState>, action: {
25
35
  payload: any;
26
36
  type: string;
@@ -110,6 +120,6 @@ export declare const scoutSlice: import("@reduxjs/toolkit").Slice<ScoutState, {
110
120
  type: string;
111
121
  }) => void;
112
122
  }, "scout", "scout", import("@reduxjs/toolkit").SliceSelectors<ScoutState>>;
113
- export declare const setHerdModules: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/setHerdModules">, setStatus: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/setStatus">, setActiveHerdId: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/setActiveHerdId">, setActiveDeviceId: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/setActiveDeviceId">, appendEventsToHerdModule: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/appendEventsToHerdModule">, replaceEventsForHerdModule: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/replaceEventsForHerdModule">, updateEventValuesForHerdModule: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/updateEventValuesForHerdModule">, updatePageIndexForHerdModule: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/updatePageIndexForHerdModule">, appendPlansToHerdModule: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/appendPlansToHerdModule">, setUser: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/setUser">, addTag: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/addTag">, deleteTag: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/deleteTag">, updateTag: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/updateTag">, addNewDeviceToHerdModule: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/addNewDeviceToHerdModule">, updateDeviceForHerdModule: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/updateDeviceForHerdModule">, addDevice: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/addDevice">, deleteDevice: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/deleteDevice">, updateDevice: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/updateDevice">, addPlan: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/addPlan">, deletePlan: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/deletePlan">, updatePlan: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/updatePlan">, addSessionToStore: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/addSessionToStore">, deleteSessionFromStore: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/deleteSessionFromStore">, updateSessionInStore: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/updateSessionInStore">;
123
+ export declare const setHerdModules: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/setHerdModules">, setStatus: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/setStatus">, setHerdModulesLoadingState: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/setHerdModulesLoadingState">, setHerdModulesLoadedInMs: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/setHerdModulesLoadedInMs">, setActiveHerdId: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/setActiveHerdId">, setActiveDeviceId: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/setActiveDeviceId">, appendEventsToHerdModule: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/appendEventsToHerdModule">, replaceEventsForHerdModule: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/replaceEventsForHerdModule">, updateEventValuesForHerdModule: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/updateEventValuesForHerdModule">, updatePageIndexForHerdModule: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/updatePageIndexForHerdModule">, appendPlansToHerdModule: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/appendPlansToHerdModule">, setUser: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/setUser">, addTag: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/addTag">, deleteTag: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/deleteTag">, updateTag: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/updateTag">, addNewDeviceToHerdModule: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/addNewDeviceToHerdModule">, updateDeviceForHerdModule: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/updateDeviceForHerdModule">, addDevice: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/addDevice">, deleteDevice: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/deleteDevice">, updateDevice: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/updateDevice">, addPlan: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/addPlan">, deletePlan: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/deletePlan">, updatePlan: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/updatePlan">, addSessionToStore: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/addSessionToStore">, deleteSessionFromStore: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/deleteSessionFromStore">, updateSessionInStore: import("@reduxjs/toolkit").ActionCreatorWithPayload<any, "scout/updateSessionInStore">;
114
124
  declare const _default: import("redux").Reducer<ScoutState>;
115
125
  export default _default;
@@ -1,4 +1,5 @@
1
1
  import { createSlice } from "@reduxjs/toolkit";
2
+ import { EnumHerdModulesLoadingState } from "../types/herd_module";
2
3
  export var EnumScoutStateStatus;
3
4
  (function (EnumScoutStateStatus) {
4
5
  EnumScoutStateStatus["LOADING"] = "LOADING";
@@ -7,6 +8,8 @@ export var EnumScoutStateStatus;
7
8
  const initialState = {
8
9
  herd_modules: [],
9
10
  status: EnumScoutStateStatus.LOADING,
11
+ herd_modules_loading_state: EnumHerdModulesLoadingState.NOT_LOADING,
12
+ herd_modules_loaded_in_ms: null,
10
13
  lastRefreshed: 0,
11
14
  active_herd_id: null,
12
15
  active_device_id: null,
@@ -23,6 +26,12 @@ export const scoutSlice = createSlice({
23
26
  setStatus: (state, action) => {
24
27
  state.status = action.payload;
25
28
  },
29
+ setHerdModulesLoadingState: (state, action) => {
30
+ state.herd_modules_loading_state = action.payload;
31
+ },
32
+ setHerdModulesLoadedInMs: (state, action) => {
33
+ state.herd_modules_loaded_in_ms = action.payload;
34
+ },
26
35
  setActiveHerdId: (state, action) => {
27
36
  state.active_herd_id = action.payload;
28
37
  },
@@ -228,5 +237,5 @@ export const scoutSlice = createSlice({
228
237
  },
229
238
  });
230
239
  // Action creators are generated for each case reducer function
231
- export const { setHerdModules, setStatus, setActiveHerdId, setActiveDeviceId, appendEventsToHerdModule, replaceEventsForHerdModule, updateEventValuesForHerdModule, updatePageIndexForHerdModule, appendPlansToHerdModule, setUser, addTag, deleteTag, updateTag, addNewDeviceToHerdModule, updateDeviceForHerdModule, addDevice, deleteDevice, updateDevice, addPlan, deletePlan, updatePlan, addSessionToStore, deleteSessionFromStore, updateSessionInStore, } = scoutSlice.actions;
240
+ export const { setHerdModules, setStatus, setHerdModulesLoadingState, setHerdModulesLoadedInMs, setActiveHerdId, setActiveDeviceId, appendEventsToHerdModule, replaceEventsForHerdModule, updateEventValuesForHerdModule, updatePageIndexForHerdModule, appendPlansToHerdModule, setUser, addTag, deleteTag, updateTag, addNewDeviceToHerdModule, updateDeviceForHerdModule, addDevice, deleteDevice, updateDevice, addPlan, deletePlan, updatePlan, addSessionToStore, deleteSessionFromStore, updateSessionInStore, } = scoutSlice.actions;
232
241
  export default scoutSlice.reducer;
@@ -1,5 +1,11 @@
1
1
  import { SupabaseClient } from "@supabase/supabase-js";
2
2
  import { IDevice, IEventWithTags, IHerd, IPlan, ILayer, IUserAndRole, IZoneWithActions, ISessionWithCoordinates } from "../types/db";
3
+ export declare enum EnumHerdModulesLoadingState {
4
+ NOT_LOADING = "NOT_LOADING",
5
+ LOADING = "LOADING",
6
+ SUCCESSFULLY_LOADED = "SUCCESSFULLY_LOADED",
7
+ UNSUCCESSFULLY_LOADED = "UNSUCCESSFULLY_LOADED"
8
+ }
3
9
  export declare class HerdModule {
4
10
  herd: IHerd;
5
11
  devices: IDevice[];
@@ -10,6 +10,13 @@ import { EnumWebResponse } from "./requests";
10
10
  import { server_get_more_zones_and_actions_for_herd } from "../helpers/zones";
11
11
  import { server_list_api_keys_batch } from "../api_keys/actions";
12
12
  import { getSessionsByHerdId } from "../helpers/sessions";
13
+ export var EnumHerdModulesLoadingState;
14
+ (function (EnumHerdModulesLoadingState) {
15
+ EnumHerdModulesLoadingState["NOT_LOADING"] = "NOT_LOADING";
16
+ EnumHerdModulesLoadingState["LOADING"] = "LOADING";
17
+ EnumHerdModulesLoadingState["SUCCESSFULLY_LOADED"] = "SUCCESSFULLY_LOADED";
18
+ EnumHerdModulesLoadingState["UNSUCCESSFULLY_LOADED"] = "UNSUCCESSFULLY_LOADED";
19
+ })(EnumHerdModulesLoadingState || (EnumHerdModulesLoadingState = {}));
13
20
  export class HerdModule {
14
21
  constructor(herd, devices, events, timestamp_last_refreshed, user_roles = null, events_page_index = 0, total_events = 0, total_events_with_filters = 0, labels = [], plans = [], zones = [], sessions = [], layers = []) {
15
22
  this.user_roles = null;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adventurelabs/scout-core",
3
- "version": "1.0.57",
3
+ "version": "1.0.59",
4
4
  "description": "Core utilities and helpers for Adventure Labs Scout applications",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -44,7 +44,7 @@
44
44
  "typescript": "^5.0.0"
45
45
  },
46
46
  "dependencies": {
47
- "@supabase/supabase-js": "^2.53.6",
47
+ "@supabase/supabase-js": "^2.53.0",
48
48
  "@supabase/ssr": "^0.6.1",
49
49
  "@reduxjs/toolkit": "^2.0.0",
50
50
  "zustand": "^4.0.0"