How can I get the chat room online members without reload the page in converse js - xmpp

I am using converse.js and I am trying to get the users who joined the chat room, I am able to get the users but when a new user joins I can not get the new user on my console log until I reload the page, Below I have created a plugin for getting the users.
export const moderationActions = () => {
window.converse.plugins.add('moderation-actions', {
dependencies: [],
initialize: function () {
const _converse = this._converse;
_converse.api.listen.on(
'getToolbarButtons',
async (toolbar_el: any, buttons: any) => {
toolbar_el.model.occupants.models.map((occupant: any) => {
console.log(occupant.get('nick'), occupant.get('show')),
console.log(occupant);
});
},
);
},
});
};
There are a few events related to users like membersFetched but don't know how can I get the users without reloading the page

Whenever someone joins or leaves a room, a new occupant model is added or removed from the occupants collection on the room model (available via the .occupants attribute).
Whenever a model is added or removed from a collection, an add or remove event is triggered which you can listen to.
So you can try something like this:
window.converse.plugins.add('num-occupants', {
initialize: function () {
const _converse = this._converse;
const room = await api.rooms.get('jid');
let num_occupants = room.occupants.length;
room.occupants.on('add', () => (num_occupants = room.occupants.length));
room.occupants.on('remove', () => (num_occupants = room.occupants.length));
}
});

Related

Google charged me $5000 in a month for using Google Place API

My project is under development, Vuejs and Flutter in the frontend and Laravel is in the backend.
I am using Google place autocomplete API in this project, I made a big mistake due to not having enough knowledge of using google apiz.
After trial finished google charged $5000.
My mistakes were 2 things;
Requesting unnecessary data and not providing sessionToken
I am posting my edited codes here if anyone can check it please, I'm afraid to make mistake again.
vuejs code
mounted() {
this.$refs.focusable.focus();
let $vm = this;
var autocomplete = new google.maps.places.Autocomplete(
document.getElementById("autocomplete"),
{
componentRestrictions: { country: "ca" },
fields: ["address_components", "formatted_address", "geometry"],
types: ["address"],
bounds: new google.maps.LatLngBounds(
new google.maps.LatLng(49.246292, -123.116226)
),
//strictbounds: true,
}
);
google.maps.event.addListener(autocomplete, "place_changed", function () {
var data = autocomplete.getPlace();
let latlng = {
lat: data.geometry.location.lat(),
lng: data.geometry.location.lng(),
};
data.address_components.forEach((component) => {
if (component.types.indexOf("administrative_area_level_1") > -1) {
if ($vm.checkState(component.short_name)) {
$vm.validAddress(data, latlng);
} else {
$vm.invalidAddress(data);
}
}
});
});
},
According to google docs link I don't need to provide sessionToken for Autocomplete widget. and I think my code is correct here.
and this is my Flutter code
TextFormField(
autofocus: true,
controller: _addressController,
decoration: InputDecoration(hintText: 'Postal code'),
onChanged: (val) {
final sessionToken = Uuid.v4();
findPlace(val, sessionToken);
},
),
//get a place
void findPlace(String placeName, String sessionToken) async {
if (placeName.length > 1) {
String autoComplete =
"$googleApi?input=$placeName&types=address&components=country:ca&key=$mapKey&sessiontoken=$sessionToken";
var res = await http.get(Uri.parse(autoComplete));
Map data = jsonDecode(res.body);
var predictions = data['predictions'];
var placesList = (predictions as List)
.map((e) => PlacePredictions.fromJson(e))
.toList();
setState(() {
sToken = sessionToken;
placePredictionList = placesList;
});
}
}
// get place details using place_id
addressDetails(placeId, sessionToken) async {
String fields = 'address_component,formatted_address,geometry';
String placeDetailsUrl =
"$googleApiDetails?place_id=$placeId&fields=$fields&key=$mapKey&sessiontoken=$sessionToken";
var res = await http.get(Uri.parse(placeDetailsUrl));
Map data = jsonDecode(res.body);
}
In the above Flutter code there is a confusion for me is this sessiontoken or sessionToken I don't know how to check it and there is no any information in the Google docs.
Help really appreciated.
Can't post as a comment as I don't have the required rep.
But you can cap your API usage so things like these won't happen.
Read more here: https://cloud.google.com/apis/docs/capping-api-usage
In the Google Cloud console, go to the APIs & Services Dashboard page.
From the projects list, select a project or create a new one.
Click the name of the API you're interested in.
Click Quotas. If the Quotas tab is not present in the tab nav, it means the API you've selected doesn't have quotas defined.
To find the quota you want to cap, enter the appropriate properties and values in the filter_list Filter field. For example, to find the Subnetworks quota, enter Quota:Subnetworks.
Click the checkbox next to the quota you want to cap, and then click create EDIT QUOTAS.
Complete the quota change form, including the new limit that you want to set.
Click SUBMIT REQUEST.

Not able to fetch store values when a link is hit directly

Hitting a link from a website without visiting the Homepage is not setting the values in the store.
I have made axios calls in nuxtServerInit action and have set the data in mutations. I am able to access this data everywhere in the project now but if I load a particular page from the website then the data is not shown until refreshed.
Following is store/index.js file
/* eslint-disable */
import Vuex from 'vuex'
import axios from 'axios'
const createStore = () => {
return new Vuex.Store({
state: {
organisation: Object,
},
mutations: {
setOrganisation(state, organisation){
state.organisation = organisation
},
},
actions: {
nuxtServerInit({ commit }, context){
axios.get(api-link-to-fetch-data-from-backend))
.then(res => {
commit("setOrganisation", res.data[0])
})
.catch(e => context.error(e));
}
},
getters: {
getOrganisation(state){
return state.organisation;
}
}
})
}
This data needs to be used in the navigation bar. So it is being fetched from the store in layout/default.vue in the created method like this,
created() {
this.organisation = this.$store.getters.getOrganisation;
}
As nuxtServerInit is the first function that is called in the nuxt lifecycle why is the data not being stored when any link from the website is accessed directly?
Example here:
Post
This information about the recent videos gets set after refreshing the page.

ionic reload a page from another page/modal

EDIT
I noticed that the subscribe event must come first before and publish get called. But it will be silly to ask user to open TabOut page every time when app start.
I do not need to always reloading the TabOut page, so I need this event sort of method to do the job. Or else could've just call the reload on ionViewDidEnter().
I have 2 Tabs and 1 modal. /TabIn, /TabOut, and /ModalIn.
The Tabs page serve as data listing which display the data from database on ionViewDidLoad().
The ModalIn page serve as data entry for the user to key in and submit data. This page resides in the TabIn page and will get called when user clicked on each of the list of data.
After successfully submit the form in the ModalIn page I want to call refresh again on the TabOut page (no matter it has been loaded before or not). I tried using events publish it is not working. Below are my code.
ModalIn .ts
let headers: any = new HttpHeaders({ 'Content-Type': 'application/x-www-form-urlencoded' }),
options: any = { "username": val, formValue },
url: any = "some_url_here";
this.http.post(url, options, headers)
.subscribe((data: any) => {
if (data.status == 'success') {
this.events.publish('shouldReloadData');
} else {
}
},
(error: any) => {
console.log(error);
});
TabOut .ts
constructor(public events: Events) {
events.subscribe('shouldReloadData', () => {
// Reload the page here
console.log("should reloadddd"); // <- This is not working
});
}
Call subscribe with this keyword inside TabOut.ts.
constructor(public events: Events) {
this.events.subscribe('shouldReloadData', () => {
});
}

Ionic2: Unsubscribe Event to Avoid Duplicate Entries?

I've followed this tutorial which outlines adding monitoring beacons in an Ionic 2 application. I have it working great: when the view loads, it initializes and begins listening for beacons:
home.ts
ionViewDidLoad() {
this.platform.ready().then(() => {
this.beaconProvider.initialise().then((isInitialised) => {
if (isInitialised) {
this.listenToBeaconEvents();
}
});
});
}
This calls the listenToBeaconEvents function which populates a list in the view with all of the beacons:
home.ts
listenToBeaconEvents() {
this.events.subscribe(‘didRangeBeaconsInRegion’, (data) => {
// update the UI with the beacon list
this.zone.run(() => {
this.beacons = [];
let beaconList = data.beacons;
beaconList.forEach((beacon) => {
let beaconObject = new BeaconModel(beacon);
this.beacons.push(beaconObject);
});
});
});
}
I'm able to stop ranging using this.beaconProvider.stopRanging() that calls a function from the below function:
beacon-provider.ts
stopRanging() {
if (this.platform.is('cordova')) {
// stop ranging
this.ibeacon.stopRangingBeaconsInRegion(this.region)
.then(
() => {
console.log('Stopped Ranging');
},
error => {
console.error('Failed to stop monitoring: ', error);
}
);
}
}
The problem I'm having is this - in the original tutorial the beacon list is shown at the root, there's no other navigation. I've moved it to a different view, and if the user exits and re-enters the view, it re-initializes and loads everything, resulting in duplicate list entries.
I've tried creating a function within beacon-provider.ts to call before the view exits, but I can't figure out how to keep the subscriptions/events from duplicating.
I've tried this.delegate.didRangeBeaconsInRegion().unsubscribe(), and some other variations but they all result in runtime errors.
In your case you are using Ionic's Events API which has its own unsubscribe(topic, handler) function.
In your component, whenever you need to unsubscribe, you should call this with the same topic:
this.events.unsubscribe(‘didRangeBeaconsInRegion’);
This will remove all handlers you may have registered for the didRangeBeaconsInRegion.
If you want to unsubscribe one specific function, you will have to have registered a named handler which you can send with unsubscribe.
this.events.unsubscribe(‘didRangeBeaconsInRegion’,this.mySubscribedHandler);
And your home.ts would look like:
mySubscribedHandler:any = (data) => {
// update the UI with the beacon list
this.zone.run(() => {
this.beacons = [];
let beaconList = data.beacons;
beaconList.forEach((beacon) => {
let beaconObject = new BeaconModel(beacon);
this.beacons.push(beaconObject);
});
});
}
listenToBeaconEvents() {
this.events.subscribe(‘didRangeBeaconsInRegion’,this.mySubscribedHandler);
}

How do I know that I'm still on the correct page when an async callback returns?

I'm building a Metro app using the single-page navigation model. On one of my pages I start an async ajax request that fetches some information. When the request returns I want to insert the received information into the displayed page.
For example:
WinJS.UI.Pages.define("/showstuff.html", {
processed: function (element, options) {
WinJS.xhr(...).done(function (result) {
element.querySelector('#target').innerText = result.responseText;
});
}
};
But how do I know that the user hasn't navigated away from the page in the meantime? It doesn't make sense to try to insert the text on a different page, so how can I make sure that the page that was loading when the request started is still active?
You can compare the pages URI with the current WinJS.Navigation.location to check if you are still on the page. You can use Windows.Foundation.Uri to pull the path from the pages URI to do this.
WinJS.UI.Pages.define("/showstuff.html", {
processed: function (element, options) {
var page = this;
WinJS.xhr(...).done(function (result) {
if (new Windows.Foundation.Uri(page.uri).path !== WinJS.Navigation.location)
return;
element.querySelector('#target').innerText = result.responseText;
});
}
};
I couldn't find an official way to do this, so I implemented a workaround.
WinJS.Navigation provides events that are fired on navigation. I used the navigating event to build a simple class that keeps track of page views:
var PageViewManager = WinJS.Class.define(
function () {
this.current = 0;
WinJS.Navigation.addEventListener('navigating',
this._handleNavigating.bind(this));
}, {
_handleNavigating: function (eventInfo) {
this.current++;
}
});
Application.pageViews = new PageViewManager();
The class increments a counter each time the user starts a new navigation.
With that counter, the Ajax request can check if any navigation occurred and react accordingly:
WinJS.UI.Pages.define("/showstuff.html", {
processed: function (element, options) {
var pageview = Application.pageViews.current;
WinJS.xhr(...).done(function (result) {
if (Application.pageViews.current != pageview)
return;
element.querySelector('#target').innerText = result.responseText;
});
}
};