From 5a92c7dc6916f8e9ba05a5ef40575d2e7c3afd91 Mon Sep 17 00:00:00 2001 From: Felix Erdmann Date: Fri, 3 Nov 2023 16:10:37 +0100 Subject: [PATCH 1/2] feat: create new sensebox --- android/app/capacitor.build.gradle | 1 + android/capacitor.settings.gradle | 3 + ios/App/Podfile | 1 + ios/App/Podfile.lock | 8 +- package.json | 1 + src/components/Device/DeviceMapWrapper.tsx | 2 +- src/components/Device/SettingsDrawer.tsx | 6 +- src/components/Map/MeasurementsGrid.tsx | 317 +++++++++--------- src/components/Wizard/CreateBikeBoxDialog.tsx | 116 +++++++ src/components/Wizard/SelectDevice.tsx | 5 +- src/components/Wizard/WizardDrawer.tsx | 6 +- src/lib/api/openSenseMapClient.ts | 99 ++++++ src/lib/senseBoxSensorIdMatcher.ts | 2 +- yarn.lock | 5 + 14 files changed, 405 insertions(+), 167 deletions(-) create mode 100644 src/components/Wizard/CreateBikeBoxDialog.tsx diff --git a/android/app/capacitor.build.gradle b/android/app/capacitor.build.gradle index b7c3a77..fb3e537 100644 --- a/android/app/capacitor.build.gradle +++ b/android/app/capacitor.build.gradle @@ -11,6 +11,7 @@ apply from: "../capacitor-cordova-android-plugins/cordova.variables.gradle" dependencies { implementation project(':capacitor-community-bluetooth-le') implementation project(':capacitor-app') + implementation project(':capacitor-geolocation') implementation project(':capacitor-preferences') implementation project(':felixerdy-background-geolocation') diff --git a/android/capacitor.settings.gradle b/android/capacitor.settings.gradle index 0c3926f..a2a503c 100644 --- a/android/capacitor.settings.gradle +++ b/android/capacitor.settings.gradle @@ -8,6 +8,9 @@ project(':capacitor-community-bluetooth-le').projectDir = new File('../node_modu include ':capacitor-app' project(':capacitor-app').projectDir = new File('../node_modules/@capacitor/app/android') +include ':capacitor-geolocation' +project(':capacitor-geolocation').projectDir = new File('../node_modules/@capacitor/geolocation/android') + include ':capacitor-preferences' project(':capacitor-preferences').projectDir = new File('../node_modules/@capacitor/preferences/android') diff --git a/ios/App/Podfile b/ios/App/Podfile index d221c7e..026731e 100644 --- a/ios/App/Podfile +++ b/ios/App/Podfile @@ -13,6 +13,7 @@ def capacitor_pods pod 'CapacitorCordova', :path => '../../node_modules/@capacitor/ios' pod 'CapacitorCommunityBluetoothLe', :path => '../../node_modules/@capacitor-community/bluetooth-le' pod 'CapacitorApp', :path => '../../node_modules/@capacitor/app' + pod 'CapacitorGeolocation', :path => '../../node_modules/@capacitor/geolocation' pod 'CapacitorPreferences', :path => '../../node_modules/@capacitor/preferences' pod 'FelixerdyBackgroundGeolocation', :path => '../../node_modules/@felixerdy/background-geolocation' end diff --git a/ios/App/Podfile.lock b/ios/App/Podfile.lock index 38ec475..abbef1b 100644 --- a/ios/App/Podfile.lock +++ b/ios/App/Podfile.lock @@ -6,6 +6,8 @@ PODS: - CapacitorCommunityBluetoothLe (3.0.2): - Capacitor - CapacitorCordova (5.5.0) + - CapacitorGeolocation (5.0.6): + - Capacitor - CapacitorPreferences (5.0.6): - Capacitor - FelixerdyBackgroundGeolocation (0.0.1): @@ -16,6 +18,7 @@ DEPENDENCIES: - "CapacitorApp (from `../../node_modules/@capacitor/app`)" - "CapacitorCommunityBluetoothLe (from `../../node_modules/@capacitor-community/bluetooth-le`)" - "CapacitorCordova (from `../../node_modules/@capacitor/ios`)" + - "CapacitorGeolocation (from `../../node_modules/@capacitor/geolocation`)" - "CapacitorPreferences (from `../../node_modules/@capacitor/preferences`)" - "FelixerdyBackgroundGeolocation (from `../../node_modules/@felixerdy/background-geolocation`)" @@ -28,6 +31,8 @@ EXTERNAL SOURCES: :path: "../../node_modules/@capacitor-community/bluetooth-le" CapacitorCordova: :path: "../../node_modules/@capacitor/ios" + CapacitorGeolocation: + :path: "../../node_modules/@capacitor/geolocation" CapacitorPreferences: :path: "../../node_modules/@capacitor/preferences" FelixerdyBackgroundGeolocation: @@ -38,9 +43,10 @@ SPEC CHECKSUMS: CapacitorApp: 024e1b1bea5f883d79f6330d309bc441c88ad04a CapacitorCommunityBluetoothLe: 83b0de348b2ec461e0f9fa0e48c9e79c8378ddb0 CapacitorCordova: 3d3908a3d208a11a75f9df3b18c4405c4de76e1d + CapacitorGeolocation: 7be5f77abc205c0efe319fff8587a7183e7b0240 CapacitorPreferences: f03954bcb0ff09c792909e46bff88e3183c16b10 FelixerdyBackgroundGeolocation: 1e6a92a836b58a62b20e0eb6b78bff201265deb8 -PODFILE CHECKSUM: f2e3708e22e094f8a9b03f2e5f0e3688df829e58 +PODFILE CHECKSUM: cd5890a32fa9a1bf24ccec4e54b55f6d47a564c8 COCOAPODS: 1.14.0 diff --git a/package.json b/package.json index 4494755..cba3c89 100644 --- a/package.json +++ b/package.json @@ -15,6 +15,7 @@ "@capacitor/android": "^5.3.0", "@capacitor/app": "^5.0.6", "@capacitor/core": "^5.3.0", + "@capacitor/geolocation": "^5.0.6", "@capacitor/ios": "^5.3.0", "@capacitor/preferences": "^5.0.6", "@felixerdy/background-geolocation": "1.2.15", diff --git a/src/components/Device/DeviceMapWrapper.tsx b/src/components/Device/DeviceMapWrapper.tsx index cfcbed9..7033cfb 100644 --- a/src/components/Device/DeviceMapWrapper.tsx +++ b/src/components/Device/DeviceMapWrapper.tsx @@ -25,7 +25,7 @@ export default function DeviceMapWrapper() { return (
-
+
diff --git a/src/components/Device/SettingsDrawer.tsx b/src/components/Device/SettingsDrawer.tsx index aa32d8c..a57ea99 100644 --- a/src/components/Device/SettingsDrawer.tsx +++ b/src/components/Device/SettingsDrawer.tsx @@ -87,8 +87,8 @@ export default function SettingsDrawer() { - - + +
@@ -168,7 +168,7 @@ export default function SettingsDrawer() { function SettingsDrawerFooter() { return ( -
+
-
-
-
- ({ x: v.timestamp, y: v.temperature })), - index: 'x', - categories: ['y'], - }} - /> - ({ x: v.timestamp, y: v.gps_spd })), - index: 'x', - categories: ['y'], - }} - /> - ({ x: v.timestamp, y: v.humidity })), - index: 'x', - categories: ['y'], - }} - /> -
-
- e.pm1) - .map(v => ({ - x: v.timestamp, - pm1: v.pm1, - pm2_5: v.pm2_5, - pm4: v.pm4, - pm10: v.pm10, - })), - index: 'x', - categories: ['pm1', 'pm2_5', 'pm4', 'pm10'], - }} - /> - ({ x: v.timestamp, y: v.distance_l })), - index: 'x', - categories: ['y'], - }} - /> - - ({ +
+
+
+ ({ x: v.timestamp, y: v.temperature })), + index: 'x', + categories: ['y'], + }} + /> + ({ x: v.timestamp, y: v.gps_spd })), + index: 'x', + categories: ['y'], + }} + /> + ({ x: v.timestamp, y: v.humidity })), + index: 'x', + categories: ['y'], + }} + /> +
+
+ e.pm1) + .map(v => ({ x: v.timestamp, - acceleration_x: v.acceleration_x, - acceleration_y: v.acceleration_y, - acceleration_z: v.acceleration_z, + pm1: v.pm1, + pm2_5: v.pm2_5, + pm4: v.pm4, + pm10: v.pm10, })), - index: 'x', - categories: [ - 'acceleration_x', - 'acceleration_y', - 'acceleration_z', - ], - colors: ['indigo', 'cyan', 'amber'], - }} - /> -
- {(!selectedBox || values.length === 0) && ( -
- {!selectedBox && ( -

- Bitte verknüpfen Sie eine senseBox über den Setup-Button. -

- )} - {selectedBox && ( -

- Sie können sich nun mit der senseBox verbinden und die - Messwerte aufzeichnen -

- )} -
- )} + index: 'x', + categories: ['pm1', 'pm2_5', 'pm4', 'pm10'], + colors: ['indigo', 'cyan', 'amber', 'emerald'], + }} + /> + ({ x: v.timestamp, y: v.distance_l })), + index: 'x', + categories: ['y'], + }} + /> + + ({ + x: v.timestamp, + acceleration_x: v.acceleration_x, + acceleration_y: v.acceleration_y, + acceleration_z: v.acceleration_z, + })), + index: 'x', + categories: [ + 'acceleration_x', + 'acceleration_y', + 'acceleration_z', + ], + colors: ['indigo', 'cyan', 'amber'], + }} + />
-
- {!isConnected ? ( -
+
+ {!isConnected ? ( + + ) : ( + + )} + {!selectedBox ? ( + + + Setup + + } + /> + ) : isConnected ? ( + !isRecording ? ( + ) : ( - - )} - {!selectedBox ? ( - - - Setup - - } - /> - ) : isConnected ? ( - !isRecording ? ( + <> - ) : ( - <> - - - ) - ) : ( - <> - )} -
+ + ) + ) : ( + <> + )}
) diff --git a/src/components/Wizard/CreateBikeBoxDialog.tsx b/src/components/Wizard/CreateBikeBoxDialog.tsx new file mode 100644 index 0000000..57d083f --- /dev/null +++ b/src/components/Wizard/CreateBikeBoxDialog.tsx @@ -0,0 +1,116 @@ +'use client' + +import { + Dialog, + DialogContent, + DialogDescription, + DialogHeader, + DialogTitle, + DialogTrigger, +} from '@/components/ui/dialog' +import { Button } from '../ui/button' +import { Loader2, Plus } from 'lucide-react' +import { useState } from 'react' +import { + Form, + FormControl, + FormDescription, + FormField, + FormItem, + FormLabel, + FormMessage, +} from '../ui/form' +import { useForm } from 'react-hook-form' +import { Input } from '../ui/input' + +import * as z from 'zod' +import { zodResolver } from '@hookform/resolvers/zod' + +const formSchema = z.object({ + name: z.string().min(2).max(50), +}) + +import { createSenseBoxBike } from '@/lib/api/openSenseMapClient' +import { toast } from '../ui/use-toast' +import useOpenSenseMapAuth from '@/lib/useOpenSenseMapAuth' +import { useAuthStore } from '@/lib/store/useAuthStore' +import { Geolocation } from '@capacitor/geolocation' + +export default function CreateBikeBoxDialog() { + const [open, setOpen] = useState(false) + const [loading, setLoading] = useState(false) + + const { refreshBoxes } = useOpenSenseMapAuth() + const setSelectedBox = useAuthStore(state => state.setSelectedBox) + + const form = useForm>({ + resolver: zodResolver(formSchema), + defaultValues: { + name: '', + }, + }) + + async function onSubmit(values: z.infer) { + try { + setLoading(true) + const coordinates = await Geolocation.getCurrentPosition() + + const newBox = await createSenseBoxBike( + values.name, + coordinates.coords.latitude, + coordinates.coords.longitude, + ) + await refreshBoxes() + setSelectedBox(newBox) + form.reset() + setOpen(false) + } catch (error) { + toast({ + title: 'Fehler', + description: 'Fehler beim Erstellen der senseBox:bike', + }) + } finally { + setLoading(false) + } + } + + return ( + + + + + + + Neue senseBox:bike +
+ + ( + + Name + + + + + Der Name der neuen senseBox:bike wird auf der openSenseMap + angezeigt + + + + )} + /> + + + +
+
+
+ ) +} diff --git a/src/components/Wizard/SelectDevice.tsx b/src/components/Wizard/SelectDevice.tsx index 3c3d27b..e80a7cf 100644 --- a/src/components/Wizard/SelectDevice.tsx +++ b/src/components/Wizard/SelectDevice.tsx @@ -2,11 +2,11 @@ import { useAuthStore } from '@/lib/store/useAuthStore' import { ScrollArea } from '../ui/scroll-area' import { Button } from '../ui/button' import { cx } from 'class-variance-authority' -import { useEffect, useState } from 'react' import { useSwiper } from 'swiper/react' import WizardSlide from './WizardSlide' import { Separator } from '../ui/separator' -import { CheckCircle, Circle, RefreshCcw } from 'lucide-react' +import { CheckCircle, Circle } from 'lucide-react' +import CreateBikeBoxDialog from './CreateBikeBoxDialog' export default function SelectDevice() { const { boxes } = useAuthStore(state => state.boxes) @@ -17,6 +17,7 @@ export default function SelectDevice() { return (

Box auswählen

+ {boxes && boxes.map(box => ( diff --git a/src/components/Wizard/WizardDrawer.tsx b/src/components/Wizard/WizardDrawer.tsx index 5a3a81f..10ccfac 100644 --- a/src/components/Wizard/WizardDrawer.tsx +++ b/src/components/Wizard/WizardDrawer.tsx @@ -53,8 +53,8 @@ export default function WizardDrawer({ )} - - + +