feat: Standort hinzugefügt

This commit is contained in:
Ismail Ali
2025-07-15 21:41:23 +02:00
parent 96b635bccb
commit 007dedb09a
3 changed files with 323 additions and 4 deletions

View File

@@ -1,5 +1,6 @@
import AsyncStorage from "@react-native-async-storage/async-storage";
import * as LocalAuthentication from "expo-local-authentication";
import * as Location from "expo-location";
import { useRouter } from "expo-router";
import * as SQLite from "expo-sqlite";
import React, { useEffect, useState } from "react";
@@ -22,6 +23,10 @@ interface User {
email: string;
firstName: string;
lastName: string;
residence: string;
workplace: string;
latitude: string;
longitude: string;
createdAt: string;
}
@@ -37,6 +42,10 @@ export default function AuthScreen() {
const [password, setPassword] = useState("");
const [firstName, setFirstName] = useState("");
const [lastName, setLastName] = useState("");
const [residence, setResidence] = useState("");
const [workplace, setWorkplace] = useState("");
const [latitude, setLatitude] = useState<string | null>(null);
const [longitude, setLongitude] = useState<string | null>(null);
const [biometricSupported, setBiometricSupported] = useState(false);
const [showCalendar, setShowCalendar] = useState(false);
@@ -61,6 +70,10 @@ export default function AuthScreen() {
firstName TEXT NOT NULL,
lastName TEXT NOT NULL,
password TEXT NOT NULL,
residence TEXT,
workplace TEXT,
latitude TEXT,
longitude TEXT,
createdAt TEXT NOT NULL
)
`);
@@ -85,7 +98,14 @@ export default function AuthScreen() {
};
const handleRegister = async () => {
if (!email || !password || !firstName || !lastName) {
if (
!email ||
!password ||
!firstName ||
!lastName ||
!residence ||
!workplace
) {
Alert.alert("Fehler", "Bitte füllen Sie alle Felder aus.");
return;
}
@@ -105,8 +125,18 @@ export default function AuthScreen() {
const createdAt = new Date().toISOString();
const result = await db.runAsync(
"INSERT INTO users (email, firstName, lastName, password, createdAt) VALUES (?, ?, ?, ?, ?)",
[email, firstName, lastName, password, createdAt]
"INSERT INTO users (email, firstName, lastName, password, residence, workplace, latitude, longitude, createdAt) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)",
[
email,
firstName,
lastName,
password,
residence,
workplace,
latitude ?? "",
longitude ?? "",
createdAt,
]
);
const newUser: User = {
@@ -114,6 +144,10 @@ export default function AuthScreen() {
email,
firstName,
lastName,
residence,
workplace,
latitude: latitude ?? "",
longitude: longitude ?? "",
createdAt,
};
@@ -162,6 +196,10 @@ export default function AuthScreen() {
email: result.email,
firstName: result.firstName,
lastName: result.lastName,
residence: result.residence,
workplace: result.workplace,
latitude: result.latitude,
longitude: result.longitude,
createdAt: result.createdAt,
};
@@ -202,6 +240,10 @@ export default function AuthScreen() {
email: user.email,
firstName: user.firstName,
lastName: user.lastName,
residence: user.residence,
workplace: user.workplace,
latitude: user.latitude,
longitude: user.longitude,
createdAt: user.createdAt,
};
@@ -227,11 +269,37 @@ export default function AuthScreen() {
setPassword("");
setFirstName("");
setLastName("");
setResidence("");
setWorkplace("");
setLatitude(null);
setLongitude(null);
} catch (error) {
Alert.alert("Fehler", "Abmeldung fehlgeschlagen.");
}
};
const handleUseLocation = async () => {
try {
const { status } = await Location.requestForegroundPermissionsAsync();
if (status !== "granted") {
Alert.alert("Fehler", "Standortberechtigung nicht erteilt.");
return;
}
const loc = await Location.getCurrentPositionAsync({});
setLatitude(loc.coords.latitude.toString());
setLongitude(loc.coords.longitude.toString());
const addr = await Location.reverseGeocodeAsync({
latitude: loc.coords.latitude,
longitude: loc.coords.longitude,
});
if (addr && addr.length > 0) {
setResidence(addr[0].city || addr[0].region || "");
}
} catch (e) {
Alert.alert("Fehler", "Standort konnte nicht ermittelt werden.");
}
};
if (loading) {
return (
<SafeAreaView style={styles.container}>
@@ -305,6 +373,30 @@ export default function AuthScreen() {
onChangeText={setLastName}
autoCapitalize="words"
/>
<TextInput
style={styles.input}
placeholder="Wohnort"
value={residence}
onChangeText={setResidence}
/>
<TextInput
style={styles.input}
placeholder="Arbeitsplatz / Uni / Schule"
value={workplace}
onChangeText={setWorkplace}
/>
<TouchableOpacity
style={[
styles.submitButton,
{ backgroundColor: "#34C759", marginBottom: 10 },
]}
onPress={handleUseLocation}
>
<Text style={styles.submitButtonText}>
Aktuellen Standort verwenden
</Text>
</TouchableOpacity>
</>
)}

224
package-lock.json generated
View File

@@ -11,6 +11,7 @@
"@expo/vector-icons": "^14.1.0",
"@react-native-async-storage/async-storage": "2.1.2",
"@react-native-picker/picker": "2.11.1",
"@react-native-voice/voice": "^3.2.4",
"@react-navigation/bottom-tabs": "^7.3.10",
"@react-navigation/elements": "^2.3.8",
"@react-navigation/native": "^7.1.6",
@@ -24,6 +25,7 @@
"expo-image": "~2.3.2",
"expo-linking": "~7.1.7",
"expo-local-authentication": "~16.0.5",
"expo-location": "~18.1.6",
"expo-router": "~5.1.3",
"expo-splash-screen": "~0.30.10",
"expo-sqlite": "~15.2.14",
@@ -38,6 +40,7 @@
"react-native-reanimated": "~3.17.4",
"react-native-safe-area-context": "5.4.0",
"react-native-screens": "~4.11.1",
"react-native-voice": "^0.3.0",
"react-native-web": "~0.20.0",
"react-native-webview": "13.13.5"
},
@@ -3529,6 +3532,153 @@
"react-native": "*"
}
},
"node_modules/@react-native-voice/voice": {
"version": "3.2.4",
"resolved": "https://registry.npmjs.org/@react-native-voice/voice/-/voice-3.2.4.tgz",
"integrity": "sha512-4i3IpB/W5VxCI7BQZO5Nr2VB0ecx0SLvkln2Gy29cAQKqgBl+1ZsCwUBChwHlPbmja6vA3tp/+2ADQGwB1OhHg==",
"dependencies": {
"@expo/config-plugins": "^2.0.0",
"invariant": "^2.2.4"
},
"peerDependencies": {
"react-native": ">= 0.60.2"
}
},
"node_modules/@react-native-voice/voice/node_modules/@babel/code-frame": {
"version": "7.10.4",
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz",
"integrity": "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==",
"dependencies": {
"@babel/highlight": "^7.10.4"
}
},
"node_modules/@react-native-voice/voice/node_modules/@expo/config-plugins": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/@expo/config-plugins/-/config-plugins-2.0.4.tgz",
"integrity": "sha512-JGt/X2tFr7H8KBQrKfbGo9hmCubQraMxq5sj3bqDdKmDOLcE1a/EDCP9g0U4GHsa425J8VDIkQUHYz3h3ndEXQ==",
"dependencies": {
"@expo/config-types": "^41.0.0",
"@expo/json-file": "8.2.30",
"@expo/plist": "0.0.13",
"debug": "^4.3.1",
"find-up": "~5.0.0",
"fs-extra": "9.0.0",
"getenv": "^1.0.0",
"glob": "7.1.6",
"resolve-from": "^5.0.0",
"slash": "^3.0.0",
"xcode": "^3.0.1",
"xml2js": "^0.4.23"
}
},
"node_modules/@react-native-voice/voice/node_modules/@expo/config-types": {
"version": "41.0.0",
"resolved": "https://registry.npmjs.org/@expo/config-types/-/config-types-41.0.0.tgz",
"integrity": "sha512-Ax0pHuY5OQaSrzplOkT9DdpdmNzaVDnq9VySb4Ujq7UJ4U4jriLy8u93W98zunOXpcu0iiKubPsqD6lCiq0pig=="
},
"node_modules/@react-native-voice/voice/node_modules/@expo/json-file": {
"version": "8.2.30",
"resolved": "https://registry.npmjs.org/@expo/json-file/-/json-file-8.2.30.tgz",
"integrity": "sha512-vrgGyPEXBoFI5NY70IegusCSoSVIFV3T3ry4tjJg1MFQKTUlR7E0r+8g8XR6qC705rc2PawaZQjqXMAVtV6s2A==",
"dependencies": {
"@babel/code-frame": "~7.10.4",
"fs-extra": "9.0.0",
"json5": "^1.0.1",
"write-file-atomic": "^2.3.0"
}
},
"node_modules/@react-native-voice/voice/node_modules/@expo/plist": {
"version": "0.0.13",
"resolved": "https://registry.npmjs.org/@expo/plist/-/plist-0.0.13.tgz",
"integrity": "sha512-zGPSq9OrCn7lWvwLLHLpHUUq2E40KptUFXn53xyZXPViI0k9lbApcR9KlonQZ95C+ELsf0BQ3gRficwK92Ivcw==",
"dependencies": {
"base64-js": "^1.2.3",
"xmlbuilder": "^14.0.0",
"xmldom": "~0.5.0"
}
},
"node_modules/@react-native-voice/voice/node_modules/getenv": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/getenv/-/getenv-1.0.0.tgz",
"integrity": "sha512-7yetJWqbS9sbn0vIfliPsFgoXMKn/YMF+Wuiog97x+urnSRRRZ7xB+uVkwGKzRgq9CDFfMQnE9ruL5DHv9c6Xg==",
"engines": {
"node": ">=6"
}
},
"node_modules/@react-native-voice/voice/node_modules/glob": {
"version": "7.1.6",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
"integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
"deprecated": "Glob versions prior to v9 are no longer supported",
"dependencies": {
"fs.realpath": "^1.0.0",
"inflight": "^1.0.4",
"inherits": "2",
"minimatch": "^3.0.4",
"once": "^1.3.0",
"path-is-absolute": "^1.0.0"
},
"engines": {
"node": "*"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/@react-native-voice/voice/node_modules/json5": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz",
"integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==",
"dependencies": {
"minimist": "^1.2.0"
},
"bin": {
"json5": "lib/cli.js"
}
},
"node_modules/@react-native-voice/voice/node_modules/signal-exit": {
"version": "3.0.7",
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz",
"integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ=="
},
"node_modules/@react-native-voice/voice/node_modules/write-file-atomic": {
"version": "2.4.3",
"resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.3.tgz",
"integrity": "sha512-GaETH5wwsX+GcnzhPgKcKjJ6M2Cq3/iZp1WyY/X1CSqrW+jVNM9Y7D8EC2sM4ZG/V8wZlSniJnCKWPmBYAucRQ==",
"dependencies": {
"graceful-fs": "^4.1.11",
"imurmurhash": "^0.1.4",
"signal-exit": "^3.0.2"
}
},
"node_modules/@react-native-voice/voice/node_modules/xml2js": {
"version": "0.4.23",
"resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz",
"integrity": "sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==",
"dependencies": {
"sax": ">=0.6.0",
"xmlbuilder": "~11.0.0"
},
"engines": {
"node": ">=4.0.0"
}
},
"node_modules/@react-native-voice/voice/node_modules/xml2js/node_modules/xmlbuilder": {
"version": "11.0.1",
"resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz",
"integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==",
"engines": {
"node": ">=4.0"
}
},
"node_modules/@react-native-voice/voice/node_modules/xmlbuilder": {
"version": "14.0.0",
"resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-14.0.0.tgz",
"integrity": "sha512-ts+B2rSe4fIckR6iquDjsKbQFK2NlUk6iG5nf14mDEyldgoc2nEKZ3jZWMPTxGQwVgToSjt6VGIho1H8/fNFTg==",
"engines": {
"node": ">=8.0"
}
},
"node_modules/@react-native/assets-registry": {
"version": "0.79.5",
"resolved": "https://registry.npmjs.org/@react-native/assets-registry/-/assets-registry-0.79.5.tgz",
@@ -5237,6 +5387,14 @@
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
"dev": true
},
"node_modules/at-least-node": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz",
"integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==",
"engines": {
"node": ">= 4.0.0"
}
},
"node_modules/available-typed-arrays": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz",
@@ -7891,6 +8049,14 @@
"expo": "*"
}
},
"node_modules/expo-location": {
"version": "18.1.6",
"resolved": "https://registry.npmjs.org/expo-location/-/expo-location-18.1.6.tgz",
"integrity": "sha512-l5dQQ2FYkrBgNzaZN1BvSmdhhcztFOUucu2kEfDBMV4wSIuTIt/CKsho+F3RnAiWgvui1wb1WTTf80E8zq48hA==",
"peerDependencies": {
"expo": "*"
}
},
"node_modules/expo-module-scripts": {
"version": "4.1.9",
"resolved": "https://registry.npmjs.org/expo-module-scripts/-/expo-module-scripts-4.1.9.tgz",
@@ -8436,6 +8602,28 @@
"node": ">= 0.6"
}
},
"node_modules/fs-extra": {
"version": "9.0.0",
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.0.0.tgz",
"integrity": "sha512-pmEYSk3vYsG/bF651KPUXZ+hvjpgWYw/Gc7W9NFUe3ZVLczKKWIij3IKpOrQcdw4TILtibFslZ0UmR8Vvzig4g==",
"dependencies": {
"at-least-node": "^1.0.0",
"graceful-fs": "^4.2.0",
"jsonfile": "^6.0.1",
"universalify": "^1.0.0"
},
"engines": {
"node": ">=10"
}
},
"node_modules/fs-extra/node_modules/universalify": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/universalify/-/universalify-1.0.0.tgz",
"integrity": "sha512-rb6X1W158d7pRQBg5gkR8uPaSfiids68LTJQYOtEUhoJUWBdaQHsuT/EUduxXYxcrt4r5PJ4fuHW1MHT6p0qug==",
"engines": {
"node": ">= 10.0.0"
}
},
"node_modules/fs-readdir-recursive": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/fs-readdir-recursive/-/fs-readdir-recursive-1.1.0.tgz",
@@ -10759,6 +10947,25 @@
"node": ">=6"
}
},
"node_modules/jsonfile": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz",
"integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==",
"dependencies": {
"universalify": "^2.0.0"
},
"optionalDependencies": {
"graceful-fs": "^4.1.6"
}
},
"node_modules/jsonfile/node_modules/universalify": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz",
"integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==",
"engines": {
"node": ">= 10.0.0"
}
},
"node_modules/jsx-ast-utils": {
"version": "3.3.5",
"resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz",
@@ -12990,6 +13197,15 @@
"react-native": "*"
}
},
"node_modules/react-native-voice": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/react-native-voice/-/react-native-voice-0.3.0.tgz",
"integrity": "sha512-puSrXCNn1MM03UZkY8q+GW931OqBCEBCiupNK4vD8i49esGqRDDmzv8sRYyEgXj5ScVDKe6lnlKCmJSn5Wo2UA==",
"deprecated": "This module has been renamed to @react-native-community/voice. Updates will no longer be pushed to this package.",
"peerDependencies": {
"react-native": ">=0.40.0"
}
},
"node_modules/react-native-web": {
"version": "0.20.0",
"resolved": "https://registry.npmjs.org/react-native-web/-/react-native-web-0.20.0.tgz",
@@ -15853,6 +16069,14 @@
"integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==",
"dev": true
},
"node_modules/xmldom": {
"version": "0.5.0",
"resolved": "https://registry.npmjs.org/xmldom/-/xmldom-0.5.0.tgz",
"integrity": "sha512-Foaj5FXVzgn7xFzsKeNIde9g6aFBxTPi37iwsno8QvApmtg7KYrr+OPyRHcJF7dud2a5nGRBXK3n0dL62Gf7PA==",
"engines": {
"node": ">=10.0.0"
}
},
"node_modules/y18n": {
"version": "5.0.8",
"resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",

View File

@@ -14,6 +14,7 @@
"@expo/vector-icons": "^14.1.0",
"@react-native-async-storage/async-storage": "2.1.2",
"@react-native-picker/picker": "2.11.1",
"@react-native-voice/voice": "^3.2.4",
"@react-navigation/bottom-tabs": "^7.3.10",
"@react-navigation/elements": "^2.3.8",
"@react-navigation/native": "^7.1.6",
@@ -41,8 +42,10 @@
"react-native-reanimated": "~3.17.4",
"react-native-safe-area-context": "5.4.0",
"react-native-screens": "~4.11.1",
"react-native-voice": "^0.3.0",
"react-native-web": "~0.20.0",
"react-native-webview": "13.13.5"
"react-native-webview": "13.13.5",
"expo-location": "~18.1.6"
},
"devDependencies": {
"@babel/core": "^7.25.2",