SOLVED: Currently online-page

Hi,

I want to make a page that shows all users that are currently online. How do I do that?

Thanks!

Solution from @J. D. (thanks!):

For example:
Databse (collection: CurrentlyOnline):
memberId (text)
TimeStamp (number)
Backend code (data.js):

import wixData from 'wix-data';

export function CurrentlyOnline_afterQuery(item, context) {
 return wixData.query("Members/PrivateMembersData")
    .eq("_id", item.memberId)
    .find()
    .then((res) => {
        item.nickname = res.items[0].nickname;
 return item;
    })
}

export function CurrentlyOnline_beforeInsert(item, context) {
 return wixData.query("CurrentlyOnline")
    .eq("memberId", item.memberId)
    .limit(1)
    .find()
    .then((res) => {
 if(res.items.length > 0){
            wixData.remove("CurrentlyOnline", res.items[0]._id)
        }
        item.timestamp = new Date().getTime();
 return item;
    })
}

Site Code Panel:

import wixUsers from 'wix-users';
import wixData from 'wix-data';
let user = wixUsers.currentUser;
let userId = wixUsers.currentUser.id.currentUser.id;

$w.onReady(function () {
 if(user.loggedIn){
        setInterval(function(){
            wixData.save("CurrentlyOnline", {"memberId": userId}) 
        }, 5000);
    }
});

“Currently Online” page - page code panel:

import wixData from 'wix-data';

$w.onReady(function () {
    setInterval(function(){
            wixData.query("CurrentlyOnline")
            .gt("timestamp", new Date().getTime() - 20000)
            .find()
            .then((res) => {
 if(res.items.length > 0){
                    $w("#repeater1").data = res.items;
                }else{
                    $w("#repeater1").data = [];
                }
            })
        }, 10000);

});

export function repeater1_itemReady($item, itemData, index) {
    $item("#text1").text = itemData.nickname;
}

Adjust the times as you wish.

You could look at adding something like a ‘Logged In Members’ dataset and add into your code so that when a member logs in then the onLogin() function simply makes a dataset boolean field be set as Yes or ticked etc. Then obviously when user logouts you can use code again to set this dataset field to be No or unticked etc.

Then you could just simply query this dataset and show only the logged in members from it in whatever you want to show it in like a table or a repeater etc.

I can’t think off the top of my head if there is a way through Wix Users to do a mass is logged in check as Wix User normally is used to check each current user really. You could even look at creating a backend function that checks each members logged in status if you wanted to.

Also, you can only really use Wix User for this as this checks all members that are logged in members.
You can’t use Wix CRM as this checks all your site contacts and remember that some of those contacts are just contacts and not members so you have no need to be checking them.

You can try doing the following:

On the site panel, use setInterval() to save the member’s userId and timeStamp every x seconds to the CurrentlyOnline collection.
On the backend create an afterQuery hook with item.nickname that gets the nickname from PrivateMembersData.

  • Make a beforeInsert hook that removes the last record of the same member if exists.

On the Currently Online site page, setInterval() that runs every x seconds and query the CurrentlyOnline with .gt(“timeStamp”, new Date().getTime() - 5000) (for example)
and push the result.items to the repeater.

Thanks, forum ninja!
Could you please give me an example (code snippet)?

For example (I didn’t check if there’re errors etc…):
Databse (collection: CurrentlyOnline):

  1. memberId (text)

  2. TimeStamp (number)
    Backend code (data.js):

import wixData from 'wix-data';

export function CurrentlyOnline_afterQuery(item, context) {
 return wixData.query("Members/PrivateMembersData")
    .eq("_id", item.memberId)
    .find()
    .then((res) => {
        item.nickname = res.items[0].nickname;
 return item;
    })
}

export function CurrentlyOnline_beforeInsert(item, context) {
 return wixData.query("CurrentlyOnline")
    .eq("memberId", item.memberId)
    .limit(1)
    .find()
    .then((res) => {
 if(res.items.length > 0){
            wixData.remove("CurrentlyOnline", res.items[0]._id)
        }
        item.timestamp = new Date().getTime();
 return item;
    })
}

Site Code Panel:

import wixUsers from 'wix-users';
import wixData from 'wix-data';
let user = wixUsers.currentUser;
let userId = wixUsers.currentUser.id;

$w.onReady(function () {
 if(user.loggedIn){
        setInterval(function(){
            wixData.save("CurrentlyOnline", {"memberId": userId}) 
        }, 5000);
    }
});

“Currently Online” page - page code panel:

import wixData from 'wix-data';

$w.onReady(function () {
    setInterval(function(){
            wixData.query("CurrentlyOnline")
            .gt("timestamp", new Date().getTime() - 20000)
            .find()
            .then((res) => {
 if(res.items.length > 0){
                    $w("#repeater1").data = res.items;
                }else{
                    $w("#repeater1").data = [];
                }
            })
        }, 10000);

});

export function repeater1_itemReady($item, itemData, index) {
    $item("#text1").text = itemData.nickname;
}


Adjust the times as you wish.

I got it working! Thing is, I have a “All members” page. My wish is to combine these two. So that I have one repeater on top with “Now online” and another one with “All others”. But I don’t want duplicates, eg. someone is displayed in Now online and in All others. Is that possible>

Sorry for my bad English, it’s not my native language.

You can query the all members collection and then filter out the currently online using javascript, or query the all members collection and eliminate the currently online in your query itself.

Okay, thanks!!!

I didn’t manage to combine the page because I would be spammed with an error message, but still, thanks! It’s awesome how it is now!

The way to combine them depends on the question whether or not you have a Members collection of your own (besides the built-in Private Members collection).

I use the built-in Members/PrivateMembersData collection.

So you can try something like that on the page code panel:

import wixData from 'wix-data';
$w.onReady(function () {
    setInterval(function(){
        wixData.query("CurrentlyOnline")
        .gt("timestamp", new Date().getTime() - 20000)
        .limit(1000)
        .find()
        .then((onlineRes) => {
            let onlineUsers = onlineRes.items;
            let offlineQuery = wixData.query("Members/PrivateMembersData");
            if(onlineUsers.length > 0){
            $w("#repeater1").data = onlineUsers;
            for(let i = 0; i < onlineUsers; i++){
                offlineQuery = offlineQuery.ne("_id", onlineUsers[i].memberId);
            }
            }else{
                $w("#repeater1").data = [];
            }
            offlineQuery
            .limit(1000)
            .find()
            .then((offlineRes) => {
                let offlineUsers = offlineRes.items;
                    if(offlineUsers.length > 0){
                        $w("#repeater2").data = offlineUsers;
                    } else {
                        $w("#repeater2").data = [];
                    }
            })
        })
    }, 10000);
});
export function repeater1_itemReady($item, itemData, index) {
$item("#text1").text = itemData.nickname;
}
 export function repeater2_itemReady($item, itemData, index) { $item("#text2").text = itemData.nickname; }