Velo Tutorial: Building Your Own Members Area

Visit the Velo by Wix website to onboard and continue learning.

Note: You can now add a members area to your site without using code. You can also create a page that displays items based on the currently logged-in member without using code.

In this article we demonstrate how to create a profile page for each of your site members. The data for the dynamic profile page is created when a site visitor first logs in to your site. Members can view and update their personal profiles at any time.  

Note: The functionality for logging members in and out of your site only works fully when viewing your published site. You will not be able to fully test your member profile pages in preview mode.

To create our member profile pages we build:

  • A members collection
  • A profile page
  • An update page
  • A login page

This article assumes you are familiar with the following concepts:

Members Collection

We begin by creating a collection named Members, which is where we store all of the member data. Each item in the collection is another member.

Because we want to restrict access to members so they can only view and update their own items, we set the permissions for the Members collection to Custom Use and choose the following:

  • Who can read content from this collection? - Site member author
  • Who can create content for this collection? - Site member
  • Who can update content from this collection? - Site member author
  • Who can delete content from this collection? - Admin

The collection can contain whatever member data you want. In this example, we use the following fields:

Field NameField KeyType
TitletitleText
First NamefirstNameText
Last NamelastNameText
EmailemailText
PhonephoneText
AboutaboutText

Profile Page

Next, we create a page to display member profiles. It is a dynamic item page connected to the Members collection. Because we are creating a dynamic item page, we need to choose a field to add to the URL that uniquely identifies each member. Here we use each member's automatically generated IDs to uniquely identify them. 

The URL looks like this:

Because we're only using this page to display data, we set the dynamic dataset's mode to Read-only.

We also set the page's permissions to Members Only using the Permissions tab of the Page Settings so that only members who are logged in can reach the page.

The page itself is designed with elements for displaying the information in a member's profile. In our example, that means text elements that are connected through the page's dynamic dataset to the fields in the Members collection.

Finally, we add a button element. When we create the update page, we will connect the link of the button to navigate to the update page for the current member.

When members check their profile pages, they will see something like this:

Update Page

The update page is very similar to the profile page. It is also a dynamic item page connected to the Members collection. It also uses the members' IDs as the unique identifying field. However, because we can't have two pages with the same URL in our site, we add Update to the URL so it looks like this: 

Because we're displaying data on this page and allowing members to edit their data, we set the dynamic dataset's mode to Read & Write.

Once again we set the page's permissions to Members Only using the Permissions tab of the Page Settings so that only members who are logged in can reach the page.

This time the page is designed with elements for displaying and editing the information in a member's profile. In our example, we'll use a dropdown element, some text input elements, and a text box element. All these elements are connected through the page's dynamic dataset to the fields in the Members collection.

Finally, we add a button element for submitting edited data. We connect the submit button using the Connect to CMS button as follows:

FieldValue
Choose a datasetMembers Item
Click action connects toProfile Page

When members see their update pages, they will see something like this:

Now that we've created the update page, we can return to the profile page to link the update button.

We connect the update button using the Connect to CMS button as follows:

FieldValue
Choose a datasetMembers Item
Click action connects toUpdate Page

Login Page

In our example we have a dedicated page for members to use for logging into the site. However, you can set this page as your homepage, add the contents of this page to any page, or show them on all pages

Note: Because we have a dedicated login page, we'll be adding the code below to this page. However, if you're showing the elements on all pages, you need to add the code below to masterPage.js.

The design of our login page is very simple. It contains two buttons. The first button is used for either logging in or logging out, depending on whether the current member is already logged in or not. The second button is used to navigate to a member's profile page. It is only shown for members who are already logged in.

Code

The code on our login page consists of four parts:

  • Imports for the APIs used in the rest of the code
  • An onReady event handler for setting up the page when it loads
  • A login button onClick event handler for either:
    • logging in a member and possibly creating a new item in the Members collection if it is a first-time login
    • logging out a member who is already logged in
  • A profile button onClick event handler for navigating members to their profile pages

Let's take a look at the code piece by piece to understand what it's doing.

Import APIs and Declare Variables

Copy Code
import { currentMember, authentication } from 'wix-members-frontend';
import wixData from 'wix-data';
import wixLocationFrontend from 'wix-location-frontend';
let memberId, memberEmail;

Lines 1-3: First, we import all the APIs we need for our example:
wix-members-frontend: For getting information about the current member and for logging members in and out.
wix-data: For querying and inserting into the Members collection.
wix-location-frontend: For navigating to other pages
Line 5: We declare 2 global variables, memberId and memberEmail.

Check if the Current Member is Logged In

Copy Code
async function checkIfLoggedIn(){
const thisMember = await currentMember.getMember();
return thisMember ? true : false;
}

Lines 1-2: We add an async function to check if the current member is logged in, and await the current member.
Lines 3-4: We return the current member. If we can get the current member, thisMember is true, and if not, then thisMember is false.

Set Up the 'login/logout' Buttons

Copy Code
$w.onReady( () => {
if (wixWindowFrontend.rendering.env === "browser") {
checkIfLoggedIn().then(res => {
if (res === true) {
$w("#loginButton").label = "Logout";
$w("#profileButton").show();
} else {
$w("#loginButton").label = "Login";
$w("#profileButton").hide();
}
})

Lines 1-3: In the onReady() function, we set the window rendering environment to ‘browser’ to prevent the code in the onReady() function from running twice. We then call the checkIfLoggedIn() function to see if the current member is logged in.
Lines 4-6: If the current member is logged in, we label the button ‘Logout’, and show the profile button.
Lines 7-11: If the current member is not logged in, we label the button ‘Login', and hide the profile button.

Authenticate the Member on Log In

Copy Code
authentication.onLogin(async (member) => {
const loggedInMember = await member.getMember();
memberId = loggedInMember._id;
memberEmail = loggedInMember.loginEmail;
return wixData.query("Members")
.eq("_id", memberId)
.find()
.then((results) => {
if (results.Members.length === 0) {
const toInsert = {
"_id": memberId,
"email": memberEmail
};
wixData.insert("Members", toInsert)
.catch( (err) => {
console.log(err);
} );
}
})
.catch( (err) => {
console.log(err);
});
});
}
});

Lines 1-2: Still in the onReady() function, we add an async function authenticating the member when they log in, and await the current member data.
Lines 3-4: We set the current member ID and email, returned from the current member data to variables.
Lines 5-25: We search the ‘Members’ data collection for the current member’s ID. If no results are found, then we insert a new item in the ‘Members’ collection for the new member, with their ID and email.

When the Login Button is Clicked

Copy Code
export async function loginButton_click(event) {
if(await checkIfLoggedIn() === true) {
authentication.logout();
console.log('Member is logged out.')
$w("#loginButton").label = "Login";
$w("#profileButton").hide();
} else {
authentication.promptLogin({"mode": "login"})
.then(() => {
console.log('Member is logged in.');
$w("#loginButton").label = "Logout";
$w("#profileButton").show();
})
.catch((error) => {
console.error(error);
});
}
}

Lines 1-6: We add an async event handler to the login button. When a member clicks the login button, the function first checks if the member is logged in. If the member is logged in, the button’s label already shows ‘Logout’ from the logic in the onReady() function above. So when the member clicks the (logout) button, they are logged out, the button label changes to 'Login', and the profile button is hidden.
Lines 7-18: If the member is not logged in, the button’s label already shows ‘Login’ from the logic in the onReady() function above. So when the member clicks the (login) button, they are prompted to log in, the button label then changes to 'Logout', and the profile button is shown.

When the Profile Button is Clicked

Copy Code
export async function profileButton_click(event) {
let loggedInMember = await currentMember.getMember();
memberId = loggedInMember._id;
wixLocationFrontend.to(`/items/${memberId}`);
}

Lines 1-2: We add an async event handler to the profile button. When a member clicks the profile button, the function first gets the current member data.
Lines 3-5: We set the current member ID, returned from the current member data to a variable. We pass the variable to the wix-location-frontend.to() function, sending members to their personal profile page.


Full Example Code

Here is the complete code for this example:

Copy Code
import { currentMember, authentication } from 'wix-members-frontend';
import wixData from 'wix-data';
import wixLocationFrontend from 'wix-location-frontend';
let memberId, memberEmail;
async function checkIfLoggedIn(){
const thisMember = await currentMember.getMember();
return thisMember ? true : false;
}
$w.onReady( () => {
if (wixWindowFrontend.rendering.env === "browser") {
checkIfLoggedIn().then(res => {
if (res === true) {
$w("#loginButton").label = "Logout";
$w("#profileButton").show();
} else {
$w("#loginButton").label = "Login";
$w("#profileButton").hide();
}
})
authentication.onLogin(async (member) => {
const loggedInMember = await member.getMember();
memberId = loggedInMember._id;
memberEmail = loggedInMember.loginEmail;
return wixData.query("Members")
.eq("_id", memberId)
.find()
.then((results) => {
if (results.Members.length === 0) {
const toInsert = {
"_id": memberId,
"email": memberEmail
};
wixData.insert("Members", toInsert)
.catch( (err) => {
console.log(err);
} );
}
})
.catch( (err) => {
console.log(err);
});
});
}
});
export async function loginButton_click(event) {
if(await checkIfLoggedIn() === true) {
authentication.logout();
console.log('Member is logged out.')
$w("#loginButton").label = "Login";
$w("#profileButton").hide();
} else {
authentication.promptLogin({"mode": "login"})
.then(() => {
console.log('Member is logged in.');
$w("#loginButton").label = "Logout";
$w("#profileButton").show();
})
.catch((error) => {
console.error(error);
});
}
}
export async function profileButton_click(event) {
let loggedInMember = await currentMember.getMember();
memberId = loggedInMember._id;
wixLocationFrontend.to(`/items/${memberId}`);
}

To learn more about the wix-members-frontend module, see the API Reference.

Was this helpful?
Yes
No