From 3b727fe859e009a8703e2d76dcf8afb12cba5b30 Mon Sep 17 00:00:00 2001 From: sercan Date: Thu, 20 May 2021 15:30:14 +0300 Subject: [PATCH] (pages/activities) Added Activities page (timeline) --- src/app/app.routing.ts | 3 + src/app/mock-api/common/navigation/data.ts | 7 ++ src/app/mock-api/index.ts | 2 + src/app/mock-api/pages/activities/api.ts | 38 ++++++ src/app/mock-api/pages/activities/data.ts | 87 +++++++++++++ .../activities/activities.component.html | 117 ++++++++++++++++++ .../pages/activities/activities.component.ts | 87 +++++++++++++ .../pages/activities/activities.module.ts | 20 +++ .../pages/activities/activities.resolvers.ts | 32 +++++ .../pages/activities/activities.routing.ts | 13 ++ .../pages/activities/activities.service.ts | 49 ++++++++ .../pages/activities/activities.types.ts | 12 ++ 12 files changed, 467 insertions(+) create mode 100644 src/app/mock-api/pages/activities/api.ts create mode 100644 src/app/mock-api/pages/activities/data.ts create mode 100644 src/app/modules/admin/pages/activities/activities.component.html create mode 100644 src/app/modules/admin/pages/activities/activities.component.ts create mode 100644 src/app/modules/admin/pages/activities/activities.module.ts create mode 100644 src/app/modules/admin/pages/activities/activities.resolvers.ts create mode 100644 src/app/modules/admin/pages/activities/activities.routing.ts create mode 100644 src/app/modules/admin/pages/activities/activities.service.ts create mode 100644 src/app/modules/admin/pages/activities/activities.types.ts 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 @@ +
+ + +
+ + +
+ + +
All Activities
+
Application wide activities are listed here as individual items, starting with the most recent.
+ + + +
+
    + + + + + +
  1. +
    + {{getRelativeFormat(activity.date)}} +
    +
  2. +
    + + +
  3. + + +
    +
    + +
    + + +
    + + +
    +
    + + + + + + + +
    + + +
    +
    +
    + +
    + {{activity.date | date:'MMM dd, h:mm a'}} +
    + + + + + + + {{activity.linkedContent}} + + + + + + {{activity.linkedContent}} + + + +
    + + +
    +
    +
    +
    +
  4. +
    +
+
+
+
+ + + + 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; +}