Fading Coder

One Final Commit for the Last Sprint

Home > Tech > Content

Building an Approval WeChat Mini Program: Registration and Login Pages

Tech 1

Project Overview

The mini program is divided into two main portals: the User Portal and the Approval Portal.

The User Portal allows regular users to apply for activities, check activity statuses, view activity history, request appointments, and view appointment history.

The Approval Portal is split into two sections: Activity Approval and Appointment Approval. As the name suggests, Activity Approval is used to review activity applications submitted by users and grant either an approved or rejected status. Appointment Approval functions similarly.

Creating the Selection Pages

Primary Selection Interface

We will first create the primary selection page, which is the initial screen users see upon launching the mini program.

Implementation Strategy

  1. Modify the top navigation title.
  2. Add two button componants.
  3. Implement page navigation on click.
  4. Apply CSS for UI styling.

Implementation Steps

  1. Register the pages in app.:

"pages": [ "pages/landing/landing", "pages/home/home", "pages/userLogin/userLogin", "pages/userRegister/userRegister", "pages/roleSelection/roleSelection", "pages/activityApprovalLogin/activityApprovalLogin", "pages/activityApprovalRegister/activityApprovalRegister", "pages/appointmentApprovalLogin/appointmentApprovalLogin", "pages/appointmentApprovalRegister/appointmentApprovalRegister" ]

  1. Update the navigation bar title in the landing page's JSON configuration:

"navigationBarTitleText": "Committee Mini Program"

  1. Add the button components and style them.

landing.wxml

<button bindtap="navigateToUserLogin" class="user-login-btn" style="width: 60%; height: 30%;">User Login</button>
<button bindtap="navigateToRoleSelection" class="approver-login-btn" style="width: 60%; height: 30%;">Approver Login</button>

landing.wxss

.approver-login-btn {
  margin-top: 10px;
  border-radius: 80rpx;
  color: black;
  background-color: #FFFFFF;
  box-shadow: 16rpx 8rpx 24rpx rgba(212,48,48, 0.15);
}

.user-login-btn {
  border-radius: 80rpx;
  margin-top: 55%;
  color: #FFFFFF;
  background-color: #D43030;
  box-shadow: 16rpx 8rpx 24rpx rgba(212,48,48, 0.35);
}
  1. Implement the navigation logic.

Note: wx.navigateTo keeps the current page and navigates to a page within the app. However, it cannot navigate to tabbar pages. You can use wx.navigateBack to return to the original page. The page stack in a mini program can hold up to ten layers.

landing.js

Page({
  navigateToRoleSelection() {
    console.log('Navigating to Approver Role Selection');
    wx.navigateTo({
      url: '../roleSelection/roleSelection'
    });
  },
  
  navigateToUserLogin() {
    console.log('Navigating to User Login');
    wx.navigateTo({
      url: '../userLogin/userLogin'
    });
  }
});

Secondary Selection Interface

This is the page where users choose between approving activities or approving appointments after selecting the Approver Login option.

Implementation Strategy

Similar to the primary selection page:

  1. Two button components are needed.
  2. Modify the JSON file to add a navigation bar title.
  3. Implement navigation logic.

Implementation Steps

Since the logic is identical to the primary selection page, the code is provided directly below.

roleSelection.wxml

<button bindtap="navigateToActivityLogin" class="activity-approval-btn" style="width: 60%; height: 30%;">Approve Activities</button>
<button bindtap="navigateToAppointmentLogin" class="appointment-approval-btn" style="width: 60%; height: 30%;">Approve Appointments</button>

roleSelection.wxss

.appointment-approval-btn {
  margin-top: 10px;
  border-radius: 80rpx;
  color: black;
  background-color: #FFFFFF;
  box-shadow: 16rpx 8rpx 24rpx rgba(212,48,48, 0.15);
}

.activity-approval-btn {
  border-radius: 80rpx;
  margin-top: 55%;
  color: #FFFFFF;
  background-color: #D43030;
  box-shadow: 16rpx 8rpx 24rpx rgba(212,48,48, 0.35);
}

roleSelection.js

Page({
  navigateToActivityLogin() {
    console.log('Navigating to Activity Approval Login');
    wx.navigateTo({
      url: '../activityApprovalLogin/activityApprovalLogin'
    });
  },
  
  navigateToAppointmentLogin() {
    console.log('Navigating to Appointment Approval Login');
    wx.navigateTo({
      url: '../appointmentApprovalLogin/appointmentApprovalLogin'
    });
  }
});

Creating the Login Page

We need to create login and registration pages for the User Portal, Activity Approval Portal, and Appointment Approval Portal. This guide will demonstrate the User Portal login and registration; the other portals can reuse the same template with modified cloud data base collection names.

Implementation Strategy

  1. Use a view container for the "User Login Portal" header with a bottom border.
  2. Use a view container for the "Login" heading with appropriate spacing.
  3. Use two input components to capture the username and password.
  4. Use an image component (eye icon) with corresponding JS logic to toggle password visibility.
  5. Use two view containers for "Forgot Account" and "Register Account" (only registration is implemented here).
  6. Use a button component with JS logic to authenticate and navigate to the user homepage.

Implementation Steps

The core challenges here are the CRUD operations with the cloud database and toggling the type attribute of the input component by clicking an image.

1. Header Container

userLogin.wxml

<view class="header">
  <view class="header-text">User Login Portal</view>
</view>

userLogin.wxss

.header {
  border-bottom: 2px solid grey;
  width: 100%;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
}

.header-text {
  font-size: 20px;
  font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
}

2. Main Heading

userLogin.wxml

<view class="main-title"><text decode="true">L&nbsp;&nbsp;ogin</text></view>

userLogin.wxss

.main-title {
  padding-top: 20%;
  font-size: 50px;
  display: flex;
  align-items: center;
  flex-direction: column;
}

3. Input Fields

To capture the username, we use the bindinput event to set the data.

userLogin.wxml

<input bindinput="captureUsername" class="input-field" placeholder="Enter Username"></input>

userLogin.js

captureUsername(e) {
  this.setData({
    username: e.detail.value
  });
}

For the password input, we bind the type attribute to a data variable to control visibility.

userLogin.wxml

<input class="input-field" type="{{inputType}}" placeholder="Enter Password" value='{{pwd}}' bindinput='capturePassword'></input>

userLogin.js

capturePassword(e) {
  this.setData({
    pwd: e.detail.value
  });
}

By binding type to {{inputType}}, the input type dynamically reflects the value of inputType in the JS data (initially "password").

4. Password Visibility Toggle

A ternary operator is used in the src attribute to conditionally render the eye icon.

userLogin.wxml

<image class='toggle-pwd-icon' bindtap='togglePasswordVisibility' src="{{isPwdVisible ? '../../icon/eye-open.png' : '../../icon/eye-closed.png'}}"></image>

userLogin.js

togglePasswordVisibility() {
  this.setData({
    isPwdVisible: !this.data.isPwdVisible,
    inputType: this.data.isPwdVisible ? 'text' : 'password'
  });
}

5. Registration Link

userLogin.wxml

<view bindtap="navigateToRegister" class="register-link">Don't have an account?</view>

userLogin.js

navigateToRegister() {
  wx.navigateTo({
    url: '../userRegister/userRegister'
  });
}

6. Login Logic

Ensure your cloud database is initialized in app.js before using it.

userLogin.wxml

<button bindtap="handleLogin" style="width: 88%;">Login</button>

The logic follows these steps: Get credentials -> Query database for the account -> Verify the password -> Navigate on success or show error on failure.

userLogin.js

const db = wx.cloud.database();

handleLogin() {
  const { username, pwd } = this.data;
  
  db.collection('users')
    .where({
      account: username
    })
    .get()
    .then(res => {
      if (res.data.length > 0 && pwd === res.data[0].password) {
        console.log('Login successful');
        wx.showToast({ title: 'Login Successful' });
        wx.switchTab({ url: '../home/home' });
      } else {
        wx.showToast({ title: 'Login Failed: Incorrect credentials', icon: 'none' });
      }
    })
    .catch(() => {
      wx.showToast({ title: 'Login Failed: Network error', icon: 'none' });
    });
}

Creating the Registration Page

The registration page is structurally similar to the login page. The primary difference is that it uses the "Create" operation from CRUD, whereas login uses "Read".

Implementation Steps

userRegister.wxml

<view class="header">
  <view class="header-text">User Registration Portal</view>
</view>
<view class="main-title"><text decode="true">R&nbsp;&nbsp;egister</text></view>
<view class="disclaimer">Note: This is the registration page. We do not collect personal information. You only need to register an account and password (used solely as credentials for this mini program). Upon successful registration, you can log in to the approval portal.</view>
<input bindinput="captureUsername" class="input-field" placeholder="Enter Username"></input>
<input bindinput="capturePassword" class="input-field" placeholder="Enter Password"></input>
<input bindinput="captureFullName" class="input-field" placeholder="Enter Full Name"></input>
<button bindtap="handleRegistration" style="width: 88%;">Register</button>

userRegister.wxss

.header {
  border-bottom: 2px solid grey;
  width: 100%;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
}

.header-text {
  font-size: 20px;
  font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
}

.main-title {
  padding-top: 20%;
  font-size: 50px;
  display: flex;
  align-items: center;
  flex-direction: column;
}

.disclaimer {
  padding: 5%;
  font-size: 15px;
  color: red;
}

.input-field {
  margin: 10% 20px 15px;
  padding: 15px;
  border-radius: 30px;
  border: 1px solid #F2E6E6;
  box-shadow: 16rpx 8rpx 24rpx rgba(212,48,48, 0.25);
}

button {
  border-radius: 80rpx;
  margin-top: 20%;
  padding: 15px 0;
  color: #FFFFFF;
  background-color: #D43030;
  box-shadow: 16rpx 8rpx 24rpx rgba(212,48,48, 0.35);
}

Since retrieving the user's openid requires a cloud function, ensure your cloud function environment is properly initialized.

userRegister.js

const db = wx.cloud.database();

Page({
  data: {
    pwd: '',
    username: '',
    fullName: ''
  },

  onLoad() {
    wx.cloud.callFunction({ name: 'getOpenId' })
      .then(res => {
        console.log("User OpenID:", res.result.openid);
      })
      .catch(err => {
        console.error("Cloud function failed:", err);
      });
  },

  handleRegistration() {
    const { username, pwd, fullName } = this.data;
    
    if (!username) {
      wx.showToast({ title: "Please enter a username", icon: "none" });
      return;
    }
    if (!pwd) {
      wx.showToast({ title: "Please enter a password", icon: "none" });
      return;
    }
    if (!fullName) {
      wx.showToast({ title: "Please enter your full name", icon: "none" });
      return;
    }

    db.collection('users').add({
      data: {
        account: username,
        password: pwd,
        name: fullName
      }
    }).then(() => {
      wx.showToast({ title: 'Registration Successful' });
    }).catch(() => {
      wx.showToast({ title: 'Registration Failed', icon: "none" });
    });
  },

  captureUsername(e) {
    this.setData({ username: e.detail.value });
  },
  
  capturePassword(e) {
    this.setData({ pwd: e.detail.value });
  },
  
  captureFullName(e) {
    this.setData({ fullName: e.detail.value });
  }
});

Remember to update the collection name and environment ID in the code to match your own cloud development configuration.

Troubleshooting Registration Failures

Possible Causes

The first reason could be that the user's openid was not retrieved when the page loaded.

The second common reason is database permissions. Navigate to your cloud development console to check the collection's permissions.

If the database permissions are set to "All users can read, but only creators can read and write," new users won't have write access, causing the registration to fail silently or return a permission error. Ensure the permistions are appropriately configured for user registration.

Related Articles

Understanding Strong and Weak References in Java

Strong References Strong reference are the most prevalent type of object referencing in Java. When an object has a strong reference pointing to it, the garbage collector will not reclaim its memory. F...

Comprehensive Guide to SSTI Explained with Payload Bypass Techniques

Introduction Server-Side Template Injection (SSTI) is a vulnerability in web applications where user input is improper handled within the template engine and executed on the server. This exploit can r...

Implement Image Upload Functionality for Django Integrated TinyMCE Editor

Django’s Admin panel is highly user-friendly, and pairing it with TinyMCE, an effective rich text editor, simplifies content management significantly. Combining the two is particular useful for bloggi...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.