diff --git a/app.json b/app.json
index 90cfc82..3136697 100644
--- a/app.json
+++ b/app.json
@@ -52,7 +52,7 @@
"applinks:headpat.place",
"applinks:api.headpat.place"
],
- "buildNumber": "91"
+ "buildNumber": "93"
},
"android": {
"permissions": [
@@ -73,7 +73,7 @@
}
},
"package": "com.headpat.app",
- "versionCode": 64
+ "versionCode": 66
},
"extra": {
"router": {
diff --git a/app/_layout.tsx b/app/_layout.tsx
index f792f84..c64d9fe 100644
--- a/app/_layout.tsx
+++ b/app/_layout.tsx
@@ -58,6 +58,7 @@ import DiscordIcon from '~/components/icons/DiscordIcon'
import EulaModal from '~/components/EulaModal'
import { Muted } from '~/components/ui/typography'
import * as Updates from 'expo-updates'
+import { LocationObject } from 'expo-location'
async function bootstrap() {
const initialNotification = await messaging().getInitialNotification()
@@ -75,37 +76,54 @@ async function bootstrap() {
}
}
-TaskManager.defineTask('background-location-task', async ({ data, error }) => {
- if (error) {
- console.error(error)
- Sentry.captureException(error)
- return BackgroundFetch.BackgroundFetchResult.Failed
- }
-
- // Use the user data from the task
- const userId = await AsyncStorage.getItem('userId')
+TaskManager.defineTask(
+ 'background-location-task',
+ async ({
+ data,
+ error,
+ }: {
+ data: { locations: LocationObject[] }
+ error: any
+ }) => {
+ if (error) {
+ console.error(error)
+ Sentry.captureException(error)
+ return BackgroundFetch.BackgroundFetchResult.Failed
+ }
- if (!userId) {
- return BackgroundFetch.BackgroundFetchResult.Failed
- }
+ // Use the user data from the task
+ const userId = await AsyncStorage.getItem('userId')
+ const preciseLocation = await AsyncStorage.getItem('preciseLocation')
- // Get current location
- const location = await Location.getCurrentPositionAsync()
+ if (!userId) {
+ return Location.stopLocationUpdatesAsync('background-location-task')
+ }
- // Make API calls to update or create location document
- await database
- .updateDocument('hp_db', 'locations', userId, {
- long: location.coords.longitude,
- lat: location.coords.latitude,
+ // Get current location
+ const location = await Location.getCurrentPositionAsync({
+ accuracy:
+ preciseLocation === 'true'
+ ? Location.Accuracy.High
+ : Location.Accuracy.Low,
})
- .catch(async () => {
- await database.createDocument('hp_db', 'locations', userId, {
+
+ // Make API calls to update or create location document
+ await database
+ .updateDocument('hp_db', 'locations', userId, {
long: location.coords.longitude,
lat: location.coords.latitude,
- timeUntilEnd: new Date(Date.now() + 24 * 60 * 60 * 1000).toISOString(),
})
- })
-})
+ .catch(async () => {
+ await database.createDocument('hp_db', 'locations', userId, {
+ long: location.coords.longitude,
+ lat: location.coords.latitude,
+ timeUntilEnd: new Date(
+ Date.now() + 24 * 60 * 60 * 1000
+ ).toISOString(),
+ })
+ })
+ }
+)
const LIGHT_THEME: Theme = {
dark: false,
@@ -323,7 +341,7 @@ function CustomDrawerContent() {
)
}}
- onPress={() => router.navigate('/community/list')}
+ onPress={() => router.navigate('/community')}
/>
diff --git a/app/account/(stacks)/userprofile/(tabs)/avatarAdd/index.tsx b/app/account/(stacks)/userprofile/(tabs)/avatarAdd/index.tsx
index 81ad30d..a2e477e 100644
--- a/app/account/(stacks)/userprofile/(tabs)/avatarAdd/index.tsx
+++ b/app/account/(stacks)/userprofile/(tabs)/avatarAdd/index.tsx
@@ -15,7 +15,6 @@ export default function AvatarAdd() {
const [image, setImage] = useState(null)
const { showLoadingModal, hideLoadingModal, showAlertModal } = useAlertModal()
const maxFileSize = 1.5 * 1024 * 1024 // 1.5 MB in bytes
- const maxResolution = 8 * 1024 * 1024
const pickImage = async () => {
try {
@@ -29,16 +28,10 @@ export default function AvatarAdd() {
return
}
- if (result.width + result.height > maxResolution) {
- showAlertModal('FAILED', 'Image resolution is too large.')
- return
- }
-
- if (result.width + result.height <= maxResolution) {
- setImage(result)
- }
+ setImage(result)
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
} catch (error) {
- console.log(error)
+ //console.log(error)
//showAlertModal('FAILED', 'Error picking image.')
//Sentry.captureException(error)
}
@@ -114,7 +107,7 @@ export default function AvatarAdd() {
} catch (error) {
console.log('error', error)
showAlertModal('FAILED', 'Error uploading image.')
- Sentry.captureException(error)
+ Sentry.captureMessage(error, 'log')
}
}
diff --git a/app/account/(stacks)/userprofile/(tabs)/bannerAdd/index.tsx b/app/account/(stacks)/userprofile/(tabs)/bannerAdd/index.tsx
index 1086641..015bd89 100644
--- a/app/account/(stacks)/userprofile/(tabs)/bannerAdd/index.tsx
+++ b/app/account/(stacks)/userprofile/(tabs)/bannerAdd/index.tsx
@@ -15,7 +15,6 @@ export default function BannerAdd() {
const [image, setImage] = useState(null)
const { showLoadingModal, hideLoadingModal, showAlertModal } = useAlertModal()
const maxFileSize = 5 * 1024 * 1024 // 1.5 MB in bytes
- const maxResolution = 8 * 1024 * 1024
const pickImage = async () => {
try {
@@ -28,16 +27,10 @@ export default function BannerAdd() {
return
}
- if (result.width + result.height > maxResolution) {
- showAlertModal('FAILED', 'Image resolution is too large.')
- return
- }
-
- if (result.width + result.height <= maxResolution) {
- setImage(result)
- }
+ setImage(result)
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
} catch (error) {
- console.log(error)
+ //console.log(error)
//showAlertModal('FAILED', 'Error picking image.')
//Sentry.captureException(error)
}
@@ -115,9 +108,9 @@ export default function BannerAdd() {
hideLoadingModal()
handleFinish()
} catch (error) {
- console.log(error)
+ //console.log(error)
showAlertModal('FAILED', 'Error picking image.')
- Sentry.captureException(error)
+ Sentry.captureMessage(error, 'log')
}
}
diff --git a/app/announcements/(stacks)/index.tsx b/app/announcements/(stacks)/index.tsx
index bea11d5..a8d1962 100644
--- a/app/announcements/(stacks)/index.tsx
+++ b/app/announcements/(stacks)/index.tsx
@@ -5,7 +5,7 @@ import {
View,
} from 'react-native'
import { H1, H3, Muted } from '~/components/ui/typography'
-import { useEffect, useState } from 'react'
+import { useCallback, useEffect, useState } from 'react'
import { Announcements } from '~/lib/types/collections'
import { database } from '~/lib/appwrite-client'
import { Query } from 'react-native-appwrite'
@@ -22,6 +22,7 @@ import { formatDate } from '~/components/calculateTimeLeft'
import { useColorScheme } from '~/lib/useColorScheme'
import { useAlertModal } from '~/components/contexts/AlertModalProvider'
import * as Sentry from '@sentry/react-native'
+import { useFocusEffect } from '@react-navigation/core'
export default function AnnouncementsPage() {
const { isDarkColorScheme } = useColorScheme()
@@ -59,8 +60,15 @@ export default function AnnouncementsPage() {
setRefreshing(false)
}
+ useFocusEffect(
+ useCallback(() => {
+ onRefresh()
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [])
+ )
+
useEffect(() => {
- fetchAnnouncements().then()
+ showLoadingModal()
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [])
diff --git a/app/community/_layout.tsx b/app/community/_layout.tsx
index badb171..e85e598 100644
--- a/app/community/_layout.tsx
+++ b/app/community/_layout.tsx
@@ -4,7 +4,7 @@ import React from 'react'
function _layout() {
return (
-
+
)
diff --git a/app/community/list/index.tsx b/app/community/index.tsx
similarity index 100%
rename from app/community/list/index.tsx
rename to app/community/index.tsx
diff --git a/app/events/(tabs)/archived.tsx b/app/events/(tabs)/archived.tsx
index 1a5cc22..1c2c420 100644
--- a/app/events/(tabs)/archived.tsx
+++ b/app/events/(tabs)/archived.tsx
@@ -13,7 +13,7 @@ import {
} from '~/components/ui/card'
import { ClockIcon, MapPinIcon } from 'lucide-react-native'
import { useColorScheme } from '~/lib/useColorScheme'
-import { useEffect, useState } from 'react'
+import { useCallback, useEffect, useState } from 'react'
import { functions } from '~/lib/appwrite-client'
import { Events } from '~/lib/types/collections'
import { H1, H3, Muted } from '~/components/ui/typography'
@@ -24,6 +24,7 @@ import {
} from '~/components/calculateTimeLeft'
import { Link } from 'expo-router'
import { useAlertModal } from '~/components/contexts/AlertModalProvider'
+import { useFocusEffect } from '@react-navigation/core'
export default function ArchivedEventsPage() {
const { isDarkColorScheme } = useColorScheme()
@@ -59,13 +60,18 @@ export default function ArchivedEventsPage() {
const onRefresh = () => {
setRefreshing(true)
- showLoadingModal()
fetchEvents().then()
}
+ useFocusEffect(
+ useCallback(() => {
+ onRefresh()
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [])
+ )
+
useEffect(() => {
showLoadingModal()
- fetchEvents().then()
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [])
@@ -79,7 +85,7 @@ export default function ArchivedEventsPage() {
- Events
+ Archived
No events available
diff --git a/app/events/(tabs)/index.tsx b/app/events/(tabs)/index.tsx
index db58358..ef22511 100644
--- a/app/events/(tabs)/index.tsx
+++ b/app/events/(tabs)/index.tsx
@@ -13,7 +13,7 @@ import {
} from '~/components/ui/card'
import { ClockIcon, MapPinIcon } from 'lucide-react-native'
import { useColorScheme } from '~/lib/useColorScheme'
-import { useEffect, useState } from 'react'
+import { useCallback, useEffect, useState } from 'react'
import { functions } from '~/lib/appwrite-client'
import { Events } from '~/lib/types/collections'
import { H1, H3, Muted } from '~/components/ui/typography'
@@ -24,6 +24,7 @@ import {
} from '~/components/calculateTimeLeft'
import { Link } from 'expo-router'
import { useAlertModal } from '~/components/contexts/AlertModalProvider'
+import { useFocusEffect } from '@react-navigation/core'
export default function EventsPage() {
const { isDarkColorScheme } = useColorScheme()
@@ -59,13 +60,18 @@ export default function EventsPage() {
const onRefresh = () => {
setRefreshing(true)
- showLoadingModal()
fetchEvents().then()
}
+ useFocusEffect(
+ useCallback(() => {
+ onRefresh()
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [])
+ )
+
useEffect(() => {
showLoadingModal()
- fetchEvents().then()
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [])
@@ -79,7 +85,7 @@ export default function EventsPage() {
- Events
+ Active
No events available
diff --git a/app/events/(tabs)/upcoming.tsx b/app/events/(tabs)/upcoming.tsx
index 8f22094..193c2a5 100644
--- a/app/events/(tabs)/upcoming.tsx
+++ b/app/events/(tabs)/upcoming.tsx
@@ -13,7 +13,7 @@ import {
} from '~/components/ui/card'
import { ClockIcon, MapPinIcon } from 'lucide-react-native'
import { useColorScheme } from '~/lib/useColorScheme'
-import { useEffect, useState } from 'react'
+import { useCallback, useEffect, useState } from 'react'
import { functions } from '~/lib/appwrite-client'
import { Events } from '~/lib/types/collections'
import { H1, H3, Muted } from '~/components/ui/typography'
@@ -24,6 +24,7 @@ import {
} from '~/components/calculateTimeLeft'
import { Link } from 'expo-router'
import { useAlertModal } from '~/components/contexts/AlertModalProvider'
+import { useFocusEffect } from '@react-navigation/core'
export default function EventsPage() {
const { isDarkColorScheme } = useColorScheme()
@@ -33,7 +34,6 @@ export default function EventsPage() {
const { showLoadingModal, hideLoadingModal, showAlertModal } = useAlertModal()
const fetchEvents = async () => {
- showLoadingModal()
try {
const data = await functions.createExecution(
'event-endpoints',
@@ -63,8 +63,15 @@ export default function EventsPage() {
fetchEvents().then()
}
+ useFocusEffect(
+ useCallback(() => {
+ onRefresh()
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [])
+ )
+
useEffect(() => {
- fetchEvents().then()
+ showLoadingModal()
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [])
@@ -78,7 +85,7 @@ export default function EventsPage() {
- Events
+ Upcoming
No upcoming events
diff --git a/app/gallery/(stacks)/index.tsx b/app/gallery/(stacks)/index.tsx
index dffba3b..abb11d9 100644
--- a/app/gallery/(stacks)/index.tsx
+++ b/app/gallery/(stacks)/index.tsx
@@ -209,8 +209,9 @@ export default function GalleryPage() {
refreshing={refreshing}
numColumns={maxColumns}
contentContainerStyle={{ flexGrow: 1 }}
- onEndReached={loadMore}
- onEndReachedThreshold={0.5}
+ // TODO: Implement this in the future
+ //onEndReached={loadMore}
+ //onEndReachedThreshold={0.5}
ListFooterComponent={
loadingMore && (
(false)
const [events, setEvents] = useState(null)
- const [friendsLocations, setFriendsLocations] = useState(null)
+ const [friendsLocations, setFriendsLocations] =
+ useState(null)
const [refreshing, setRefreshing] = useState(false)
const [currentEvent, setCurrentEvent] = useState(null)
const [filters, setFilters] = useState({
@@ -187,39 +188,35 @@ export default function MutualLocationsPage() {
setUserStatus(updatedDocument)
}
- setFriendsLocations(
- (prevLocations: LocationType.LocationDocumentsType[]) => {
- const existingLocation = prevLocations.find(
- (location) => location?.$id === updatedDocument.$id
+ setFriendsLocations((prevLocations) => {
+ const existingLocation = prevLocations.find(
+ (location) => location?.$id === updatedDocument.$id
+ )
+ if (existingLocation) {
+ // Merge updated document with existing one, preserving userData
+ return prevLocations.map((location) =>
+ location?.$id === updatedDocument.$id
+ ? {
+ ...location,
+ ...updatedDocument,
+ userData: location.userData,
+ }
+ : location
)
- if (existingLocation) {
- // Merge updated document with existing one, preserving userData
- return prevLocations.map((location) =>
- location?.$id === updatedDocument.$id
- ? {
- ...location,
- ...updatedDocument,
- userData: location.userData,
- }
- : location
- )
- } else {
- return [...prevLocations, updatedDocument]
- }
+ } else {
+ return [...prevLocations, updatedDocument]
}
- )
+ })
break
case 'delete':
if (current && updatedDocument.$id === current.$id) {
setUserStatus(null)
}
- setFriendsLocations(
- (prevLocations: LocationType.LocationDocumentsType[]) => {
- return prevLocations.filter(
- (location) => location?.$id !== updatedDocument.$id
- )
- }
- )
+ setFriendsLocations((prevLocations) => {
+ return prevLocations.filter(
+ (location) => location?.$id !== updatedDocument.$id
+ )
+ })
break
case 'create':
if (current && updatedDocument.$id === current.$id) {
@@ -234,24 +231,22 @@ export default function MutualLocationsPage() {
)
const updatedLocationWithUserData = { ...updatedDocument, userData }
- setFriendsLocations(
- (prevLocations: LocationType.LocationDocumentsType[]) => {
- const locationExists = prevLocations.some(
- (location) => location?.$id === updatedDocument.$id
+ setFriendsLocations((prevLocations) => {
+ const locationExists = prevLocations.some(
+ (location) => location?.$id === updatedDocument.$id
+ )
+ if (locationExists) {
+ // Update existing location
+ return prevLocations.map((location) =>
+ location.$id === updatedDocument.$id
+ ? updatedLocationWithUserData
+ : location
)
- if (locationExists) {
- // Update existing location
- return prevLocations.map((location) =>
- location.$id === updatedDocument.$id
- ? updatedLocationWithUserData
- : location
- )
- } else {
- // Add new location
- return [...prevLocations, updatedLocationWithUserData]
- }
+ } else {
+ // Add new location
+ return [...prevLocations, updatedLocationWithUserData]
}
- )
+ })
break
default:
Sentry.captureException('Unknown event type:', updatedDocument)
diff --git a/app/locations/(tabs)/share.tsx b/app/locations/(tabs)/share.tsx
index 6bf392a..5214372 100644
--- a/app/locations/(tabs)/share.tsx
+++ b/app/locations/(tabs)/share.tsx
@@ -18,16 +18,34 @@ import {
AlertDialogHeader,
AlertDialogTitle,
} from '~/components/ui/alert-dialog'
+import { useFocusEffect } from '@react-navigation/native'
+import { Switch } from '~/components/ui/switch'
+import { Label } from '~/components/ui/label'
+import { Separator } from '~/components/ui/separator'
export default function ShareLocationView() {
const [isRegistered, setIsRegistered] = React.useState(false)
const [status, setStatus] = React.useState(null)
const [modalOpen, setModalOpen] = React.useState(false)
+ const [preciseLocation, setPreciseLocation] = React.useState(false)
const { current } = useUser()
- React.useEffect(() => {
- checkStatusAsync().then()
- }, [])
+ useFocusEffect(
+ React.useCallback(() => {
+ checkStatusAsync().then()
+ checkPreciseStatus().then()
+ }, [])
+ )
+
+ const checkPreciseStatus = async () => {
+ const preciseLocation = await AsyncStorage.getItem('preciseLocation')
+ if (!preciseLocation) {
+ await AsyncStorage.setItem('preciseLocation', 'true')
+ setPreciseLocation(true)
+ } else {
+ setPreciseLocation(preciseLocation === 'true')
+ }
+ }
const checkStatusAsync = async () => {
const status = await BackgroundFetch.getStatusAsync()
@@ -60,15 +78,30 @@ export default function ShareLocationView() {
}
async function registerBackgroundFetchAsync(userId: string) {
+ if (!userId) {
+ setIsRegistered(false)
+ return Alert.alert('Error', 'No user ID found. Are you logged in?')
+ }
await AsyncStorage.setItem('userId', userId)
- //await requestPermissions()
+ //const preciseLocationItem = await AsyncStorage.getItem('preciseLocation')
+
let foreground = await Location.getForegroundPermissionsAsync()
let background = await Location.getBackgroundPermissionsAsync()
if (foreground.status !== 'granted' || background.status !== 'granted') {
setModalOpen(true)
return
}
-
+ /*
+ await Location.startLocationUpdatesAsync('background-location-task', {
+ accuracy:
+ preciseLocationItem === 'true'
+ ? Location.Accuracy.High
+ : Location.Accuracy.Low,
+ showsBackgroundLocationIndicator: true,
+ distanceInterval: 10,
+ timeInterval: 10000,
+ })
+ */
await Location.startLocationUpdatesAsync('background-location-task', {
accuracy: Location.Accuracy.High,
showsBackgroundLocationIndicator: true,
@@ -82,8 +115,7 @@ export default function ShareLocationView() {
await Location.stopLocationUpdatesAsync('background-location-task')
try {
- await database.deleteDocument('hp_db', 'locations', userId)
- return
+ return await database.deleteDocument('hp_db', 'locations', userId)
// eslint-disable-next-line @typescript-eslint/no-unused-vars
} catch (e) {
return
@@ -104,6 +136,34 @@ export default function ShareLocationView() {
await checkStatusAsync()
}
+ /*
+ const updateLocationAccuracy = async () => {
+ AsyncStorage.setItem(
+ 'preciseLocation',
+ preciseLocation ? 'false' : 'true'
+ ).then(() => {
+ setPreciseLocation(!preciseLocation)
+ })
+
+ const preciseLocationItem = await AsyncStorage.getItem('preciseLocation')
+ const isRegistered = await TaskManager.isTaskRegisteredAsync(
+ 'background-location-task'
+ )
+
+ if (isRegistered) {
+ await Location.stopLocationUpdatesAsync('background-location-task')
+ await Location.startLocationUpdatesAsync('background-location-task', {
+ accuracy:
+ preciseLocationItem === 'true'
+ ? Location.Accuracy.High
+ : Location.Accuracy.Low,
+ showsBackgroundLocationIndicator: true,
+ distanceInterval: 10,
+ timeInterval: 10000,
+ })
+ }
+ }
+ */
return (
@@ -148,6 +208,19 @@ export default function ShareLocationView() {
+
+ {/* TODO: Implement this feature
+
+
+
+
+ */}
NOTE: Please only enable this for conventions or other kinds of events.
In the future you will be able to properly select users to share your
diff --git a/app/user/(stacks)/index.tsx b/app/user/(stacks)/index.tsx
index af38569..a782f48 100644
--- a/app/user/(stacks)/index.tsx
+++ b/app/user/(stacks)/index.tsx
@@ -14,7 +14,7 @@ export default function UserListPage() {
const [loadingMore, setLoadingMore] = useState(false)
const [offset, setOffset] = useState(0)
- const fetchUsers = useCallback(async (newOffset: number = 0) => {
+ const fetchUsers = async (newOffset: number = 0) => {
try {
const data: UserData.UserDataType = await database.listDocuments(
'hp_db',
@@ -37,7 +37,7 @@ export default function UserListPage() {
toast('Failed to fetch users. Please try again later.')
Sentry.captureException(error)
}
- }, [])
+ }
const onRefresh = async () => {
setRefreshing(true)
@@ -58,7 +58,7 @@ export default function UserListPage() {
useEffect(() => {
fetchUsers(0).then()
- }, [fetchUsers])
+ }, [])
const renderItem = ({ item }: { item: UserData.UserDataDocumentsType }) => (
diff --git a/components/locations/SettingsModal.tsx b/components/locations/SettingsModal.tsx
index 13d862c..c063bb8 100644
--- a/components/locations/SettingsModal.tsx
+++ b/components/locations/SettingsModal.tsx
@@ -14,6 +14,7 @@ import { Text } from '~/components/ui/text'
import { Input } from '~/components/ui/input'
import { database } from '~/lib/appwrite-client'
import { Switch } from '~/components/ui/switch'
+import { Separator } from '~/components/ui/separator'
export default function SettingsModal({
openModal,
@@ -69,6 +70,7 @@ export default function SettingsModal({
maxLength={40}
/>
+
-
-
-
- {text}
+
+
+
+
+
+
+ {text}
+
+
+
-
+
)
}