Wix code Advance
Wix release the new wix-realtime which allow developers to build interactive apps like chat app, multi-player game etc.
So, In this example i will discuss how we can build a chat app where a user can send a message to person B and person B immediatly get the message.
If you want to test it live here is the link:
https://test.salman2301.com
Overview Front-end we use custom element, which allows to show the message side by side and also with custome element, we can have a fix height and scroll bar so user can scroll to previous messages. We can use repeater for this but we need to use pagination or infinite scrolling which is why i didn't.
On the Backend, we use wix-realtime API with datahook
- datahook runs the code when a new row is inserted in the database. - realtime API allow us to do pub/sub ( publish/ subscriber) where sender or publisher send message to a channel and the reciever or subscriber can reciver the message.
Dataflow If a user Person A send a message to Person B, the message will be inserted in the database and this runs the afterInsert data hook and the data hook use realtime api to publish to a channel, the name of the channel is same as the Person B user id. In this way, only the person B recieve the message and On the front-end, let's assume that the person B is online and we subscribe to the channel and the name of the channel Is the current user id. We get the user id from wix-user module wixUser.currentUser.id .
Database Database Name: message
Fields: field_key data from - USER_ID to - USER_ID message - Message
Code // backend/data.js
import {publish} from 'wix-realtime-backend' ;
// datahook runs when a new row is inserted in the database
// item contains inserted row information { from: "uuid", to:"uuid", message:"hello"}
export function message_afterInsert(item, context) {
const { from, to, message, _id } = item;
const channel = { name : to};
let data = {
message,
from,
_id
};
// publish which take a channel name and data.
publish(channel, data, {includePublisher: true });
return item;
} // Page code
import * as realtime from "wix-realtime" ;
import wixUsers from "wix-users" ;
import wixData from "wix-data" ;
import { getUsers, getMe } from "backend/getUsers.jsw" ;
let lastUserId, lastLoginEmail, lastPicture;
let userId = wixUsers.currentUser.id;
let owner;
$w.onReady( function () {
// $w('#dataset1').onReady(init);
init();
$w( "#inSearch" ).onKeyPress((e) => {
setTimeout(() => {
if (e.key === "Enter" ) filterMem();
if (e.key === "Escape" ) {
$w( "#inSearch" ).value = "" ;
filterMem();
}
}, 40 );
});
$w( "#ChatElement" ).setAttribute(
"append-msg" ,
JSON.stringify({
user: {
name: "salman" ,
},
msg: " Hello this is a test" ,
date: new Date().toISOString(),
isOwner: true ,
})
);
getMe().then((data) => {
owner = data;
});
});
function init() {
// wix real time
const channel = { name: userId };
realtime.subscribe(channel, newMessage);
// update UI
filterMem();
// events
$w( "#repeaterUser" ).onItemReady(($item, itemData, i) => {
let { loginEmail, picture } = itemData;
$item( "#image1" ).src = picture;
$item( "#textEmail" ).text = loginEmail;
});
$w( "#containerUser" ).onClick((e) => {
switchUser(e.context.itemId);
});
$w( "#btnSend" ).onClick(sendMessage);
$w( "#inMessage" ).onKeyPress((e) => {
const { ctrlKey, key } = e;
if (key === "Enter" && !ctrlKey) {
sendMessage();
}
});
}
async function filterMem() {
let inMember = $w( "#inSearch" ).value || undefined ;
getUsers(inMember)
.then((data) => {
$w( "#repeaterUser" ).data = data.items;
if (!lastUserId) {
switchUser(data.items[ 0 ]._id);
}
})
.catch(console.error);
}
async function switchUser(toUserId) {
lastUserId = toUserId;
$w( "#repeaterUser" ).onItemReady(($item, itemData, i) => {
let { _id, loginEmail, picture } = itemData;
if (_id === toUserId) {
$item( "#imgCurrUser" ).show();
$w( "#textHeadUser" ).text = `Connected to ${ loginEmail } ` ;
lastLoginEmail = loginEmail;
lastPicture = picture;
refreshMsg();
} else {
$item( "#imgCurrUser" ).hide();
}
});
}
async function newMessage({ payload }) {
appendMsg(payload._id);
}
async function refreshMsg() {
$w( "#ChatElement" ).setAttribute( "messages" , "[]" );
let resMsgs = await wixData
.query( "message" )
.eq( "from" , userId)
.eq( "to" , lastUserId)
.or(wixData.query( "message" ).eq( "from" , lastUserId).eq( "to" , userId))
.ascending( "_createdDate" )
.find();
let msg = resMsgs.items;
let username = lastLoginEmail.split( "@" )[ 0 ];
msg = msg.map((el) => {
let isOwner = userId === el.from;
let userImage = isOwner ? owner.picture : lastPicture;
userImage = encodeURI(userImage);
if (!userImage.startsWith( "https://" )) userImage = undefined ;
return {
_id: el._id,
isOwner: isOwner,
user: {
name: username,
image: userImage,
},
msg: el.message,
date: el._createdDate,
data: el,
};
});
$w( "#ChatElement" ).setAttribute( "messages" , JSON.stringify(msg));
if (msg.length === 0 ) {
$w( "#textNoMsg" ).show();
} else {
$w( "#textNoMsg" ).hide();
}
}
async function appendMsg(msgId) {
let resMsgs = await wixData.query( "message" ).eq( "_id" , msgId).find();
let message = resMsgs.items[ 0 ];
console.log({ resMsgs });
let username = lastLoginEmail.split( "@" )[ 0 ];
let isOwner = userId === message.from;
let userImage = isOwner ? owner.picture : lastPicture;
userImage = encodeURI(userImage);
if (!userImage.startsWith( "https://" )) userImage = undefined ;
let msg = {
_id: message._id,
isOwner: isOwner,
user: {
name: username,
image: userImage,
},
msg: message.message,
date: message._createdDate,
data: message,
};
if (!(lastUserId === message.from || lastUserId === message.to)) {
console.error( " No for the current user show alert!" );
return ;
}
$w( "#ChatElement" ).setAttribute( "append-msg" , JSON.stringify(msg));
}
async function sendMessage() {
try {
$w( "#btnSend" ).disable();
let msg = $w( "#inMessage" ).value;
if (!msg) return ;
let toInsert = {
from: userId,
to: lastUserId,
message: msg,
};
let inserted = await wixData.insert( "message" , toInsert);
appendMsg(inserted._id);
$w( "#btnSend" ).enable();
$w( "#inMessage" ).value = "" ;
} catch (e) {
console.log( "ERROR : " , e.message);
$w( "#btnSend" ).enable();
$w( "#inMessage" ).value = "" ;
}
}
For the custome element check my github
https://github.com/Salman2301/wix-chat-component
Like