Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
314 changes: 246 additions & 68 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,96 +1,274 @@
CONTENTS OF THIS FILE
# Customizing the PWA

The Mentor PWA is developed using the Ionic framework. This document provides instructions on setting up the development environment.

Contents
---------------------

* Dependencies
* Ionic-Android build Setup
* Cli setup
* Project setup
* Build apk
* Debug apk
* [Dependencies](#dependencies)
* [Setting up the CLI](#setting-up-the-cli)
* [Setting up the Project](#setting-up-the-project)
* [Building the Application](#building-the-application)
* [Debugging the Application](#debugging-the-application)
* [Setting up the HashiCorp® Vault](#setting-up-the-hashicorp-vault)
* [Creating a Jenkins® Job](#creating-a-jenkins-job)
* [Deploying the Application Using an Ansible® Script](#deploying-the-application-using-an-ansible-script)
* [Structure of Environment file, Server.js, and pm2.config.json](#structure-of-environment-file-serverjs-and-pm2configjson)

Dependencies
------------

DEPENDENCIES
---------------------
* Ionic:
| Requirement | Description |
|--------------|-----------|
| Ionic CLI|Version 7.1.1 (/usr/local/lib/node_modules/@ionic/cli)|
| Ionic Framework | <ul><li>@ionic/angular 6.7.5</li> <li>@angular-devkit/build-angular : 13.2.6 </li><li> @angular-devkit/schematics : 13.2.6 </li><li>@angular/cli : 13.2.6 </li><li> @ionic/angular-toolkit : 6.1.0 </li></ul>|
| Capacitor | <ul><li>Capacitor CLI : 5.5.1 </li><li>@capacitor/android : 5.5.1 </li><li>@capacitor/core : 5.5.1 </li><li>@capacitor/ios : 5.5.1 </li></ul>|
| Cordova | <ul><li>Cordova CLI : 11.0.0</li><li>Cordova Platforms : none</li><li>Cordova Plugins : no whitelisted plugins (0 plugins total)</li></ul>|
| Utility | <ul><li>cordova-res : 0.15.4</li><li>native-run : 1.7.4 </li></ul>
| System | <ul><li>Android SDK Tools : 26.1.1</li><li><a href="https://nodejs.org/">Node.js®</a>: v18.18.2</li><li>npm: 10.2.0</li><li>OS : Linux 5.13</li></ul>|

Ionic CLI : 6.19.1 (/usr/local/lib/node_modules/@ionic/cli)
Ionic Framework : @ionic/angular 6.1.7
@angular-devkit/build-angular : 13.2.6
@angular-devkit/schematics : 13.2.6
@angular/cli : 13.2.6
@ionic/angular-toolkit : 6.1.0
Setting up the CLI
------------------

* Capacitor:
1. Install the Ionic framework.

Capacitor CLI : 3.5.1
@capacitor/android : 3.5.0
@capacitor/core : 3.5.1
@capacitor/ios : 3.5.0
```
npm install -g ionic
```

* Cordova:
2. Install the Ionic client.

Cordova CLI : 11.0.0
Cordova Platforms : none
Cordova Plugins : no whitelisted plugins (0 plugins total)
```
npm install -g @ionic/cli
```

* Utility:
3. Install the Capacitor Core.

cordova-res : 0.15.4
native-run : 1.6.0
```
npm install @capacitor/core
```

* System:
4. Install the Capacitor runtime Client.

Android SDK Tools : 26.1.1 (/home/afnan/Android/Sdk)
NodeJS : v14.19.0 (/usr/local/bin/node)
npm : 6.14.16
OS : Linux 5.13
```
npm install @capacitor/cli --save-dev
```

Setting up the Project
----------------------

IONIC-ANDROID BUILD SETUP
---------------------
1. Clone the [repository](https://github.com/ELEVATE-Project/mentoring-mobile-app.git).
2. Change to the latest GitHub branch (**release-2.6.1**).
3. Add environment files into the src/environments folder.
4. Go to the project folder and run `npm i`.

- [Install java] (https://www.oracle.com/java/technologies/downloads/#java8)
- [Install Gradle] (https://gradle.org/install/)
- [Install Android Studio] (https://developer.android.com/studio)

- After Android studio installation, install SDK
- Open Android studio and goto settings/appearance and behavior/system settings/Android SDK
- Install appropriate Android sdk platform package.
- Add environment variables in ~/.bashrc or ~/.bash_profile as follows
export ANDROID_SDK_ROOT=path_to_sdk
export PATH=$PATH:$ANDROID_SDK_ROOT/tools/bin
export PATH=$PATH:$ANDROID_SDK_ROOT/platform-tools
- Reference: https://ionicframework.com/docs/installation/android
Building the Application
------------------------

1. To add the Capacitor plugin, run the following command:

CLI SETUP
---------------------
```
npx cap sync

- `npm install -g ionic`
- `npm install @capacitor/core`
- `npm install @capacitor/cli --save-dev`
- `npx cap init`
```

2. To run a development build, run the following command:

PROJECT SETUP
---------------------
```
ionic build

- git clone the repo (https://github.com/ELEVATE-Prjoect/mentoring-mobile-app.git)
- Add environment files inside src/environments
- Go to project folder and run npm i
```

BUILD APK
---------------------
3. To perform an Ionic build and update any Capacitor plugins or dependencies, run the capacitor sync command.

- To check attached devices do adb devices
- Run ionic build (Make sure you have attached device)
- Run ionic cap sync
- Run ionic capacitor run android --prod
- Apk location project_folder/platforms/android/app/build/outputs/apk/debug/apk_name.apk
```
ionic cap sync

```

4. Run the project on your local system using the following command:

```
ionic serve

```

Debugging the Application
-------------------------

1. Open the running app in the browser.
2. Start inspecting using Chrome dev tools or any alternatives.

Setting up the HashiCorp Vault
------------------------------

After setting up the HashiCorp Vault, you must add the Vault address to the Jenkins Pipeline script and Ansible deployment script.

Creating a Jenkins Job
----------------------
To automate your app deployment using Jenkins, do as follows:

1. Create a Jenkins job each time you want a deployment.

2. Add the pipeline script for the job inside the job’s **Configure** section. This pipeline will fetch the latest code from the given branch in the repository and run the [Ansible script](#deploying-the-application-using-an-ansible-script).

```
pipeline { agent any
options {
disableConcurrentBuilds()
}
stages {
stage("git"){
steps{

git branch: '<branch-name>', url: '<github-repo-url>'
}

}
stage("ansible run"){
steps{

ansiblePlaybook becomeUser: 'jenkins',
credentialsId:’your-cred-id’,
extras: "-e vaultAddress=<your-hashicorp-vault-address> -e gitBranch=<git-branch>",
installation: 'ansible',
inventory: '<path-to-your-inventory>',
playbook: '<path-to-your-ansible-script>'
}

}
}
}
```

Deploying the Application Using an Ansible Script
-------------------------------------------------

To build and deploy the application using an Ansible script, do as follows:

1. Add an Ansible script to the **deployment** folder in the root folder of your project.

>**Note**: Update the script with details (such as paths) that are specific to your project.

```
- hosts: <your-host>
vars:
project_path: <path-to-the-project-in-server>
root_path: <path-to-the-parent-folder-of-project>
//Add variables here if needed. (Remove this line in your code)
tasks:
- name: Slurp host file
slurp:
src: "<path-to-hashicorp-vault-token>"
register: slurpfile
- name: Run the HashiCorp Vault credentials
shell: "curl --location --request GET '{{ vaultAddress }}mentored-portal' --header 'X-Vault-Token: {{ slurpfile['content'] | b64decode }}' | jq '.data' > '{{root_path}}/data2.json'"
register: vaultCurl
- name: Change directory
shell: cd {{project_path}}
- name: Fetch the latest code
git:
repo: https://github.com/ELEVATE-Project/mentoring-mobile-app
dest: "{{project_path}}"
version: "{{gitBranch}}"
force: yes
- name: Update npm
shell: cd {{project_path}} && npm i --force
- name: Set permission
shell: chmod 744 {{ project_path }}/src/scripts/json2env.sh
- name: Generate .env
shell: cat {{root_path}}/data2.json | jq '.data' > {{ project_path }}/src/environments/environment.ts && sed -i '1s/^/export const environment = \n/' {{ project_path }}/src/environments/environment.ts
register: envConfig
- debug: msg=" cred {{ envConfig }} "
- name: Change directory
shell: chdir {{project_path}}
- name: Fetch pm2 config file
shell: "curl --location --request GET '{{ vaultAddress }}portalPm2Config' --header 'X-Vault-Token: {{ slurpfile['content'] | b64decode }}' | jq '.data.data' > '{{ project_path }}/pm2.config.json'"
register: pm2
- name: Change directory
shell: cd {{project_path}}
- name: Remove www folder
shell: rm -rf www
- name: Build pwa app
shell: cd {{project_path}} && ionic build --prod
- name: Start pm2
shell: cd {{project_path}} && pm2 start pm2.config.json
```

3. Add the script's path to the [Jenkins Pipeline script](#creating-a-jenkins-job). When you run the Jenkins job, the script is executed.

4. To convert the JSON file that was fetched from the HashiCorp Vault to an env format, add the following script to ```/src/scripts/json2env.sh.```:

```
#!/bin/sh

tr -d '\n' |
grep -o '"[A-Za-z\_][A-Za-z_0-9]\+"\s*:\s*\("[^"]\+"\|[0-9\.]\+\|true\|false\|null\)' |
sed 's/"\(._\)"\s_:\s\*"\?\([^"]\+\)"\?/\1= "\2"/'
```

Structure of Environment file, Server.js, and pm2.config.json
-------------------------------------------------------------

For deploying your application, you need an Environment file, Server.js, and a pm2.config.json file.

### Structure of environment.ts File

```jsx
export const environment = {
production: true / false,
name: "<name>",
staging: true / false,
dev: true / false,
baseUrl: "<base-url>",
sqliteDBName: "<db-name> (if you have)",
deepLinkUrl: "<deeplink-url>",
privacyPolicyUrl: "<privacy-policy-url>",
termsOfServiceUrl: "<term-of-service-url>",
};
```

### Structure of pm2.config.json File

```json
{
"apps": [
{
"name": "<APP_NAME>",
"script": "server.js",
"args": [],
"instances": "1",
"exec_mode": "cluster",
"watch": false,
"merge_logs": true,
"env": {
"NODE_ENV": "production",
"PORT": <PORT_NO>
}
}
]
}
```

### Structure of Server.js File

```jsx
const express = require('express');
const path = require('path');
const app = express();
const port = process.env.PORT || 7601;


app.use(express.static(path.join(__dirname, 'www')));


app.get('*', (req, res) => {
res.sendFile(path.join(__dirname, 'www', 'index.html'));
});

DEBUG APK
---------------------

- Open chrome and enter chrome://inspect
- Select app
app.listen(port, () => {
console.log(`Server is running on port ${port}`);
});
```
2 changes: 1 addition & 1 deletion src/app/pages/auth/otp/otp.page.html
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
</section>
<section>
<div class="d-flex flex-justify-center flex-align-items-center">
<ion-button [ngClass]="{'my-10': true, 'disabled': !recaptchaResolved , 'onboard-button':true}" [disabled]="!recaptchaResolved"
<ion-button [ngClass]="{'my-10': true, 'disabled': !recaptchaResolved && !enableGeneratetOtp, 'onboard-button':true}" [disabled]="!recaptchaResolved && !enableGeneratetOtp"
(click)="onSubmitGenerateOtp()" shape="round">
{{'GENERATE_OTP'|translate}}
</ion-button>
Expand Down
4 changes: 3 additions & 1 deletion src/app/pages/auth/otp/otp.page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ export class OtpPage implements OnInit {
captchaToken:any="";
recaptchaResolved: boolean = this.siteKey ? false : true;
showOtp:any = false;
enableGeneratetOtp: boolean = false;


constructor(private router: Router, private profileService: ProfileService,private location: Location, private activatedRoute: ActivatedRoute, private localStorage: LocalStorageService, private translateService: TranslateService, private authService: AuthService, private toast: ToastService, private menuCtrl: MenuController, private nav: NavController) {
Expand Down Expand Up @@ -119,7 +120,8 @@ export class OtpPage implements OnInit {
async resendOtp() {
this.enableResendOtp = false;
this.showOtp = false;
this.recaptchaResolved = false
this.recaptchaResolved = false;
this.enableGeneratetOtp = this.siteKey ? false : true;
}

async onSubmitGenerateOtp(){
Expand Down
7 changes: 5 additions & 2 deletions src/app/pages/session-detail/session-detail.page.html
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,11 @@ <h6 class="title-font">{{detailData?.data?.title}}</h6>
<ion-label *ngIf="endDate && detailData?.data?.status?.value=='COMPLETED'" class="date-label">{{"COMPLETED_ON"|translate}} {{endDate|date:'dd/MM/yyyy'}} {{"AT"|translate}} {{endDate|date:'shortTime'}}</ion-label>
</ion-item>
<div class="d-flex ion-no-padding" *ngIf="sessionManagerText && detailData.data.manager_name">
<ion-icon class="person-container" name="person"></ion-icon>
<p class="manager-text-container">{{ sessionManagerText | translate}} <span>{{detailData.data.manager_name}}</span></p>
<div class="invite-container">
<ion-icon class="person-container" name="person"></ion-icon>
<ion-label class="manager-text-container">{{ sessionManagerText | translate}}</ion-label>
<ion-label class="label">{{detailData.data.manager_name}}</ion-label>
</div>
</div>
</div>
<app-generic-details [sessionData]='detailData' (onViewList)="onViewList($event)"></app-generic-details>
Expand Down
Loading