@adventurelabs/scout-core 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +90 -0
- package/dist/api_keys/actions.d.ts +2 -0
- package/dist/api_keys/actions.js +20 -0
- package/dist/api_keys/index.d.ts +1 -0
- package/dist/api_keys/index.js +1 -0
- package/dist/constants/annotator.d.ts +1 -0
- package/dist/constants/annotator.js +11 -0
- package/dist/constants/app.d.ts +2 -0
- package/dist/constants/app.js +2 -0
- package/dist/constants/index.d.ts +2 -0
- package/dist/constants/index.js +2 -0
- package/dist/helpers/auth.d.ts +1 -0
- package/dist/helpers/auth.js +8 -0
- package/dist/helpers/bounding_boxes.d.ts +5 -0
- package/dist/helpers/bounding_boxes.js +43 -0
- package/dist/helpers/db.d.ts +3 -0
- package/dist/helpers/db.js +22 -0
- package/dist/helpers/devices.d.ts +8 -0
- package/dist/helpers/devices.js +92 -0
- package/dist/helpers/email.d.ts +7 -0
- package/dist/helpers/email.js +22 -0
- package/dist/helpers/events.d.ts +6 -0
- package/dist/helpers/events.js +71 -0
- package/dist/helpers/finance.d.ts +9 -0
- package/dist/helpers/finance.js +16 -0
- package/dist/helpers/gps.d.ts +5 -0
- package/dist/helpers/gps.js +11 -0
- package/dist/helpers/herds.d.ts +9 -0
- package/dist/helpers/herds.js +80 -0
- package/dist/helpers/index.d.ts +17 -0
- package/dist/helpers/index.js +17 -0
- package/dist/helpers/location.d.ts +1 -0
- package/dist/helpers/location.js +3 -0
- package/dist/helpers/plans.d.ts +5 -0
- package/dist/helpers/plans.js +61 -0
- package/dist/helpers/tags.d.ts +7 -0
- package/dist/helpers/tags.js +158 -0
- package/dist/helpers/time.d.ts +3 -0
- package/dist/helpers/time.js +11 -0
- package/dist/helpers/ui.d.ts +4 -0
- package/dist/helpers/ui.js +12 -0
- package/dist/helpers/users.d.ts +6 -0
- package/dist/helpers/users.js +66 -0
- package/dist/helpers/web.d.ts +1 -0
- package/dist/helpers/web.js +7 -0
- package/dist/helpers/zones.d.ts +18 -0
- package/dist/helpers/zones.js +108 -0
- package/dist/hooks/index.d.ts +2 -0
- package/dist/hooks/index.js +2 -0
- package/dist/hooks/useScoutDbListener.d.ts +1 -0
- package/dist/hooks/useScoutDbListener.js +94 -0
- package/dist/hooks/useScoutRefresh.d.ts +7 -0
- package/dist/hooks/useScoutRefresh.js +45 -0
- package/dist/index.d.ts +38 -0
- package/dist/index.js +43 -0
- package/dist/providers/ScoutRefreshProvider.d.ts +1 -0
- package/dist/providers/ScoutRefreshProvider.js +8 -0
- package/dist/providers/index.d.ts +1 -0
- package/dist/providers/index.js +1 -0
- package/dist/store/hooks.d.ts +1 -0
- package/dist/store/hooks.js +3 -0
- package/dist/store/index.d.ts +1 -0
- package/dist/store/index.js +1 -0
- package/dist/store/scout.d.ts +103 -0
- package/dist/store/scout.js +196 -0
- package/dist/supabase/client.d.ts +1 -0
- package/dist/supabase/client.js +5 -0
- package/dist/supabase/index.d.ts +3 -0
- package/dist/supabase/index.js +3 -0
- package/dist/supabase/middleware.d.ts +2 -0
- package/dist/supabase/middleware.js +46 -0
- package/dist/supabase/server.d.ts +636 -0
- package/dist/supabase/server.js +22 -0
- package/dist/types/bounding_boxes.d.ts +27 -0
- package/dist/types/bounding_boxes.js +11 -0
- package/dist/types/db.d.ts +42 -0
- package/dist/types/db.js +15 -0
- package/dist/types/gps.d.ts +21 -0
- package/dist/types/gps.js +13 -0
- package/dist/types/herd_module.d.ts +31 -0
- package/dist/types/herd_module.js +82 -0
- package/dist/types/index.d.ts +6 -0
- package/dist/types/index.js +6 -0
- package/dist/types/requests.d.ts +18 -0
- package/dist/types/requests.js +25 -0
- package/dist/types/supabase.d.ts +754 -0
- package/dist/types/supabase.js +25 -0
- package/dist/types/ui.d.ts +7 -0
- package/dist/types/ui.js +8 -0
- package/package.json +52 -0
package/README.md
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# @adventurelabs/scout-core
|
|
2
|
+
|
|
3
|
+
Core utilities and helpers for Adventure Labs Scout applications.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @adventurelabs/scout-core
|
|
9
|
+
# or
|
|
10
|
+
yarn add @adventurelabs/scout-core
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Usage
|
|
14
|
+
|
|
15
|
+
```typescript
|
|
16
|
+
import {
|
|
17
|
+
HerdModule,
|
|
18
|
+
IDevice,
|
|
19
|
+
IEvent,
|
|
20
|
+
isEmailValidForLogin,
|
|
21
|
+
useScoutDbListener,
|
|
22
|
+
useScoutRefresh,
|
|
23
|
+
} from "@adventurelabs/scout-core";
|
|
24
|
+
|
|
25
|
+
// Use the HerdModule class
|
|
26
|
+
const herdModule = new HerdModule(herd, devices, events, Date.now());
|
|
27
|
+
|
|
28
|
+
// Use helper functions
|
|
29
|
+
const isValidEmail = isEmailValidForLogin("user@adventurelabs.earth");
|
|
30
|
+
|
|
31
|
+
// Use React hooks for real-time database listening
|
|
32
|
+
useScoutDbListener(); // Automatically listens for changes to plans, devices, and tags
|
|
33
|
+
|
|
34
|
+
// Use refresh hook
|
|
35
|
+
const { handleRefresh } = useScoutRefresh({ autoRefresh: true });
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Available Modules
|
|
39
|
+
|
|
40
|
+
### Types
|
|
41
|
+
|
|
42
|
+
- Database types from Supabase
|
|
43
|
+
- Herd, Device, Event, User interfaces
|
|
44
|
+
- Request/Response types
|
|
45
|
+
|
|
46
|
+
### Helpers
|
|
47
|
+
|
|
48
|
+
- Authentication utilities
|
|
49
|
+
- Database operations
|
|
50
|
+
- Email validation
|
|
51
|
+
- GPS and location helpers
|
|
52
|
+
- Device and event management
|
|
53
|
+
- Tag and annotation utilities
|
|
54
|
+
|
|
55
|
+
### Hooks
|
|
56
|
+
|
|
57
|
+
- `useScoutDbListener` - Real-time database listening for plans, devices, and tags
|
|
58
|
+
- `useScoutRefresh` - Data refresh utilities
|
|
59
|
+
|
|
60
|
+
### Store
|
|
61
|
+
|
|
62
|
+
- Zustand-based state management for Scout applications
|
|
63
|
+
|
|
64
|
+
### Supabase
|
|
65
|
+
|
|
66
|
+
- Client, server, and middleware utilities for Supabase integration
|
|
67
|
+
|
|
68
|
+
### API Keys
|
|
69
|
+
|
|
70
|
+
- API key management utilities
|
|
71
|
+
|
|
72
|
+
## Development
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
# Install dependencies
|
|
76
|
+
yarn install
|
|
77
|
+
|
|
78
|
+
# Build the package
|
|
79
|
+
yarn build
|
|
80
|
+
|
|
81
|
+
# Watch for changes
|
|
82
|
+
yarn dev
|
|
83
|
+
|
|
84
|
+
# Clean build artifacts
|
|
85
|
+
yarn clean
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## License
|
|
89
|
+
|
|
90
|
+
MIT
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use server";
|
|
2
|
+
import { newServerClient } from "../supabase/server";
|
|
3
|
+
export async function server_list_api_keys(device_id) {
|
|
4
|
+
const supabase = await newServerClient();
|
|
5
|
+
const { data, error } = await supabase.rpc("load_api_keys", {
|
|
6
|
+
id_of_device: device_id,
|
|
7
|
+
});
|
|
8
|
+
if (error) {
|
|
9
|
+
console.error("Error listing API keys:", error.message);
|
|
10
|
+
}
|
|
11
|
+
if (!data)
|
|
12
|
+
return [];
|
|
13
|
+
const data_to_return = [];
|
|
14
|
+
for (let i = 0; i < data.length; i++) {
|
|
15
|
+
// convert data to IApiKeyScout
|
|
16
|
+
const converted_data = JSON.parse(data[i]);
|
|
17
|
+
data_to_return.push(converted_data);
|
|
18
|
+
}
|
|
19
|
+
return data_to_return;
|
|
20
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./actions";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./actions";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const LABELS: string[];
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function isEmailValidForLogin(email: string, approved_domains?: string[]): boolean;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { validateEmail } from "./email";
|
|
2
|
+
const APPROVED_DOMAINS = ["adventurelabs.earth", "conservaition.ai"];
|
|
3
|
+
export function isEmailValidForLogin(email, approved_domains = APPROVED_DOMAINS) {
|
|
4
|
+
return (validateEmail(email) && isEmailFromApprovedDomain(email, approved_domains));
|
|
5
|
+
}
|
|
6
|
+
function isEmailFromApprovedDomain(email, approved_domains = APPROVED_DOMAINS) {
|
|
7
|
+
return approved_domains.filter((domain) => email.endsWith(domain)).length > 0;
|
|
8
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { BoundingBox, EnumSourceBoundingBox } from "../types/bounding_boxes";
|
|
2
|
+
import { Tag } from "../types/db";
|
|
3
|
+
export declare function convertManualBoundingBoxToTag(boundingBox: BoundingBox, event_id: number): Tag;
|
|
4
|
+
export declare function convertTagToBoundingBox(tag: Tag, source: EnumSourceBoundingBox): BoundingBox;
|
|
5
|
+
export declare function formatBoundingBoxLabel(label: string): string;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { SelectionStatus, } from "../types/bounding_boxes";
|
|
2
|
+
export function convertManualBoundingBoxToTag(boundingBox, event_id) {
|
|
3
|
+
const newClassName = boundingBox.label;
|
|
4
|
+
// try to convert if nan, make it 0
|
|
5
|
+
let newId = Number(boundingBox.id);
|
|
6
|
+
if (isNaN(newId)) {
|
|
7
|
+
newId = 0;
|
|
8
|
+
}
|
|
9
|
+
const newTag = {
|
|
10
|
+
id: newId,
|
|
11
|
+
x: boundingBox.xCenterPercentage,
|
|
12
|
+
y: boundingBox.yCenterPercentage,
|
|
13
|
+
width: boundingBox.widthPercentage,
|
|
14
|
+
height: boundingBox.heightPercentage,
|
|
15
|
+
inserted_at: new Date().toISOString(),
|
|
16
|
+
conf: 1,
|
|
17
|
+
observation_type: "manual",
|
|
18
|
+
class_name: newClassName,
|
|
19
|
+
event_id: event_id,
|
|
20
|
+
};
|
|
21
|
+
return newTag;
|
|
22
|
+
}
|
|
23
|
+
export function convertTagToBoundingBox(tag, source) {
|
|
24
|
+
const newBoundingBox = {
|
|
25
|
+
xCenterPercentage: tag.x,
|
|
26
|
+
yCenterPercentage: tag.y,
|
|
27
|
+
widthPercentage: tag.width,
|
|
28
|
+
heightPercentage: tag.height,
|
|
29
|
+
label: tag.class_name,
|
|
30
|
+
id: tag.id ? tag.id.toString() : "0",
|
|
31
|
+
left: 0,
|
|
32
|
+
top: 0,
|
|
33
|
+
width: 0,
|
|
34
|
+
height: 0,
|
|
35
|
+
anchorPoint: { x: 0, y: 0 },
|
|
36
|
+
status: SelectionStatus.ARCHIVED,
|
|
37
|
+
source: source,
|
|
38
|
+
};
|
|
39
|
+
return newBoundingBox;
|
|
40
|
+
}
|
|
41
|
+
export function formatBoundingBoxLabel(label) {
|
|
42
|
+
return label;
|
|
43
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { createClient } from "@supabase/supabase-js";
|
|
2
|
+
export function createClientWithApiKey(user_api_key) {
|
|
3
|
+
const supabase_url = process.env.NEXT_PUBLIC_SUPABASE_URL;
|
|
4
|
+
const supabase_anon_key = process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY;
|
|
5
|
+
if (!supabase_url || !supabase_anon_key) {
|
|
6
|
+
return null;
|
|
7
|
+
}
|
|
8
|
+
// EXCHANGE API KEY FOR JWT
|
|
9
|
+
const supabase_anon = createClient(supabase_url, supabase_anon_key, {
|
|
10
|
+
global: {
|
|
11
|
+
headers: {
|
|
12
|
+
api_key: `${user_api_key}`,
|
|
13
|
+
},
|
|
14
|
+
},
|
|
15
|
+
auth: {
|
|
16
|
+
persistSession: false,
|
|
17
|
+
detectSessionInUrl: false,
|
|
18
|
+
autoRefreshToken: false,
|
|
19
|
+
},
|
|
20
|
+
});
|
|
21
|
+
return supabase_anon;
|
|
22
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { IDevice } from "../types/db";
|
|
2
|
+
import { IWebResponseCompatible } from "../types/requests";
|
|
3
|
+
import { SupabaseClient } from "@supabase/supabase-js";
|
|
4
|
+
export declare function get_devices_by_herd(herd_id: number, client: SupabaseClient): Promise<IWebResponseCompatible<IDevice[]>>;
|
|
5
|
+
export declare function get_device_by_id(device_id: number, client?: SupabaseClient): Promise<IWebResponseCompatible<IDevice | null>>;
|
|
6
|
+
export declare function serverUpdateDevice(updatedDevice: IDevice): Promise<IWebResponseCompatible<IDevice | null>>;
|
|
7
|
+
export declare function serverCreateDevice(newDevice: any): Promise<IWebResponseCompatible<IDevice | null>>;
|
|
8
|
+
export declare function serverDeleteDeviceById(device_id: number): Promise<IWebResponseCompatible<IDevice | null>>;
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
"use server";
|
|
2
|
+
import { newServerClient } from "../supabase/server";
|
|
3
|
+
import { IWebResponse } from "../types/requests";
|
|
4
|
+
export async function get_devices_by_herd(herd_id, client) {
|
|
5
|
+
// call get_devices_for_herd with rpc
|
|
6
|
+
const { data, error } = await client.rpc("get_devices_for_herd", {
|
|
7
|
+
herd_id_caller: herd_id,
|
|
8
|
+
});
|
|
9
|
+
if (!data) {
|
|
10
|
+
return IWebResponse.error("No devices found").to_compatible();
|
|
11
|
+
}
|
|
12
|
+
else {
|
|
13
|
+
let response = IWebResponse.success(data);
|
|
14
|
+
return response.to_compatible();
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
export async function get_device_by_id(device_id, client) {
|
|
18
|
+
if (!client) {
|
|
19
|
+
client = await newServerClient();
|
|
20
|
+
}
|
|
21
|
+
const { data, error } = await client.rpc("get_device_by_id", {
|
|
22
|
+
device_id_caller: device_id,
|
|
23
|
+
});
|
|
24
|
+
if (!data) {
|
|
25
|
+
return IWebResponse.error("No device found").to_compatible();
|
|
26
|
+
}
|
|
27
|
+
else {
|
|
28
|
+
let response = IWebResponse.success(data);
|
|
29
|
+
return response.to_compatible();
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
export async function serverUpdateDevice(updatedDevice) {
|
|
33
|
+
// delete api keys, latitide, and longitude
|
|
34
|
+
const device_formatted = { ...updatedDevice };
|
|
35
|
+
delete device_formatted.api_keys_scout;
|
|
36
|
+
const device_latitude = device_formatted.latitude;
|
|
37
|
+
const device_longitude = device_formatted.longitude;
|
|
38
|
+
delete device_formatted.latitude;
|
|
39
|
+
delete device_formatted.longitude;
|
|
40
|
+
delete device_formatted.recent_events;
|
|
41
|
+
const supabase = await newServerClient();
|
|
42
|
+
const { data, error } = await supabase
|
|
43
|
+
.from("devices")
|
|
44
|
+
.update(device_formatted)
|
|
45
|
+
.match({ id: device_formatted.id })
|
|
46
|
+
.select("*");
|
|
47
|
+
if (error) {
|
|
48
|
+
return IWebResponse.error(error.message).to_compatible();
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
const updatedDevice = {
|
|
52
|
+
...data[0],
|
|
53
|
+
latitude: device_latitude,
|
|
54
|
+
longitude: device_longitude,
|
|
55
|
+
};
|
|
56
|
+
return IWebResponse.success(updatedDevice).to_compatible();
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
export async function serverCreateDevice(newDevice) {
|
|
60
|
+
const supabase = await newServerClient();
|
|
61
|
+
const user = await supabase.auth.getUser();
|
|
62
|
+
const userId = user?.data?.user?.id;
|
|
63
|
+
newDevice.created_by = userId;
|
|
64
|
+
// strip id field from herd object
|
|
65
|
+
const { data, error } = await supabase
|
|
66
|
+
.from("devices")
|
|
67
|
+
.insert([newDevice])
|
|
68
|
+
.select("*");
|
|
69
|
+
if (error) {
|
|
70
|
+
// TODO: ALLOW PROPERTY INSTANTION OF CPMPATIBLE WEB RESPONSE
|
|
71
|
+
return IWebResponse.error(error.message).to_compatible();
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
const newDevice = { ...data[0], latitude: 0, longitude: 0 };
|
|
75
|
+
return IWebResponse.success(newDevice).to_compatible();
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
export async function serverDeleteDeviceById(device_id) {
|
|
79
|
+
const supabase = await newServerClient();
|
|
80
|
+
const { data, error } = await supabase
|
|
81
|
+
.from("devices")
|
|
82
|
+
.delete()
|
|
83
|
+
.match({ id: device_id })
|
|
84
|
+
.select("*");
|
|
85
|
+
if (error) {
|
|
86
|
+
return IWebResponse.error(error.message).to_compatible();
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
89
|
+
const deletedDevice = { ...data[0], latitude: 0, longitude: 0 };
|
|
90
|
+
return IWebResponse.success(deletedDevice).to_compatible();
|
|
91
|
+
}
|
|
92
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ensure email conforms to basic email format x@y.z
|
|
3
|
+
* @param email
|
|
4
|
+
* @returns boolean
|
|
5
|
+
*
|
|
6
|
+
*/
|
|
7
|
+
export function validateEmail(email) {
|
|
8
|
+
// emails should be x@y
|
|
9
|
+
const parts = email.split("@");
|
|
10
|
+
if (parts.length !== 2) {
|
|
11
|
+
return false;
|
|
12
|
+
}
|
|
13
|
+
// x should not be empty
|
|
14
|
+
if (parts[0].length === 0) {
|
|
15
|
+
return false;
|
|
16
|
+
}
|
|
17
|
+
// y should have at least one dot
|
|
18
|
+
if (!parts[1].includes(".")) {
|
|
19
|
+
return false;
|
|
20
|
+
}
|
|
21
|
+
return true;
|
|
22
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { IEvent } from "../types/db";
|
|
2
|
+
import { IWebResponseCompatible } from "../types/requests";
|
|
3
|
+
export declare function server_get_events_by_herd(herd_id: number): Promise<IWebResponseCompatible<IEvent[]>>;
|
|
4
|
+
export declare function server_get_more_events_by_herd(herd_id: number, offset: number, page_count?: number): Promise<IWebResponseCompatible<IEvent[]>>;
|
|
5
|
+
export declare function server_get_total_events_by_herd(herd_id: number): Promise<IWebResponseCompatible<number>>;
|
|
6
|
+
export declare function server_create_event(newEvent: any): Promise<IWebResponseCompatible<boolean>>;
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
"use server";
|
|
2
|
+
import { newServerClient } from "../supabase/server";
|
|
3
|
+
import { EnumWebResponse, IWebResponse, } from "../types/requests";
|
|
4
|
+
export async function server_get_events_by_herd(herd_id) {
|
|
5
|
+
const supabase = await newServerClient();
|
|
6
|
+
// fetch events and include devices
|
|
7
|
+
// sort by timestamp
|
|
8
|
+
const { data } = await supabase
|
|
9
|
+
.from("events")
|
|
10
|
+
.select(`
|
|
11
|
+
*,
|
|
12
|
+
devices: devices!inner(*)
|
|
13
|
+
`)
|
|
14
|
+
.eq("devices.herd_id", herd_id)
|
|
15
|
+
.order("timestamp_observation", { ascending: false });
|
|
16
|
+
// TODO: DETERMINE WHEN TO PASS ERROR
|
|
17
|
+
let response = IWebResponse.success(data ? data : []);
|
|
18
|
+
return response.to_compatible();
|
|
19
|
+
}
|
|
20
|
+
export async function server_get_more_events_by_herd(herd_id, offset, page_count = 10) {
|
|
21
|
+
const from = offset * page_count;
|
|
22
|
+
const to = from + page_count - 1;
|
|
23
|
+
const supabase = await newServerClient();
|
|
24
|
+
// fetch events and include devices
|
|
25
|
+
// sort by timestamp
|
|
26
|
+
const { data } = await supabase
|
|
27
|
+
.from("events")
|
|
28
|
+
.select(`
|
|
29
|
+
*,
|
|
30
|
+
devices: devices!inner(*)
|
|
31
|
+
`)
|
|
32
|
+
.eq("devices.herd_id", herd_id)
|
|
33
|
+
.range(from, to)
|
|
34
|
+
.order("timestamp_observation", { ascending: false });
|
|
35
|
+
// TODO: DETERMINE WHEN TO PASS ERROR
|
|
36
|
+
let response = IWebResponse.success(data ? data : []);
|
|
37
|
+
return response.to_compatible();
|
|
38
|
+
}
|
|
39
|
+
// function to get total number of events for a herd
|
|
40
|
+
export async function server_get_total_events_by_herd(herd_id) {
|
|
41
|
+
const supabase = await newServerClient();
|
|
42
|
+
// call public.get_total_events_for_herd(herd_id)
|
|
43
|
+
const { data, error } = await supabase.rpc("get_total_events_for_herd", {
|
|
44
|
+
herd_id_caller: herd_id,
|
|
45
|
+
});
|
|
46
|
+
if (error) {
|
|
47
|
+
return {
|
|
48
|
+
status: EnumWebResponse.ERROR,
|
|
49
|
+
msg: error.message,
|
|
50
|
+
data: 0,
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
return IWebResponse.success(data).to_compatible();
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
export async function server_create_event(newEvent) {
|
|
58
|
+
const supabase = await newServerClient();
|
|
59
|
+
// strip id field from herd object
|
|
60
|
+
const { data, error } = await supabase.from("events").insert([newEvent]);
|
|
61
|
+
if (error) {
|
|
62
|
+
return {
|
|
63
|
+
status: EnumWebResponse.ERROR,
|
|
64
|
+
msg: error.message,
|
|
65
|
+
data: null,
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
return IWebResponse.success(true).to_compatible();
|
|
70
|
+
}
|
|
71
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
declare function convertToSubcurrency(amount: number, factor?: number): number;
|
|
2
|
+
export declare function roundToTwoDecimals(amount: number): number;
|
|
3
|
+
/**
|
|
4
|
+
* This function takes a number and returns a string with commas and a dollar sign
|
|
5
|
+
* @param amount
|
|
6
|
+
* @returns
|
|
7
|
+
*/
|
|
8
|
+
export declare function formatDollarAmountforDisplay(amount: number): string;
|
|
9
|
+
export default convertToSubcurrency;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
function convertToSubcurrency(amount, factor = 100) {
|
|
2
|
+
return Math.round(amount * factor);
|
|
3
|
+
}
|
|
4
|
+
export function roundToTwoDecimals(amount) {
|
|
5
|
+
return Math.round(amount * 100) / 100;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* This function takes a number and returns a string with commas and a dollar sign
|
|
9
|
+
* @param amount
|
|
10
|
+
* @returns
|
|
11
|
+
*/
|
|
12
|
+
export function formatDollarAmountforDisplay(amount) {
|
|
13
|
+
// add commas to the number and prefix with $
|
|
14
|
+
return `$${amount.toLocaleString()}`;
|
|
15
|
+
}
|
|
16
|
+
export default convertToSubcurrency;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export default function get_gps_center(gpsList) {
|
|
2
|
+
let latitude = 0;
|
|
3
|
+
let longitude = 0;
|
|
4
|
+
gpsList.forEach((gps) => {
|
|
5
|
+
latitude += gps.latitude;
|
|
6
|
+
longitude += gps.longitude;
|
|
7
|
+
});
|
|
8
|
+
latitude /= gpsList.length;
|
|
9
|
+
longitude /= gpsList.length;
|
|
10
|
+
return { latitude, longitude };
|
|
11
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { IHerd } from "../types/db";
|
|
2
|
+
import { IWebResponseCompatible } from "../types/requests";
|
|
3
|
+
import { SupabaseClient } from "@supabase/supabase-js";
|
|
4
|
+
import { IHerdModule } from "../types/herd_module";
|
|
5
|
+
export declare function get_herds(client: SupabaseClient): Promise<IWebResponseCompatible<IHerd[]>>;
|
|
6
|
+
export declare function get_herd_by_slug(slug: string): Promise<IWebResponseCompatible<IHerd>>;
|
|
7
|
+
export declare function deleteHerd(herd_id: number): Promise<IWebResponseCompatible<boolean>>;
|
|
8
|
+
export declare function createHerd(newHerd: any): Promise<IWebResponseCompatible<boolean>>;
|
|
9
|
+
export declare function server_load_herd_modules(): Promise<IHerdModule[]>;
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
"use server";
|
|
2
|
+
import { newServerClient } from "../supabase/server";
|
|
3
|
+
import { EnumWebResponse, IWebResponse, } from "../types/requests";
|
|
4
|
+
import { HerdModule } from "../types/herd_module";
|
|
5
|
+
export async function get_herds(client) {
|
|
6
|
+
const { data: herds } = await client.from("herds").select();
|
|
7
|
+
if (!herds) {
|
|
8
|
+
return {
|
|
9
|
+
status: EnumWebResponse.ERROR,
|
|
10
|
+
msg: "No herds found",
|
|
11
|
+
data: null,
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
else {
|
|
15
|
+
let response = IWebResponse.success(herds);
|
|
16
|
+
return response.to_compatible();
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
export async function get_herd_by_slug(slug) {
|
|
20
|
+
const supabase = await newServerClient();
|
|
21
|
+
const { data: herds } = await supabase
|
|
22
|
+
.from("herds")
|
|
23
|
+
.select()
|
|
24
|
+
.eq("slug", slug)
|
|
25
|
+
.limit(1);
|
|
26
|
+
if (!herds) {
|
|
27
|
+
return {
|
|
28
|
+
status: EnumWebResponse.ERROR,
|
|
29
|
+
msg: "No herds found",
|
|
30
|
+
data: null,
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
return IWebResponse.success(herds[0]);
|
|
34
|
+
}
|
|
35
|
+
export async function deleteHerd(herd_id) {
|
|
36
|
+
const supabase = await newServerClient();
|
|
37
|
+
const { error } = await supabase.from("herds").delete().match({ id: 20 });
|
|
38
|
+
if (error) {
|
|
39
|
+
return {
|
|
40
|
+
status: EnumWebResponse.ERROR,
|
|
41
|
+
msg: error.message,
|
|
42
|
+
data: null,
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
return IWebResponse.success(true).to_compatible();
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
export async function createHerd(newHerd) {
|
|
50
|
+
const supabase = await newServerClient();
|
|
51
|
+
const user = await supabase.auth.getUser();
|
|
52
|
+
const userId = user?.data?.user?.id;
|
|
53
|
+
newHerd.created_by = userId;
|
|
54
|
+
// strip id field from herd object
|
|
55
|
+
const { data, error } = await supabase.from("herds").insert([newHerd]);
|
|
56
|
+
if (error) {
|
|
57
|
+
return {
|
|
58
|
+
status: EnumWebResponse.ERROR,
|
|
59
|
+
msg: error.message,
|
|
60
|
+
data: null,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
return IWebResponse.success(true).to_compatible();
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
export async function server_load_herd_modules() {
|
|
68
|
+
// load herds
|
|
69
|
+
const client_supabase = await newServerClient();
|
|
70
|
+
let new_herds = await get_herds(client_supabase);
|
|
71
|
+
if (new_herds.status != EnumWebResponse.SUCCESS || !new_herds.data) {
|
|
72
|
+
return [];
|
|
73
|
+
}
|
|
74
|
+
let new_herd_modules = [];
|
|
75
|
+
const herdModulePromises = new_herds.data.map((herd) => HerdModule.from_herd(herd, client_supabase));
|
|
76
|
+
new_herd_modules = await Promise.all(herdModulePromises);
|
|
77
|
+
// now serialize the herd modules
|
|
78
|
+
let serialized_herd_modules = new_herd_modules.map((herd_module) => herd_module.to_serializable());
|
|
79
|
+
return serialized_herd_modules;
|
|
80
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export * from "./auth";
|
|
2
|
+
export * from "./bounding_boxes";
|
|
3
|
+
export * from "./db";
|
|
4
|
+
export * from "./devices";
|
|
5
|
+
export * from "./email";
|
|
6
|
+
export * from "./events";
|
|
7
|
+
export * from "./finance";
|
|
8
|
+
export * from "./gps";
|
|
9
|
+
export * from "./herds";
|
|
10
|
+
export * from "./location";
|
|
11
|
+
export * from "./plans";
|
|
12
|
+
export * from "./tags";
|
|
13
|
+
export * from "./time";
|
|
14
|
+
export * from "./ui";
|
|
15
|
+
export * from "./users";
|
|
16
|
+
export * from "./web";
|
|
17
|
+
export * from "./zones";
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export * from "./auth";
|
|
2
|
+
export * from "./bounding_boxes";
|
|
3
|
+
export * from "./db";
|
|
4
|
+
export * from "./devices";
|
|
5
|
+
export * from "./email";
|
|
6
|
+
export * from "./events";
|
|
7
|
+
export * from "./finance";
|
|
8
|
+
export * from "./gps";
|
|
9
|
+
export * from "./herds";
|
|
10
|
+
export * from "./location";
|
|
11
|
+
export * from "./plans";
|
|
12
|
+
export * from "./tags";
|
|
13
|
+
export * from "./time";
|
|
14
|
+
export * from "./ui";
|
|
15
|
+
export * from "./users";
|
|
16
|
+
export * from "./web";
|
|
17
|
+
export * from "./zones";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function format_coordinates_for_db(lat: number, long: number): string;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { IPlan } from "../types/db";
|
|
2
|
+
import { IWebResponseCompatible } from "../types/requests";
|
|
3
|
+
export declare function server_get_plans_by_herd(herd_id: number): Promise<IWebResponseCompatible<IPlan[]>>;
|
|
4
|
+
export declare function server_create_plans(plans: IPlan[]): Promise<IWebResponseCompatible<IPlan[]>>;
|
|
5
|
+
export declare function server_delete_plans_by_ids(plan_ids: number[]): Promise<IWebResponseCompatible<boolean>>;
|