I was wondering if you could me with this task. I have tried a few suggestions from similar threads I’ve found and tried some I could easily detect, but I couldn’t really relate others to my situation, so perhaps you can help me in my particular case.
The issue here is that the ionViewDidEnter hook is triggered twice once the app is launched (however, it doesn’t do that afterwards, for example, if you navigate to other pages and come back, it will correctly only trigger once). I’ll put the html and ts code here so for more clarity. If more info is needed, please let me know! Cheers everyone
HTML:
<ion-header>
<ion-toolbar>
<ion-title>Join an Event</ion-title>
<ion-buttons slot="start">
<ion-menu-button></ion-menu-button>
</ion-buttons>
</ion-toolbar>
</ion-header>
<ion-content>
<div padding text-center *ngIf="!hasVerifiedEmail">
Please verify your email to view the events!
<ion-button (click)="sendVerificationEmail()">Send verification email</ion-button><br>
Click refresh if you have verified!
<ion-button (click)="pageReload()">Refresh</ion-button>
</div>
<div *ngIf="hasVerifiedEmail">
<ion-searchbar mode="ios" placeholder="Search Event by Name" show-clear-button="always" showCancelButton="focus" (ionChange)="searchField($event)"></ion-searchbar> <!-- (ionCancel)="getUserPrefs()" -->
<h6>Filter Events by Sport/Activity</h6>
<ion-slides class="categories-slides" [options]="catSlideOptions">
<ion-slide (click)="changeSportPreference('All')"><img src="assets/img/cat-all.jpg"></ion-slide>
<ion-slide (click)="changeSportPreference('Soccer')"><img src="assets/img/cat-soccer.jpg"></ion-slide>
<ion-slide (click)="changeSportPreference('Basketball')"><img src="assets/img/cat-basketball.jpg"></ion-slide>
<ion-slide (click)="changeSportPreference('Tennis')"><img src="assets/img/cat-tennis.jpg"></ion-slide>
<ion-slide (click)="changeSportPreference('Gym')"><img src="assets/img/cat-gym.jpg"></ion-slide>
<ion-slide (click)="changeSportPreference('Running')"><img src="assets/img/cat-running.jpg"></ion-slide>
</ion-slides>
<h6>Find a Place (Coming Soon!)</h6>
<ion-slides [options]="placesOptions">
<ion-slide>
<ion-card><img src="assets/img/pitch-smithfield.jpg">
<ion-card-header>
<ion-card-title>Smithfield Astro Pitch</ion-card-title>
<ion-button small expand="block" fill="outline" (click)="comingSoonAlert()"><ion-card-subtitle>Book Now</ion-card-subtitle></ion-button>
</ion-card-header>
</ion-card>
</ion-slide>
<ion-slide>
<ion-card><img src="assets/img/pitch-example.jpg">
<ion-card-header>
<ion-card-title>Example Astro Pitch</ion-card-title>
<ion-button small expand="block" fill="outline" (click)="comingSoonAlert()"><ion-card-subtitle>Book Now</ion-card-subtitle></ion-button>
</ion-card-header>
</ion-card>
</ion-slide>
</ion-slides>
<ion-button small expand="block" fill="outline" (click)="toggleFilteredEvents()"><ion-card-subtitle>{{ showFilteredEvents ? "Show All Events" : "Show Events Within 5km" }}</ion-card-subtitle></ion-button>
<!-- Modified this for Pagination test 2, copy code from repo to backup -->
<ion-list *ngIf="itemsPage!==undefined">
<h6>Events Available</h6>
<ion-card *ngFor="let evt of (showFilteredEvents ? eventsWithin5Km : itemsPage)" padding style="background: url('../../../assets/img/gameon-tennis-bg.jpg') no-repeat center center / cover;">
<ion-row>
<ion-col>
<ion-card-subtitle>{{ evt.date | date:'dd/MM/yyyy' }}, at {{ evt.date | date:'h:mm a'}}</ion-card-subtitle>
<ion-card-title>{{ evt.type }}</ion-card-title>
<ion-card-subtitle>{{ evt.title }}</ion-card-subtitle>
<ion-card-subtitle><ion-icon name="pin"></ion-icon>{{ evt.location }}</ion-card-subtitle>
<ion-card-subtitle>Participants: <span class="numPart"> {{ evt.part.length }}</span> / <span class="numPlayers">{{ evt.players }}</span></ion-card-subtitle>
</ion-col>
<ion-col>
<ion-button small expand="block" fill="outline" (click)="viewEventDetails(evt)">View Event</ion-button>
<!-- <ion-button small expand="block" fill="outline" (click)="addMeToEvent(evt)">Join Event</ion-button> -->
<ion-button small expand="block" fill="outline" (click)="joinEvent(evt)">Join Event</ion-button>
</ion-col>
</ion-row>
</ion-card>
</ion-list>
<div *ngIf="itemsPage?.length<=0" class="ion-padding">
<ion-item class="ion-text-center txtAlert" lines="none">
No events available for this category
</ion-item>
<ion-item class="ion-text-center txtAlert" lines="none">
<ion-label><ion-button small expand="block" fill="outline" (click)="userCurrentPreferredSport('All')">View All</ion-button> or <ion-button small expand="block" fill="outline" (click)="createEvent()">Create one!</ion-button></ion-label>
</ion-item>
</div>
<ion-infinite-scroll threshold="80px" (ionInfinite)="loadDataInfiniteScrolling($event)">
<ion-infinite-scroll-content
loadingSpinner="bubbles"
loadingText="Loading more data...">
</ion-infinite-scroll-content>
</ion-infinite-scroll>
</div>
</ion-content>
TS:
constructor(
private eventServ: EventsService,
private alertServ: AlertService,
private userServ: UsersService,
private pushServ: PushService,
private authServ: AuthService,
public loadServ: LoadService,
private router: Router,
private locationAccuracy: LocationAccuracy, // GPS and Geolocation for User and Events
private actRoute: ActivatedRoute // GPS and Geolocation for User and Events
){
}
ngOnInit() {
}
async ionViewDidEnter() {
console.log('ionViewDidEnter() called');
this.loadServ.presentLoad();
this.events = []
this.currentUser = JSON.parse(localStorage.getItem('currentUser') || '{}');
this.getUserProfile();
this.userModel = {};
this.getCurrentLocation();
// ADDED TO ATTEMPT TO TRY TO CALCULATE USERS AND EVENT DISTANCE
this.eventLocation = this.actRoute.snapshot.paramMap.get('eventLocation');
this.userLocation = null;
console.log("the user has verified his email.");
}
getUserProfile() {
this.userServ.getUserProfile(this.currentUser['user']['uid']).then((doc: any) => {
if (doc.exists) {
this.user = this.currentUser;
this.tempUser = doc.data();
this.userModel = this.tempUser;
this.userName = this.userModel.name ?? " ";
this.userFavSport = this.userModel.pref ?? 'all';
} else {
console.log("getUserProfile failed");
}
this.listEvents(this.userFavSport);
});
}
// Setting and changing the User's preferred Sport
userCurrentPreferredSport(userFavSport?: any) {
this.index = 0;
let localPref: any;
console.log('PrefArray:', userFavSport);
if (userFavSport !== undefined) {
localPref = userFavSport;
} else if (this.userFavSport !== undefined) {
localPref = this.userFavSport;
} else {
localPref = 'All';
}
console.log('localPref:', localPref); // debugging
if (localPref == 'All') {
// Load all events when "All" is selected
// Filter to include all data types
this.itemsPage = this.events.slice(this.index, this.index + this.offset);
this.index += this.offset;
} else {
let prefItemsPage = this.events.filter((item: any) => {
if (localPref == 'All') {
// Include all data types when localPref is "All"
return true;
} else {
return item.type === localPref;
}
});
console.log('prefItemsPage:', prefItemsPage); // debugging
// Load the initial set of events based on user preference
this.itemsPage = prefItemsPage.slice(this.index, this.index + this.offset);
this.index += this.offset;
}
// Check if there are more events to load
this.checkIndexToLoad();
}
changeSportPreference(selectedSport: string) {
this.userFavSport = selectedSport; // Update the user's sport preference
this.userCurrentPreferredSport(this.userFavSport); // Call the preference function to load events of the selected sport
}
// Infinite Scrolling
async checkIndexToLoad() {
if (this.index < this.events.length) {
// Enable infinite scrolling if there are more events to load
this.infiniteScroll!.disabled = false;
} else {
// Disable infinite scrolling if no more events are available
this.infiniteScroll!.disabled = true;
}
}
scrollHandler(e:any) {
console.log("e: ", e);
if (e === 'bottom') {
//this.page.more()
}
}
async loadDataInfiniteScrolling(event: any) {
this.reActiveInfinite = event;
console.log('loadData called. userFavSport: ', this.userFavSport);
setTimeout(() => {
// Load more events based on the user's current sport preference
let filteredEvents = [];
if (this.userFavSport === 'All') {
// Load more events without sport type filtering when 'All' is selected
filteredEvents = this.events;
} else {
// Load more events based on the user's current sport preference
filteredEvents = this.events.filter((event: any) => {
return event.type === this.userFavSport;
});
}
const moreEvents = filteredEvents.slice(this.index, this.index + this.offset);
this.index += this.offset;
for (let i = 0; i < moreEvents.length; i++) {
this.itemsPage.push(moreEvents[i]);
}
event.target.complete();
// Check if there are more events to load
this.checkIndexToLoad();
}, 1000);
}
// Page reload after user verifies email
pageReload(){
window.location.reload();
}
// Search Field (top bar)
async searchField(event: any) {
this.itemsPage = await this.eventServ.initializeEvents();
const searchTerm = event.srcElement.value;
if (!searchTerm) {
return;
}
this.itemsPage = this.itemsPage.filter((currentEvent: any) => {
return (
currentEvent.title.toLowerCase().includes(searchTerm.toLowerCase()) ||
currentEvent.type.toLowerCase().includes(searchTerm.toLowerCase())
);
});
}
// Events-related functions (List, View, Create, Join)
async listEvents(pref: any){
this.eventServ.listEvents().subscribe(async (res: any[])=>{
this.events = res.map(e => {
return {
id: e.payload.doc.id,
createdAt: e.payload.doc.data()['createdAt'],
createdBy: e.payload.doc.data()['createdBy'],
part: e.payload.doc.data()['part'],
comments: e.payload.doc.data()['comments'],
type: e.payload.doc.data()['type'],
title: e.payload.doc.data()['title'],
date: e.payload.doc.data()['date'],
time: e.payload.doc.data()['time'],
map: e.payload.doc.data()['map'],
players: e.payload.doc.data()['players'],
location: e.payload.doc.data()['location'],
description: e.payload.doc.data()['description'],
image: e.payload.doc.data()['image'],
} as Event;
})
console.log('Events => ', this.events);
if(this.events.length>0){
this.userCurrentPreferredSport(pref);
}
});
setTimeout(() => {
this.loadServ.dismissLoad();
}, 1000);
}
viewEventDetails(evt:any){
this.router.navigate(['/event', { dataEvt: JSON.stringify(evt) }]);
}
createEvent(){
this.router.navigate(['/create-event']);
}
joinEvent(evt: any){
let evTopic = evt.id;
FCM.subscribeTo({ topic: evTopic });
let myUID = this.currentUser['user']['uid'];
evt['part'].forEach((element: { [x: string]: any; }) => {
if (JSON.stringify(evt['part'].length) == evt['players']) {
this.eventIsFull = true;
}
else if (element['id'] == myUID || this.currentUser.isAdmin){
this.alreadyInEvent = true;
}
else {
this.alreadyInEvent = false;
}
console.log('evt[part]: ', element);
});
if(this.alreadyInEvent == false && this.eventIsFull == false){
let addUser = {
'id': myUID,
'name': this.userName,
'isAdmin': false
}
evt['part'].push(addUser);
this.updateProfile(evt['id']);
let msg = 'Joined Event successfuly!';
this.alertServ.myAlert(msg);
this.eventServ.joinEvents(evt.id, evt).then((res:any)=>{
let myName = this.userName;
let msg = myName + ' joined the event';
this.pushServ.sendPush(evTopic, myName, msg).subscribe((res:any)=> {
console.log("Res push: ", res)
})
this.viewEventDetails(evt);
});
}else if (this.alreadyInEvent == true){
let msg = 'You are already in this event!';
this.alertServ.myAlert(msg);
} else if (this.eventIsFull == true && this.alreadyInEvent == false) {
let msg = 'This event is full!';
this.alertServ.myAlert(msg);
}
}
updateProfile(evtID:any) {
let uid = this.currentUser['user']['uid'];
console.log('evtID-1: ', evtID);
if(evtID!==undefined){
if(this.userModel['myevt']==undefined){
this.userModel['myevt'] = [evtID];
}else{
this.userModel['myevt'].push(evtID);
}
console.log('this.model: ', this.userModel);
this.authServ.updateProfile(uid, this.userModel)
.then(res => {
console.log('Update User Evt', res);
});
}else{
console.log('evtID-3: ', evtID);
}
}
// GPS and Geolocation for User and Events
async getCurrentLocation() {
try {
const permissionStatus = await Geolocation.checkPermissions();
console.log('Permission status: ', permissionStatus.location);
if(permissionStatus?.location != 'granted') {
const requestStatus = await Geolocation.requestPermissions();
if(requestStatus.location != 'granted') {
// go to location settings
await this.openSettings(true);
return;
}
}
if(Capacitor.getPlatform() == 'android') {
this.enableGps();
}
let options: PositionOptions = {
maximumAge: 3000,
timeout: 10000,
enableHighAccuracy: true
};
const position = await Geolocation.getCurrentPosition(options);
console.log(position);
console.log("Latitude: ", position.coords.latitude);
console.log("Longitude: ", position.coords.longitude);
this.userLocation = {
lat: position.coords.latitude,
lng: position.coords.longitude,
};
} catch(e: any) {
if(e?.message == 'Location services are not enabled') {
await this.openSettings();
}
console.log(e);
}
}
// Open Settings on phone for the purpose of granting location permission from the user
openSettings(app = false) {
console.log('open settings...');
return NativeSettings.open({
optionAndroid: app ? AndroidSettings.ApplicationDetails : AndroidSettings.Location,
optionIOS: app ? IOSSettings.App : IOSSettings.LocationServices
});
}
async enableGps() {
const canRequest = await this.locationAccuracy.canRequest();
if(canRequest) {
await this.locationAccuracy.request(this.locationAccuracy.REQUEST_PRIORITY_HIGH_ACCURACY);
}
}
filterEventsWithin5Km() {
const R = 6371; // Radius of the Earth in kilometers
this.eventsWithin5Km = this.events.filter((event:any) => {
// Ensure event.map is not null or undefined before accessing its properties
if (event.map?.lat && event.map?.lng && this.userLocation?.lat && this.userLocation?.lng) {
// Parse the latitude and longitude values
const eventLat = parseFloat(event.map.lat);
const eventLng = parseFloat(event.map.lng);
const userLat = parseFloat(this.userLocation.lat);
const userLng = parseFloat(this.userLocation.lng);
// Calculate the distance
const dLat = (eventLat - userLat) * (Math.PI / 180);
const dLon = (eventLng - userLng) * (Math.PI / 180);
const a =
Math.sin(dLat / 2) * Math.sin(dLat / 2) +
Math.cos(userLat * (Math.PI / 180)) * Math.cos(eventLat * (Math.PI / 180)) *
Math.sin(dLon / 2) * Math.sin(dLon / 2);
const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
const distance = R * c; // Distance in kilometers
console.log('Event:', event.title);
console.log('Event Location:', eventLat, eventLng);
console.log('User Location:', userLat, userLng);
console.log('Distance:', distance);
return distance <= 5; // Return true for events within 5 km
} else {
return false; // If event.map or userLocation is null or undefined, return false
}
});
console.log('Filtered Events:', this.eventsWithin5Km);
}
toggleFilteredEvents() {
this.showFilteredEvents = !this.showFilteredEvents;
if (this.showFilteredEvents) {
// If showing filtered events, call the filtering function
this.filterEventsWithin5Km();
}
}
// Alerts
comingSoonAlert(){
let msg = 'This feature is not yet available! Check back later!';
this.alertServ.myAlert(msg);
}
// User Logout
logout() {
this.authServ.logout().then(() => {
this.router.navigate(['/login']);
})
}
}