diff --git a/src/app/app.routing.ts b/src/app/app.routing.ts
index 253a1dd3..28d97b62 100644
--- a/src/app/app.routing.ts
+++ b/src/app/app.routing.ts
@@ -97,6 +97,9 @@ export const appRoutes: Route[] = [
// Pages
{path: 'pages', children: [
+ // Activities
+ {path: 'activities', loadChildren: () => import('app/modules/admin/pages/activities/activities.module').then(m => m.ActivitiesModule)},
+
// Authentication
{path: 'authentication', loadChildren: () => import('app/modules/admin/pages/authentication/authentication.module').then(m => m.AuthenticationModule)},
diff --git a/src/app/mock-api/common/navigation/data.ts b/src/app/mock-api/common/navigation/data.ts
index 3823a2d3..05e50df0 100644
--- a/src/app/mock-api/common/navigation/data.ts
+++ b/src/app/mock-api/common/navigation/data.ts
@@ -151,6 +151,13 @@ export const defaultNavigation: FuseNavigationItem[] = [
type : 'group',
icon : 'heroicons_outline:document',
children: [
+ {
+ id : 'pages.activities',
+ title: 'Activities',
+ type : 'basic',
+ icon : 'heroicons_outline:menu-alt-2',
+ link : '/pages/activities'
+ },
{
id : 'pages.authentication',
title : 'Authentication',
diff --git a/src/app/mock-api/index.ts b/src/app/mock-api/index.ts
index 2dc55532..9d4e494c 100644
--- a/src/app/mock-api/index.ts
+++ b/src/app/mock-api/index.ts
@@ -1,4 +1,5 @@
import { AcademyMockApi } from 'app/mock-api/apps/academy/api';
+import { ActivitiesMockApi } from 'app/mock-api/pages/activities/api';
import { AnalyticsMockApi } from 'app/mock-api/dashboards/analytics/api';
import { AuthMockApi } from 'app/mock-api/common/auth/api';
import { CalendarMockApi } from 'app/mock-api/apps/calendar/api';
@@ -21,6 +22,7 @@ import { UserMockApi } from 'app/mock-api/common/user/api';
export const mockApiServices = [
AcademyMockApi,
+ ActivitiesMockApi,
AnalyticsMockApi,
AuthMockApi,
CalendarMockApi,
diff --git a/src/app/mock-api/pages/activities/api.ts b/src/app/mock-api/pages/activities/api.ts
new file mode 100644
index 00000000..c9b7997e
--- /dev/null
+++ b/src/app/mock-api/pages/activities/api.ts
@@ -0,0 +1,38 @@
+import { Injectable } from '@angular/core';
+import { cloneDeep } from 'lodash-es';
+import { FuseMockApiService } from '@fuse/lib/mock-api';
+import { activities as activitiesData } from 'app/mock-api/pages/activities/data';
+
+@Injectable({
+ providedIn: 'root'
+})
+export class ActivitiesMockApi
+{
+ private _activities: any = activitiesData;
+
+ /**
+ * Constructor
+ */
+ constructor(private _fuseMockApiService: FuseMockApiService)
+ {
+ // Register Mock API handlers
+ this.registerHandlers();
+ }
+
+ // -----------------------------------------------------------------------------------------------------
+ // @ Public methods
+ // -----------------------------------------------------------------------------------------------------
+
+ /**
+ * Register Mock API handlers
+ */
+ registerHandlers(): void
+ {
+ // -----------------------------------------------------------------------------------------------------
+ // @ Activities - GET
+ // -----------------------------------------------------------------------------------------------------
+ this._fuseMockApiService
+ .onGet('api/pages/activities')
+ .reply(() => [200, cloneDeep(this._activities)]);
+ }
+}
diff --git a/src/app/mock-api/pages/activities/data.ts b/src/app/mock-api/pages/activities/data.ts
new file mode 100644
index 00000000..3dde090a
--- /dev/null
+++ b/src/app/mock-api/pages/activities/data.ts
@@ -0,0 +1,87 @@
+/* eslint-disable */
+import * as moment from 'moment';
+import { Activity } from 'app/modules/admin/pages/activities/activities.types';
+
+export const activities: Activity[] = [
+ {
+ id : '493190c9-5b61-4912-afe5-78c21f1044d7',
+ icon : 'heroicons_solid:star',
+ description : 'Your submission has been accepted',
+ date : moment().subtract(25, 'minutes').toISOString(), // 25 minutes ago
+ extraContent: `
Congratulations for your acceptance!
+ Hi Brian,
Your submission has been accepted and you are ready to move into the next phase. Once you are ready, reach out to me and we will ...
`
+ },
+ {
+ id : '6e3e97e5-effc-4fb7-b730-52a151f0b641',
+ image : 'assets/images/avatars/male-04.jpg',
+ description : 'Leo Gill added you to Top Secret Project group and assigned you as a Project Manager',
+ date : moment().subtract(50, 'minutes').toISOString(), // 50 minutes ago
+ linkedContent: 'Top Secret Project',
+ link : '/dashboards/project',
+ useRouter : true
+ },
+ {
+ id : 'b91ccb58-b06c-413b-b389-87010e03a120',
+ icon : 'heroicons_solid:mail',
+ description : 'You have 15 unread mails across 3 mailboxes',
+ date : moment().subtract(3, 'hours').toISOString(), // 3 hours ago
+ linkedContent: 'Mailbox',
+ link : '/apps/mailbox',
+ useRouter : true
+ },
+ {
+ id : '541416c9-84a7-408a-8d74-27a43c38d797',
+ icon : 'heroicons_solid:refresh',
+ description : 'Your Docker container is ready to publish',
+ date : moment().subtract(5, 'hours').toISOString(), // 5 hours ago
+ linkedContent: 'Download the Container',
+ link : '.',
+ useRouter : true
+ },
+ {
+ id : 'ef7b95a7-8e8b-4616-9619-130d9533add9',
+ image : 'assets/images/avatars/male-06.jpg',
+ description: 'Roger Murray accepted your friend request',
+ date : moment().subtract(7, 'hours').toISOString() // 7 hours ago
+ },
+ {
+ id : 'eb8aa470-635e-461d-88e1-23d9ea2a5665',
+ image : 'assets/images/avatars/female-04.jpg',
+ description: 'Sophie Stone sent you a direct message',
+ date : moment().subtract(9, 'hours').toISOString() // 9 hours ago
+ },
+ {
+ id : 'b85c2338-cc98-4140-bbf8-c226ce4e395e',
+ icon : 'heroicons_solid:mail',
+ description : 'You have 3 new mails',
+ date : moment().subtract(1, 'day').toISOString(), // 1 day ago
+ extraContent: `
+
Please review and sign the attached agreement
+
Delivery address confirmation
+
Previous clients and their invoices
+
`,
+ linkedContent: 'Mailbox',
+ link : '/apps/mailbox',
+ useRouter : true
+ },
+ {
+ id : 'fd0f01b4-f3de-4333-add5-cd86850279f8',
+ image : 'assets/images/avatars/female-02.jpg',
+ description : 'Tina Harris started a chat with you',
+ date : moment().subtract(1, 'day').toISOString(), // 1 day ago,
+ linkedContent: 'Go to Chat (Tina Harris)',
+ link : '/apps/chat/5636c0ba-fa47-42ca-9160-27340583041e'
+ },
+ {
+ id : '8f8e1bf9-4661-4939-9e43-390957b60f42',
+ icon : 'heroicons_solid:star',
+ description: 'Your submission has been accepted and you are ready to sign-up for the final assigment which will be ready in 2 days',
+ date : moment().subtract(3, 'days').toISOString() // 3 days ago
+ },
+ {
+ id : '30af917b-7a6a-45d1-822f-9e7ad7f8bf69',
+ icon : 'heroicons_solid:refresh',
+ description: 'Your Vagrant container is ready to download',
+ date : moment().subtract(4, 'day').toISOString() // 4 days ago
+ }
+];
diff --git a/src/app/modules/admin/pages/activities/activities.component.html b/src/app/modules/admin/pages/activities/activities.component.html
new file mode 100644
index 00000000..1203299a
--- /dev/null
+++ b/src/app/modules/admin/pages/activities/activities.component.html
@@ -0,0 +1,117 @@
+
+
+
+
+
+
+
+
+
+
+
Application wide activities are listed here as individual items, starting with the most recent.
+
+
+
+
+
+
+
+
+
+
+ -
+
+ {{getRelativeFormat(activity.date)}}
+
+
+
+
+
+ -
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Loading...
+
+
+
+
+ There are is activity at the moment...
+
+
+
+
+
+
diff --git a/src/app/modules/admin/pages/activities/activities.component.ts b/src/app/modules/admin/pages/activities/activities.component.ts
new file mode 100644
index 00000000..07c8f5c6
--- /dev/null
+++ b/src/app/modules/admin/pages/activities/activities.component.ts
@@ -0,0 +1,87 @@
+import { ChangeDetectionStrategy, Component, OnInit, ViewEncapsulation } from '@angular/core';
+import { Observable } from 'rxjs';
+import * as moment from 'moment';
+import { Activity } from 'app/modules/admin/pages/activities/activities.types';
+import { ActivitiesService } from 'app/modules/admin/pages/activities/activities.service';
+
+@Component({
+ selector : 'activity',
+ templateUrl : './activities.component.html',
+ encapsulation : ViewEncapsulation.None,
+ changeDetection: ChangeDetectionStrategy.OnPush
+})
+export class ActivitiesComponent implements OnInit
+{
+ activities$: Observable;
+
+ /**
+ * Constructor
+ */
+ constructor(public _activityService: ActivitiesService)
+ {
+ }
+
+ // -----------------------------------------------------------------------------------------------------
+ // @ Lifecycle hooks
+ // -----------------------------------------------------------------------------------------------------
+
+ /**
+ * On init
+ */
+ ngOnInit(): void
+ {
+ // Get the activities
+ this.activities$ = this._activityService.activities;
+ }
+
+ // -----------------------------------------------------------------------------------------------------
+ // @ Public methods
+ // -----------------------------------------------------------------------------------------------------
+
+ /**
+ * Returns whether the given dates are different days
+ *
+ * @param current
+ * @param compare
+ */
+ isSameDay(current: string, compare: string): boolean
+ {
+ return moment(current, moment.ISO_8601).isSame(moment(compare, moment.ISO_8601), 'day');
+ }
+
+ /**
+ * Get the relative format of the given date
+ *
+ * @param date
+ */
+ getRelativeFormat(date: string): string
+ {
+ const today = moment().startOf('day');
+ const yesterday = moment().subtract(1, 'day').startOf('day');
+
+ // Is today?
+ if ( moment(date, moment.ISO_8601).isSame(today, 'day') )
+ {
+ return 'Today';
+ }
+
+ // Is yesterday?
+ if ( moment(date, moment.ISO_8601).isSame(yesterday, 'day') )
+ {
+ return 'Yesterday';
+ }
+
+ return moment(date, moment.ISO_8601).fromNow();
+ }
+
+ /**
+ * Track by function for ngFor loops
+ *
+ * @param index
+ * @param item
+ */
+ trackByFn(index: number, item: any): any
+ {
+ return item.id || index;
+ }
+}
diff --git a/src/app/modules/admin/pages/activities/activities.module.ts b/src/app/modules/admin/pages/activities/activities.module.ts
new file mode 100644
index 00000000..6b50ea31
--- /dev/null
+++ b/src/app/modules/admin/pages/activities/activities.module.ts
@@ -0,0 +1,20 @@
+import { NgModule } from '@angular/core';
+import { RouterModule } from '@angular/router';
+import { MatIconModule } from '@angular/material/icon';
+import { SharedModule } from 'app/shared/shared.module';
+import { ActivitiesComponent } from 'app/modules/admin/pages/activities/activities.component';
+import { activitiesRoutes } from 'app/modules/admin/pages/activities/activities.routing';
+
+@NgModule({
+ declarations: [
+ ActivitiesComponent
+ ],
+ imports : [
+ RouterModule.forChild(activitiesRoutes),
+ MatIconModule,
+ SharedModule
+ ]
+})
+export class ActivitiesModule
+{
+}
diff --git a/src/app/modules/admin/pages/activities/activities.resolvers.ts b/src/app/modules/admin/pages/activities/activities.resolvers.ts
new file mode 100644
index 00000000..f9c16d06
--- /dev/null
+++ b/src/app/modules/admin/pages/activities/activities.resolvers.ts
@@ -0,0 +1,32 @@
+import { Injectable } from '@angular/core';
+import { ActivatedRouteSnapshot, Resolve, RouterStateSnapshot } from '@angular/router';
+import { Observable } from 'rxjs';
+import { ActivitiesService } from 'app/modules/admin/pages/activities/activities.service';
+
+@Injectable({
+ providedIn: 'root'
+})
+export class ActivitiesResolver implements Resolve
+{
+ /**
+ * Constructor
+ */
+ constructor(private _activityService: ActivitiesService)
+ {
+ }
+
+ // -----------------------------------------------------------------------------------------------------
+ // @ Public methods
+ // -----------------------------------------------------------------------------------------------------
+
+ /**
+ * Resolve
+ *
+ * @param route
+ * @param state
+ */
+ resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable
+ {
+ return this._activityService.getActivities();
+ }
+}
diff --git a/src/app/modules/admin/pages/activities/activities.routing.ts b/src/app/modules/admin/pages/activities/activities.routing.ts
new file mode 100644
index 00000000..fd863a44
--- /dev/null
+++ b/src/app/modules/admin/pages/activities/activities.routing.ts
@@ -0,0 +1,13 @@
+import { Route } from '@angular/router';
+import { ActivitiesComponent } from 'app/modules/admin/pages/activities/activities.component';
+import { ActivitiesResolver } from 'app/modules/admin/pages/activities/activities.resolvers';
+
+export const activitiesRoutes: Route[] = [
+ {
+ path : '',
+ component: ActivitiesComponent,
+ resolve : {
+ activities: ActivitiesResolver
+ }
+ }
+];
diff --git a/src/app/modules/admin/pages/activities/activities.service.ts b/src/app/modules/admin/pages/activities/activities.service.ts
new file mode 100644
index 00000000..1e0cb62f
--- /dev/null
+++ b/src/app/modules/admin/pages/activities/activities.service.ts
@@ -0,0 +1,49 @@
+import { Injectable } from '@angular/core';
+import { HttpClient } from '@angular/common/http';
+import { BehaviorSubject, Observable } from 'rxjs';
+import { tap } from 'rxjs/operators';
+import { Activity } from 'app/modules/admin/pages/activities/activities.types';
+
+@Injectable({
+ providedIn: 'root'
+})
+export class ActivitiesService
+{
+ // Private
+ private _activities: BehaviorSubject = new BehaviorSubject(null);
+
+ /**
+ * Constructor
+ */
+ constructor(private _httpClient: HttpClient)
+ {
+ }
+
+ // -----------------------------------------------------------------------------------------------------
+ // @ Accessors
+ // -----------------------------------------------------------------------------------------------------
+
+ /**
+ * Getter for activities
+ */
+ get activities(): Observable
+ {
+ return this._activities.asObservable();
+ }
+
+ // -----------------------------------------------------------------------------------------------------
+ // @ Public methods
+ // -----------------------------------------------------------------------------------------------------
+
+ /**
+ * Get activities
+ */
+ getActivities(): Observable
+ {
+ return this._httpClient.get('api/pages/activities').pipe(
+ tap((response: Activity[]) => {
+ this._activities.next(response);
+ })
+ );
+ }
+}
diff --git a/src/app/modules/admin/pages/activities/activities.types.ts b/src/app/modules/admin/pages/activities/activities.types.ts
new file mode 100644
index 00000000..088ca35d
--- /dev/null
+++ b/src/app/modules/admin/pages/activities/activities.types.ts
@@ -0,0 +1,12 @@
+export interface Activity
+{
+ id: string;
+ icon?: string;
+ image?: string;
+ description?: string;
+ date: string;
+ extraContent?: string;
+ linkedContent?: string;
+ link?: string;
+ useRouter?: boolean;
+}