diff --git a/src/app/core/user/pages/about/about.html b/src/app/core/user/pages/about/about.html
new file mode 100644
index 000000000..c45d302d3
--- /dev/null
+++ b/src/app/core/user/pages/about/about.html
@@ -0,0 +1,97 @@
+
+
+
+
+
+ {{ title }}
+
+
+
+
+
+
+
+
+
+ {{ 'core.user.contact' | translate}}
+
+
+ {{ 'core.user.email' | translate }}
+
+ {{ user.email }}
+
+
+
+
+
+ {{ 'core.user.phone1' | translate}}
+
+ {{ user.phone1 }}
+
+
+
+
+
+ {{ 'core.user.phone2' | translate}}
+
+ {{ user.phone2 }}
+
+
+
+
+
+ {{ 'core.user.address' | translate}}
+
+ {{ user.address }}
+
+
+
+
+
+ {{ 'core.user.city' | translate}}
+ {{ user.city }}
+
+
+
+
+ {{ 'core.user.country' | translate}}
+ {{ user.country }}
+
+
+
+
+ {{ 'core.userdetails' | translate}}
+
+
+ {{ 'core.user.webpage' | translate}}
+
+ {{ user.url }}
+
+
+
+
+
+ {{ 'core.user.interests' | translate}}
+ {{ user.interests }}
+
+
+
+
+
+ {{ 'core.user.description' | translate}}
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/app/core/user/pages/about/about.page.module.ts b/src/app/core/user/pages/about/about.page.module.ts
new file mode 100644
index 000000000..daa3c8811
--- /dev/null
+++ b/src/app/core/user/pages/about/about.page.module.ts
@@ -0,0 +1,47 @@
+// (C) Copyright 2015 Moodle Pty Ltd.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+import { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { RouterModule, Routes } from '@angular/router';
+import { IonicModule } from '@ionic/angular';
+import { TranslateModule } from '@ngx-translate/core';
+
+import { CoreComponentsModule } from '@components/components.module';
+import { CoreDirectivesModule } from '@directives/directives.module';
+
+import { CoreUserAboutPage } from './about.page';
+
+const routes: Routes = [
+ {
+ path: '',
+ component: CoreUserAboutPage,
+ },
+];
+
+@NgModule({
+ imports: [
+ RouterModule.forChild(routes),
+ CommonModule,
+ IonicModule,
+ TranslateModule.forChild(),
+ CoreComponentsModule,
+ CoreDirectivesModule,
+ ],
+ declarations: [
+ CoreUserAboutPage,
+ ],
+ exports: [RouterModule],
+})
+export class CoreUserAboutPageModule {}
diff --git a/src/app/core/user/pages/about/about.page.ts b/src/app/core/user/pages/about/about.page.ts
new file mode 100644
index 000000000..c7730eb83
--- /dev/null
+++ b/src/app/core/user/pages/about/about.page.ts
@@ -0,0 +1,115 @@
+// (C) Copyright 2015 Moodle Pty Ltd.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+import { Component, OnInit } from '@angular/core';
+import { ActivatedRoute } from '@angular/router';
+import { SafeUrl } from '@angular/platform-browser';
+import { IonRefresher } from '@ionic/angular';
+
+import { CoreSites } from '@services/sites';
+import { CoreDomUtils } from '@services/utils/dom';
+import { CoreTextUtils } from '@services/utils/text';
+import { CoreUtils } from '@services/utils/utils';
+import { CoreEvents } from '@singletons/events';
+import { CoreUser, CoreUserProfile, CoreUserProfileRefreshedData, CoreUserProvider } from '@core/user/services/user';
+import { CoreUserHelper } from '@core/user/services/user.helper';
+
+/**
+ * Page that displays info about a user.
+ */
+@Component({
+ selector: 'page-core-user-about',
+ templateUrl: 'about.html',
+})
+export class CoreUserAboutPage implements OnInit {
+
+ protected courseId!: number;
+ protected userId!: number;
+ protected siteId: string;
+
+ userLoaded = false;
+ hasContact = false;
+ hasDetails = false;
+ user?: CoreUserProfile;
+ title?: string;
+ formattedAddress?: string;
+ encodedAddress?: SafeUrl;
+
+ constructor(
+ protected route: ActivatedRoute,
+ ) {
+ this.siteId = CoreSites.instance.getCurrentSiteId();
+ }
+
+ /**
+ * On init.
+ *
+ * @return Promise resolved when done.
+ */
+ async ngOnInit(): Promise {
+ this.userId = this.route.snapshot.queryParams['userId'];
+ this.courseId = this.route.snapshot.queryParams['courseId'];
+
+ this.fetchUser().finally(() => {
+ this.userLoaded = true;
+ });
+ }
+
+ /**
+ * Fetches the user data.
+ *
+ * @return Promise resolved when done.
+ */
+ async fetchUser(): Promise {
+ try {
+ const user = await CoreUser.instance.getProfile(this.userId, this.courseId);
+
+ if (user.address) {
+ this.formattedAddress = CoreUserHelper.instance.formatAddress(user.address, user.city, user.country);
+ this.encodedAddress = CoreTextUtils.instance.buildAddressURL(user.address);
+ }
+
+ this.hasContact = !!(user.email || user.phone1 || user.phone2 || user.city || user.country || user.address);
+ this.hasDetails = !!(user.url || user.interests || (user.customfields && user.customfields.length > 0));
+
+ this.user = user;
+ this.title = user.fullname;
+ } catch (error) {
+ CoreDomUtils.instance.showErrorModalDefault(error, 'core.user.errorloaduser', true);
+ }
+ }
+
+ /**
+ * Refresh the user data.
+ *
+ * @param event Event.
+ * @return Promise resolved when done.
+ */
+ async refreshUser(event?: CustomEvent): Promise {
+ await CoreUtils.instance.ignoreErrors(CoreUser.instance.invalidateUserCache(this.userId));
+
+ await this.fetchUser();
+
+ event?.detail.complete();
+
+ if (this.user) {
+ CoreEvents.trigger(CoreUserProvider.PROFILE_REFRESHED, {
+ courseId: this.courseId,
+ userId: this.userId,
+ user: this.user,
+ }, this.siteId);
+ }
+ }
+
+}
diff --git a/src/app/core/user/user-routing.module.ts b/src/app/core/user/user-routing.module.ts
index 0d117604f..75a460cd6 100644
--- a/src/app/core/user/user-routing.module.ts
+++ b/src/app/core/user/user-routing.module.ts
@@ -25,6 +25,10 @@ const routes: Routes = [
path: 'profile',
loadChildren: () => import('./pages/profile/profile.page.module').then( m => m.CoreUserProfilePageModule),
},
+ {
+ path: 'about',
+ loadChildren: () => import('./pages/about/about.page.module').then( m => m.CoreUserAboutPageModule),
+ },
];
@NgModule({
diff --git a/src/theme/app.scss b/src/theme/app.scss
index f48f74a42..66a988c47 100644
--- a/src/theme/app.scss
+++ b/src/theme/app.scss
@@ -261,3 +261,9 @@ ion-select.core-button-select,
z-index: 100;
cursor: pointer;
}
+
+.core-anchor, core-format-text a {
+ color: -webkit-link;
+ cursor: pointer;
+ text-decoration: underline;
+}