mirror of
https://github.com/akveo/ngx-admin.git
synced 2025-12-16 07:30:12 +01:00
Final state from MSSE692
This commit is contained in:
parent
5f18537bd5
commit
43c7198f22
41 changed files with 816 additions and 218 deletions
36
package-lock.json
generated
36
package-lock.json
generated
|
|
@ -49,6 +49,7 @@
|
|||
"rxjs-compat": "6.3.0",
|
||||
"socicon": "3.0.5",
|
||||
"style-loader": "^1.1.3",
|
||||
"thingbook-api": "^1.0.14",
|
||||
"tinymce": "4.5.7",
|
||||
"tslib": "^2.0.0",
|
||||
"typeface-exo": "0.0.22",
|
||||
|
|
@ -649,6 +650,7 @@
|
|||
"resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-11.0.4.tgz",
|
||||
"integrity": "sha512-suhAhsZEv+lLwm8dc524cMvO7gHPi+z2+4tueNS+zDiIObdZc4fs+KoOlnRMdYwba++X/V8mHXuDEQetl3GFcw==",
|
||||
"dependencies": {
|
||||
"parse5": "^5.0.0",
|
||||
"tslib": "^2.0.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
|
|
@ -911,6 +913,7 @@
|
|||
"dependencies": {
|
||||
"anymatch": "~3.1.1",
|
||||
"braces": "~3.0.2",
|
||||
"fsevents": "~2.3.1",
|
||||
"glob-parent": "~5.1.0",
|
||||
"is-binary-path": "~2.1.0",
|
||||
"is-glob": "~4.0.1",
|
||||
|
|
@ -4780,6 +4783,7 @@
|
|||
"dependencies": {
|
||||
"anymatch": "^1.3.0",
|
||||
"async-each": "^1.0.0",
|
||||
"fsevents": "^1.0.0",
|
||||
"glob-parent": "^2.0.0",
|
||||
"inherits": "^2.0.1",
|
||||
"is-binary-path": "^1.0.0",
|
||||
|
|
@ -10966,7 +10970,8 @@
|
|||
"dependencies": {
|
||||
"async": "^1.4.0",
|
||||
"optimist": "^0.6.1",
|
||||
"source-map": "^0.4.4"
|
||||
"source-map": "^0.4.4",
|
||||
"uglify-js": "^2.6"
|
||||
},
|
||||
"bin": {
|
||||
"handlebars": "bin/handlebars"
|
||||
|
|
@ -13695,6 +13700,7 @@
|
|||
"dependencies": {
|
||||
"anymatch": "~3.1.1",
|
||||
"braces": "~3.0.2",
|
||||
"fsevents": "~2.3.1",
|
||||
"glob-parent": "~5.1.0",
|
||||
"is-binary-path": "~2.1.0",
|
||||
"is-glob": "~4.0.1",
|
||||
|
|
@ -14220,8 +14226,11 @@
|
|||
"dependencies": {
|
||||
"errno": "^0.1.1",
|
||||
"graceful-fs": "^4.1.2",
|
||||
"image-size": "~0.5.0",
|
||||
"make-dir": "^2.1.0",
|
||||
"mime": "^1.4.1",
|
||||
"native-request": "^1.0.5",
|
||||
"source-map": "~0.6.0",
|
||||
"tslib": "^1.10.0"
|
||||
},
|
||||
"bin": {
|
||||
|
|
@ -21141,6 +21150,9 @@
|
|||
"resolved": "https://registry.npmjs.org/rollup/-/rollup-2.32.1.tgz",
|
||||
"integrity": "sha512-Op2vWTpvK7t6/Qnm1TTh7VjEZZkN8RWgf0DHbkKzQBwNf748YhXbozHVefqpPp/Fuyk/PQPAnYsBxAEtlMvpUw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"fsevents": "~2.1.2"
|
||||
},
|
||||
"bin": {
|
||||
"rollup": "dist/bin/rollup"
|
||||
},
|
||||
|
|
@ -21493,6 +21505,7 @@
|
|||
"dependencies": {
|
||||
"anymatch": "~3.1.1",
|
||||
"braces": "~3.0.2",
|
||||
"fsevents": "~2.3.1",
|
||||
"glob-parent": "~5.1.0",
|
||||
"is-binary-path": "~2.1.0",
|
||||
"is-glob": "~4.0.1",
|
||||
|
|
@ -22832,8 +22845,12 @@
|
|||
"dependencies": {
|
||||
"asn1": "~0.2.3",
|
||||
"assert-plus": "^1.0.0",
|
||||
"bcrypt-pbkdf": "^1.0.0",
|
||||
"dashdash": "^1.12.0",
|
||||
"getpass": "^0.1.1"
|
||||
"ecc-jsbn": "~0.1.1",
|
||||
"getpass": "^0.1.1",
|
||||
"jsbn": "~0.1.0",
|
||||
"tweetnacl": "~0.14.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
|
|
@ -24353,6 +24370,11 @@
|
|||
"integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/thingbook-api": {
|
||||
"version": "1.0.14",
|
||||
"resolved": "https://registry.npmjs.org/thingbook-api/-/thingbook-api-1.0.14.tgz",
|
||||
"integrity": "sha512-nX72Sa2SM13Hg1W8PTbJ+IIvoynCNDwTcTEXNScQLrw16b6QcgCRaVJ69W4tzxb0sFffzDN7+xcPoewl//syxg=="
|
||||
},
|
||||
"node_modules/through": {
|
||||
"version": "2.3.8",
|
||||
"resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
|
||||
|
|
@ -25412,8 +25434,10 @@
|
|||
"integrity": "sha512-9P3MWk6SrKjHsGkLT2KHXdQ/9SNkyoJbabxnKOoJepsvJjJG8uYTR3yTPxPQvNDI3w4Nz1xnE0TLHK4RIVe/MQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"chokidar": "^3.4.1",
|
||||
"graceful-fs": "^4.1.2",
|
||||
"neo-async": "^2.5.0"
|
||||
"neo-async": "^2.5.0",
|
||||
"watchpack-chokidar2": "^2.0.1"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"chokidar": "^3.4.1",
|
||||
|
|
@ -26366,6 +26390,7 @@
|
|||
"anymatch": "^2.0.0",
|
||||
"async-each": "^1.0.1",
|
||||
"braces": "^2.3.2",
|
||||
"fsevents": "^1.2.7",
|
||||
"glob-parent": "^3.1.0",
|
||||
"inherits": "^2.0.3",
|
||||
"is-binary-path": "^1.0.0",
|
||||
|
|
@ -48529,6 +48554,11 @@
|
|||
"integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=",
|
||||
"dev": true
|
||||
},
|
||||
"thingbook-api": {
|
||||
"version": "1.0.14",
|
||||
"resolved": "https://registry.npmjs.org/thingbook-api/-/thingbook-api-1.0.14.tgz",
|
||||
"integrity": "sha512-nX72Sa2SM13Hg1W8PTbJ+IIvoynCNDwTcTEXNScQLrw16b6QcgCRaVJ69W4tzxb0sFffzDN7+xcPoewl//syxg=="
|
||||
},
|
||||
"through": {
|
||||
"version": "2.3.8",
|
||||
"resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
|
||||
|
|
|
|||
|
|
@ -4,15 +4,15 @@
|
|||
"license": "MIT",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/akveo/ngx-admin.git"
|
||||
"url": "git+https://github.com/kerry-t-johnson/thingbook-ui"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/akveo/ngx-admin/issues"
|
||||
"url": "https://github.com/kerry-t-johnson/thingbook-ui/issues"
|
||||
},
|
||||
"scripts": {
|
||||
"ng": "ng",
|
||||
"conventional-changelog": "conventional-changelog",
|
||||
"start": "ng serve",
|
||||
"start": "ng serve --host 0.0.0.0",
|
||||
"build": "ng build",
|
||||
"build:prod": "npm run build -- --prod --aot",
|
||||
"test": "ng test",
|
||||
|
|
@ -70,6 +70,7 @@
|
|||
"rxjs-compat": "6.3.0",
|
||||
"socicon": "3.0.5",
|
||||
"style-loader": "^1.1.3",
|
||||
"thingbook-api": "^1.0.14",
|
||||
"tinymce": "4.5.7",
|
||||
"tslib": "^2.0.0",
|
||||
"typeface-exo": "0.0.22",
|
||||
|
|
|
|||
|
|
@ -12,7 +12,6 @@ import {
|
|||
SeoService,
|
||||
StateService,
|
||||
} from './utils';
|
||||
import { UserData } from './data/users';
|
||||
import { ElectricityData } from './data/electricity';
|
||||
import { SmartTableData } from './data/smart-table';
|
||||
import { UserActivityData } from './data/user-activity';
|
||||
|
|
@ -32,7 +31,6 @@ import { StatsProgressBarData } from './data/stats-progress-bar';
|
|||
import { VisitorsAnalyticsData } from './data/visitors-analytics';
|
||||
import { SecurityCamerasData } from './data/security-cameras';
|
||||
|
||||
import { UserService } from './mock/users.service';
|
||||
import { ElectricityService } from './mock/electricity.service';
|
||||
import { SmartTableService } from './mock/smart-table.service';
|
||||
import { UserActivityService } from './mock/user-activity.service';
|
||||
|
|
@ -72,7 +70,6 @@ const socialLinks = [
|
|||
];
|
||||
|
||||
const DATA_SERVICES = [
|
||||
{ provide: UserData, useClass: UserService },
|
||||
{ provide: ElectricityData, useClass: ElectricityService },
|
||||
{ provide: SmartTableData, useClass: SmartTableService },
|
||||
{ provide: UserActivityData, useClass: UserActivityService },
|
||||
|
|
|
|||
|
|
@ -1,21 +0,0 @@
|
|||
import { Observable } from 'rxjs';
|
||||
|
||||
export interface User {
|
||||
name: string;
|
||||
picture: string;
|
||||
}
|
||||
|
||||
export interface Contacts {
|
||||
user: User;
|
||||
type: string;
|
||||
}
|
||||
|
||||
export interface RecentUsers extends Contacts {
|
||||
time: number;
|
||||
}
|
||||
|
||||
export abstract class UserData {
|
||||
abstract getUsers(): Observable<User[]>;
|
||||
abstract getContacts(): Observable<Contacts[]>;
|
||||
abstract getRecentUsers(): Observable<RecentUsers[]>;
|
||||
}
|
||||
|
|
@ -1,7 +1,6 @@
|
|||
import { NgModule, ModuleWithProviders } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
|
||||
import { UserService } from './users.service';
|
||||
import { ElectricityService } from './electricity.service';
|
||||
import { SmartTableService } from './smart-table.service';
|
||||
import { UserActivityService } from './user-activity.service';
|
||||
|
|
@ -23,7 +22,6 @@ import { VisitorsAnalyticsService } from './visitors-analytics.service';
|
|||
import { SecurityCamerasService } from './security-cameras.service';
|
||||
|
||||
const SERVICES = [
|
||||
UserService,
|
||||
ElectricityService,
|
||||
SmartTableService,
|
||||
UserActivityService,
|
||||
|
|
|
|||
|
|
@ -1,53 +0,0 @@
|
|||
import { of as observableOf, Observable } from 'rxjs';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Contacts, RecentUsers, UserData } from '../data/users';
|
||||
|
||||
@Injectable()
|
||||
export class UserService extends UserData {
|
||||
|
||||
private time: Date = new Date;
|
||||
|
||||
private users = {
|
||||
nick: { name: 'Nick Jones', picture: 'assets/images/nick.png' },
|
||||
eva: { name: 'Eva Moor', picture: 'assets/images/eva.png' },
|
||||
jack: { name: 'Jack Williams', picture: 'assets/images/jack.png' },
|
||||
lee: { name: 'Lee Wong', picture: 'assets/images/lee.png' },
|
||||
alan: { name: 'Alan Thompson', picture: 'assets/images/alan.png' },
|
||||
kate: { name: 'Kate Martinez', picture: 'assets/images/kate.png' },
|
||||
};
|
||||
private types = {
|
||||
mobile: 'mobile',
|
||||
home: 'home',
|
||||
work: 'work',
|
||||
};
|
||||
private contacts: Contacts[] = [
|
||||
{ user: this.users.nick, type: this.types.mobile },
|
||||
{ user: this.users.eva, type: this.types.home },
|
||||
{ user: this.users.jack, type: this.types.mobile },
|
||||
{ user: this.users.lee, type: this.types.mobile },
|
||||
{ user: this.users.alan, type: this.types.home },
|
||||
{ user: this.users.kate, type: this.types.work },
|
||||
];
|
||||
private recentUsers: RecentUsers[] = [
|
||||
{ user: this.users.alan, type: this.types.home, time: this.time.setHours(21, 12)},
|
||||
{ user: this.users.eva, type: this.types.home, time: this.time.setHours(17, 45)},
|
||||
{ user: this.users.nick, type: this.types.mobile, time: this.time.setHours(5, 29)},
|
||||
{ user: this.users.lee, type: this.types.mobile, time: this.time.setHours(11, 24)},
|
||||
{ user: this.users.jack, type: this.types.mobile, time: this.time.setHours(10, 45)},
|
||||
{ user: this.users.kate, type: this.types.work, time: this.time.setHours(9, 42)},
|
||||
{ user: this.users.kate, type: this.types.work, time: this.time.setHours(9, 31)},
|
||||
{ user: this.users.jack, type: this.types.mobile, time: this.time.setHours(8, 0)},
|
||||
];
|
||||
|
||||
getUsers(): Observable<any> {
|
||||
return observableOf(this.users);
|
||||
}
|
||||
|
||||
getContacts(): Observable<Contacts[]> {
|
||||
return observableOf(this.contacts);
|
||||
}
|
||||
|
||||
getRecentUsers(): Observable<RecentUsers[]> {
|
||||
return observableOf(this.recentUsers);
|
||||
}
|
||||
}
|
||||
|
|
@ -3,7 +3,7 @@
|
|||
<a (click)="toggleSidebar()" href="#" class="sidebar-toggle">
|
||||
<nb-icon icon="menu-2-outline"></nb-icon>
|
||||
</a>
|
||||
<a class="logo" href="#" (click)="navigateHome()">ngx-<span>admin</span></a>
|
||||
<a class="logo" href="#" (click)="navigateHome()">Thing<span>Book</span></a>
|
||||
</div>
|
||||
<nb-select [selected]="currentTheme" (selectedChange)="changeTheme($event)" status="primary">
|
||||
<nb-option *ngFor="let theme of themes" [value]="theme.value"> {{ theme.name }}</nb-option>
|
||||
|
|
@ -18,12 +18,10 @@
|
|||
</nb-action>
|
||||
<nb-action class="control-item" icon="email-outline"></nb-action>
|
||||
<nb-action class="control-item" icon="bell-outline"></nb-action>
|
||||
<nb-action class="user-action" *nbIsGranted="['view', 'user']" >
|
||||
<nb-user [nbContextMenu]="userMenu"
|
||||
[onlyPicture]="userPictureOnly"
|
||||
[name]="user?.name"
|
||||
[picture]="user?.picture">
|
||||
<nb-action class="user-action" *nbIsGranted="['view', 'user']">
|
||||
<nb-user [nbContextMenu]="userMenu" [onlyPicture]="userPictureOnly" [name]="displayName"
|
||||
[picture]="user?.picture">
|
||||
</nb-user>
|
||||
</nb-action>
|
||||
</nb-actions>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -1,10 +1,10 @@
|
|||
import { Component, OnDestroy, OnInit } from '@angular/core';
|
||||
import { NbMediaBreakpointsService, NbMenuService, NbSidebarService, NbThemeService } from '@nebular/theme';
|
||||
|
||||
import { UserData } from '../../../@core/data/users';
|
||||
import { LayoutService } from '../../../@core/utils';
|
||||
import { map, takeUntil } from 'rxjs/operators';
|
||||
import { Subject } from 'rxjs';
|
||||
import { UserService, User } from '../../../modules/user/user.service';
|
||||
|
||||
@Component({
|
||||
selector: 'ngx-header',
|
||||
|
|
@ -15,45 +15,40 @@ export class HeaderComponent implements OnInit, OnDestroy {
|
|||
|
||||
private destroy$: Subject<void> = new Subject<void>();
|
||||
userPictureOnly: boolean = false;
|
||||
user: any;
|
||||
user: User;
|
||||
displayName: string;
|
||||
|
||||
themes = [
|
||||
{
|
||||
value: 'default',
|
||||
name: 'Light',
|
||||
},
|
||||
{
|
||||
value: 'dark',
|
||||
name: 'Dark',
|
||||
},
|
||||
{
|
||||
value: 'cosmic',
|
||||
name: 'Cosmic',
|
||||
},
|
||||
{
|
||||
value: 'corporate',
|
||||
name: 'Corporate',
|
||||
},
|
||||
{ value: 'default', name: 'Light', },
|
||||
{ value: 'dark', name: 'Dark', },
|
||||
{ value: 'cosmic', name: 'Cosmic', },
|
||||
{ value: 'corporate', name: 'Corporate', },
|
||||
];
|
||||
|
||||
currentTheme = 'default';
|
||||
|
||||
userMenu = [ { title: 'Profile' }, { title: 'Log out' } ];
|
||||
userMenu = [
|
||||
{ title: 'Profile', icon: 'person-outline', link: 'pages/user/profile', },
|
||||
{ title: 'Log out' }
|
||||
];
|
||||
|
||||
constructor(private sidebarService: NbSidebarService,
|
||||
private menuService: NbMenuService,
|
||||
private themeService: NbThemeService,
|
||||
private userService: UserData,
|
||||
private layoutService: LayoutService,
|
||||
private breakpointService: NbMediaBreakpointsService) {
|
||||
private menuService: NbMenuService,
|
||||
private themeService: NbThemeService,
|
||||
private userService: UserService,
|
||||
private layoutService: LayoutService,
|
||||
private breakpointService: NbMediaBreakpointsService) {
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.currentTheme = this.themeService.currentTheme;
|
||||
|
||||
this.userService.getUsers()
|
||||
this.userService.onUserStatus()
|
||||
.pipe(takeUntil(this.destroy$))
|
||||
.subscribe((users: any) => this.user = users.nick);
|
||||
.subscribe((user: any) => {
|
||||
this.user = user;
|
||||
this.displayName = user?.first ?? user?.email;
|
||||
});
|
||||
|
||||
const { xl } = this.breakpointService.getBreakpointsMap();
|
||||
this.themeService.onMediaQueryChange()
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
import { BrowserModule } from '@angular/platform-browser';
|
||||
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { HttpClientModule } from '@angular/common/http';
|
||||
import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http';
|
||||
import { CoreModule } from './@core/core.module';
|
||||
import { ThemeModule } from './@theme/theme.module';
|
||||
import { AppComponent } from './app.component';
|
||||
|
|
@ -15,14 +15,19 @@ import {
|
|||
NbChatModule,
|
||||
NbDatepickerModule,
|
||||
NbDialogModule,
|
||||
NbIconModule,
|
||||
NbMenuModule,
|
||||
NbSidebarModule,
|
||||
NbToastrModule,
|
||||
NbWindowModule,
|
||||
} from '@nebular/theme';
|
||||
|
||||
import { UserModule } from './modules/user/user.module';
|
||||
|
||||
@NgModule({
|
||||
declarations: [AppComponent],
|
||||
declarations: [
|
||||
AppComponent,
|
||||
],
|
||||
imports: [
|
||||
BrowserModule,
|
||||
BrowserAnimationsModule,
|
||||
|
|
@ -32,6 +37,7 @@ import {
|
|||
NbMenuModule.forRoot(),
|
||||
NbDatepickerModule.forRoot(),
|
||||
NbDialogModule.forRoot(),
|
||||
NbIconModule,
|
||||
NbWindowModule.forRoot(),
|
||||
NbToastrModule.forRoot(),
|
||||
NbChatModule.forRoot({
|
||||
|
|
@ -39,8 +45,11 @@ import {
|
|||
}),
|
||||
CoreModule.forRoot(),
|
||||
ThemeModule.forRoot(),
|
||||
UserModule.forRoot(),
|
||||
|
||||
],
|
||||
bootstrap: [AppComponent],
|
||||
providers: []
|
||||
})
|
||||
export class AppModule {
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,34 @@
|
|||
<nb-card>
|
||||
<nb-card-header>
|
||||
<span class="col-lg-10">{{agreement?.name}}</span>
|
||||
<span class="col-lg-1">
|
||||
<nb-icon icon="activity" [status]='agreement?.state == "ACTIVE" ? "success" : "danger" '>
|
||||
</nb-icon>
|
||||
</span>
|
||||
</nb-card-header>
|
||||
<nb-card-body>
|
||||
<div>
|
||||
<span>{{agreement?.producer.name}}<nb-icon icon="arrowhead-right"></nb-icon>
|
||||
{{agreement?.consumer.name}}</span>
|
||||
</div>
|
||||
<div>
|
||||
<app-date-calendar [date]="agreement?.commenceDate"></app-date-calendar>
|
||||
<app-date-calendar [date]="agreement?.expirationDate"></app-date-calendar>
|
||||
</div>
|
||||
<div>
|
||||
<nb-accordion>
|
||||
<nb-accordion-item *ngFor="let fragment of agreement.template.template.fragments">
|
||||
<nb-accordion-item-header>
|
||||
{{ fragment.name }}
|
||||
<span style="justify-content: flex-end;">
|
||||
{{ fragment.type | titlecase}}
|
||||
</span>
|
||||
</nb-accordion-item-header>
|
||||
<nb-accordion-item-body>
|
||||
{{fragment.text}}
|
||||
</nb-accordion-item-body>
|
||||
</nb-accordion-item>
|
||||
</nb-accordion>
|
||||
</div>
|
||||
</nb-card-body>
|
||||
</nb-card>
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
import { Component, Input, OnInit } from "@angular/core";
|
||||
import { OrganizationDataSharingAgreement } from "thingbook-api/lib";
|
||||
import { OrganizationService } from "../../organization.service";
|
||||
|
||||
@Component({
|
||||
selector: 'org-data-sharing-agreement',
|
||||
templateUrl: './data-sharing-agreement.component.html',
|
||||
styleUrls: ['./data-sharing-agreement.component.scss']
|
||||
})
|
||||
export class DataSharingAgreementComponent implements OnInit {
|
||||
|
||||
@Input() agreement: OrganizationDataSharingAgreement;
|
||||
|
||||
constructor() {
|
||||
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
<h3>{{org?.name}}</h3>
|
||||
<nb-tabset fullWidth="true">
|
||||
<nb-tab tabTitle="Data Sharing Agreements ({{ agreements?.length }})" class="container">
|
||||
<ng-container *ngIf="agreements?.length > 0; else loading">
|
||||
<nb-list class="col-lg-12">
|
||||
<nb-list-item *ngFor="let a of agreements; odd as odd; even as even;"
|
||||
[ngClass]="{row: true, odd: odd, even: even}">
|
||||
<org-data-sharing-agreement [agreement]="a"></org-data-sharing-agreement>
|
||||
</nb-list-item>
|
||||
</nb-list>
|
||||
</ng-container>
|
||||
<ng-template #loading>
|
||||
<div>Loading...</div>
|
||||
</ng-template>
|
||||
</nb-tab>
|
||||
<nb-tab tabTitle="Data Sharing Templates">
|
||||
<span>TBD</span>
|
||||
</nb-tab>
|
||||
</nb-tabset>
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
import { Component, OnInit } from "@angular/core";
|
||||
import { ActivatedRoute, ParamMap } from "@angular/router";
|
||||
import { switchMap } from "rxjs/operators";
|
||||
import { Organization, OrganizationDataSharingAgreement } from "thingbook-api/lib";
|
||||
import { OrganizationService } from "../../organization.service";
|
||||
|
||||
@Component({
|
||||
selector: 'org-detail',
|
||||
templateUrl: './detail-page.component.html',
|
||||
styleUrls: ['./detail-page.component.scss'],
|
||||
})
|
||||
export class OrganizationDetailPageComponent implements OnInit {
|
||||
|
||||
org: Organization;
|
||||
agreements: OrganizationDataSharingAgreement[] = [];
|
||||
|
||||
constructor(private route: ActivatedRoute, private orgSvc: OrganizationService) {
|
||||
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.route.paramMap.pipe(
|
||||
switchMap((params: ParamMap) => {
|
||||
return this.orgSvc.getOrganization(params.get('id'));
|
||||
})
|
||||
).subscribe(org => this.org = org);
|
||||
|
||||
this.route.paramMap.pipe(
|
||||
switchMap((params: ParamMap) => {
|
||||
return this.orgSvc.getOrganizationAgreements(params.get('id'));
|
||||
})
|
||||
).subscribe(agreements => {
|
||||
this.agreements = agreements;
|
||||
console.log(agreements);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
<div class="lists row">
|
||||
<div class="col-md-12 col-lg-12 col-xxxl-12">
|
||||
<nb-card class="list-card">
|
||||
<nb-card-header>Organizations</nb-card-header>
|
||||
<nb-card-body>
|
||||
<nb-list>
|
||||
<nb-list-item *ngFor="let o of orgs">
|
||||
<span class="col-sm-6">{{o.name}}</span>
|
||||
<span class="col-sm-3">{{o.domainName}}</span>
|
||||
<app-verification-icon [value]=o?.verification?.verified></app-verification-icon>
|
||||
<a [routerLink]="['/pages/org', o._id]"><span class="col-sm-2">Details...</span></a>
|
||||
</nb-list-item>
|
||||
</nb-list>
|
||||
</nb-card-body>
|
||||
</nb-card>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
@import '../../../../@theme/styles/themes';
|
||||
|
||||
@include nb-install-component() {
|
||||
.list-card {
|
||||
nb-card-header {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
nb-card-body {
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
import { Component, OnInit } from "@angular/core";
|
||||
import { Organization } from "thingbook-api/lib";
|
||||
import { OrganizationService } from "../../organization.service";
|
||||
|
||||
@Component({
|
||||
selector: 'organization-list',
|
||||
templateUrl: './list-page.component.html',
|
||||
styleUrls: ['./list-page.component.scss']
|
||||
})
|
||||
export class OrganizationListPageComponent implements OnInit {
|
||||
|
||||
orgs: Organization[];
|
||||
|
||||
constructor(private orgSvc: OrganizationService) {
|
||||
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.orgSvc.getOrganizations()
|
||||
.subscribe(orgs => {
|
||||
this.orgs = orgs;
|
||||
console.log(this.orgs);
|
||||
});
|
||||
}
|
||||
}
|
||||
34
src/app/modules/organization/organization.module.ts
Normal file
34
src/app/modules/organization/organization.module.ts
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { RouterModule } from '@angular/router';
|
||||
import { OrganizationListPageComponent } from './components/list-page/list-page.component';
|
||||
import { NbAccordionModule, NbCardModule, NbIconModule, NbListModule, NbTabsetModule } from '@nebular/theme';
|
||||
import { ThemeModule } from '../../@theme/theme.module';
|
||||
import { OrganizationDetailPageComponent } from './components/detail-page/detail-page.component';
|
||||
import { DataSharingAgreementComponent } from './components/data-sharing-agreement/data-sharing-agreement.component';
|
||||
import { WidgetsModule } from '../../widgets/widgets.module';
|
||||
|
||||
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
OrganizationListPageComponent,
|
||||
OrganizationDetailPageComponent,
|
||||
DataSharingAgreementComponent,
|
||||
],
|
||||
imports: [
|
||||
CommonModule,
|
||||
ThemeModule,
|
||||
NbAccordionModule,
|
||||
NbCardModule,
|
||||
NbIconModule,
|
||||
NbListModule,
|
||||
NbTabsetModule,
|
||||
RouterModule.forChild([
|
||||
{ path: 'list', component: OrganizationListPageComponent },
|
||||
{ path: ':id', component: OrganizationDetailPageComponent }
|
||||
]),
|
||||
WidgetsModule,
|
||||
]
|
||||
})
|
||||
export class OrganizationModule { }
|
||||
51
src/app/modules/organization/organization.service.ts
Normal file
51
src/app/modules/organization/organization.service.ts
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
import { HttpClient } from "@angular/common/http";
|
||||
import { Injectable } from "@angular/core";
|
||||
import { Observable, of } from "rxjs";
|
||||
import { catchError, tap } from "rxjs/operators";
|
||||
import { Organization, OrganizationDataSharingAgreement } from 'thingbook-api';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class OrganizationService {
|
||||
|
||||
constructor(private http: HttpClient) {
|
||||
|
||||
}
|
||||
|
||||
getOrganization(id): Observable<Organization> {
|
||||
return this.http.get<Organization>(`http://localhost:3000/api/v1/organization/${id}`)
|
||||
.pipe(
|
||||
catchError(this.handleError<Organization>('getOrganization', null))
|
||||
);
|
||||
}
|
||||
|
||||
getOrganizationAgreements(id): Observable<OrganizationDataSharingAgreement[]> {
|
||||
return this.http.get<OrganizationDataSharingAgreement[]>(`http://localhost:3000/api/v1/organization/${id}/agreement`)
|
||||
.pipe(
|
||||
catchError(this.handleError<OrganizationDataSharingAgreement[]>('getOrganizationAgreements', []))
|
||||
);
|
||||
}
|
||||
|
||||
getOrganizations(): Observable<Organization[]> {
|
||||
return this.http.get<Organization[]>('http://localhost:3000/api/v1/organization')
|
||||
.pipe(
|
||||
catchError(this.handleError<Organization[]>('getOrganizations', []))
|
||||
);
|
||||
}
|
||||
|
||||
private handleError<T>(operation = 'operation', result?: T) {
|
||||
return (error: any): Observable<T> => {
|
||||
|
||||
// TODO: send the error to remote logging infrastructure
|
||||
console.error(error); // log to console instead
|
||||
|
||||
// TODO: better job of transforming error for user consumption
|
||||
console.log(`${operation} failed: ${error.message}`);
|
||||
|
||||
// Let the app keep running by returning an empty result.
|
||||
return of(result as T);
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
17
src/app/modules/user/pages/profile.component.html
Normal file
17
src/app/modules/user/pages/profile.component.html
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
<nb-card>
|
||||
<nb-card-header>{{user?.email}}</nb-card-header>
|
||||
<nb-card-body>
|
||||
<form>
|
||||
<div class="form-group">
|
||||
<label for="inputFirst" class="label">First name</label>
|
||||
<input nbInput fullWidth id="inputFirst" ngModel [(ngModel)]="first"
|
||||
placeholder="First name">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="inputLast" class="label">Last name</label>
|
||||
<input type="text" nbInput fullWidth id="inputLast" placeholder="Last name">
|
||||
</div>
|
||||
<button type="submit" nbButton hero status="primary">Update</button>
|
||||
</form>
|
||||
</nb-card-body>
|
||||
</nb-card>
|
||||
15
src/app/modules/user/pages/profile.component.scss
Normal file
15
src/app/modules/user/pages/profile.component.scss
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
nb-checkbox {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.form-inline [fullWidth] {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.form-inline > * {
|
||||
margin: 0 1.5rem 1.5rem 0;
|
||||
}
|
||||
|
||||
nb-card.inline-form-card nb-card-body {
|
||||
padding-bottom: 0;
|
||||
}
|
||||
38
src/app/modules/user/pages/profile.component.ts
Normal file
38
src/app/modules/user/pages/profile.component.ts
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
import { Component, OnDestroy, OnInit } from "@angular/core";
|
||||
import { Subject } from "rxjs";
|
||||
import { takeUntil } from "rxjs/operators";
|
||||
import { User, UserService } from "../user.service";
|
||||
|
||||
@Component({
|
||||
selector: 'user-profile',
|
||||
templateUrl: './profile.component.html',
|
||||
styleUrls: ['./profile.component.scss']
|
||||
})
|
||||
export class UserProfileComponent implements OnInit, OnDestroy {
|
||||
|
||||
private destroy$: Subject<void> = new Subject<void>();
|
||||
public user: User;
|
||||
public first: string = "Blah";
|
||||
public last: string;
|
||||
|
||||
constructor(private userService: UserService) {
|
||||
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.userService.onUserStatus()
|
||||
.pipe(takeUntil(this.destroy$))
|
||||
.subscribe((user: any) => {
|
||||
this.user = user;
|
||||
this.user.first = 'Blargle';
|
||||
this.first = user?.first || 'Foo!';
|
||||
this.last = user?.last || 'Bar!';
|
||||
});
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.destroy$.next();
|
||||
this.destroy$.complete();
|
||||
}
|
||||
|
||||
}
|
||||
67
src/app/modules/user/user.module.ts
Normal file
67
src/app/modules/user/user.module.ts
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
import { ModuleWithProviders, NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { NbPasswordAuthStrategy, NbAuthModule } from '@nebular/auth';
|
||||
import { HTTP_INTERCEPTORS } from '@angular/common/http';
|
||||
import { LoginInterceptor } from '../../user.interceptors';
|
||||
import { RouterModule } from '@angular/router';
|
||||
import { UserProfileComponent } from './pages/profile.component';
|
||||
import { ThemeModule } from '../../@theme/theme.module';
|
||||
import { NbCardModule, NbCheckboxComponent, NbCheckboxModule, NbInputModule, NbMenuModule } from '@nebular/theme';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
UserProfileComponent,
|
||||
],
|
||||
imports: [
|
||||
CommonModule,
|
||||
ThemeModule,
|
||||
NbMenuModule,
|
||||
NbCardModule,
|
||||
NbCheckboxModule,
|
||||
NbInputModule,
|
||||
FormsModule,
|
||||
RouterModule.forChild([
|
||||
{ path: 'profile', component: UserProfileComponent }
|
||||
]),
|
||||
],
|
||||
exports: [
|
||||
UserProfileComponent,
|
||||
RouterModule,
|
||||
],
|
||||
})
|
||||
export class UserModule {
|
||||
|
||||
static forRoot(): ModuleWithProviders<UserModule>[] {
|
||||
return [{
|
||||
ngModule: UserModule,
|
||||
providers: [
|
||||
{ provide: HTTP_INTERCEPTORS, useClass: LoginInterceptor, multi: true }
|
||||
],
|
||||
},
|
||||
NbAuthModule.forRoot({
|
||||
strategies: [
|
||||
NbPasswordAuthStrategy.setup({
|
||||
name: 'email',
|
||||
baseEndpoint: 'http://localhost:3000/api/v1/user',
|
||||
login: {
|
||||
endpoint: '/login',
|
||||
requireValidToken: false,
|
||||
},
|
||||
register: {
|
||||
endpoint: '/register',
|
||||
requireValidToken: false,
|
||||
},
|
||||
logout: {
|
||||
method: 'get',
|
||||
endpoint: '/logout',
|
||||
requireValidToken: false,
|
||||
}
|
||||
}),
|
||||
],
|
||||
forms: {},
|
||||
}),
|
||||
];
|
||||
}
|
||||
|
||||
}
|
||||
16
src/app/modules/user/user.service.spec.ts
Normal file
16
src/app/modules/user/user.service.spec.ts
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
import { TestBed } from '@angular/core/testing';
|
||||
|
||||
import { UserServiceImpl } from './user.service.impl';
|
||||
|
||||
describe('UserService', () => {
|
||||
let service: UserServiceImpl;
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({});
|
||||
service = TestBed.inject(UserServiceImpl);
|
||||
});
|
||||
|
||||
it('should be created', () => {
|
||||
expect(service).toBeTruthy();
|
||||
});
|
||||
});
|
||||
27
src/app/modules/user/user.service.ts
Normal file
27
src/app/modules/user/user.service.ts
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
import { Injectable } from '@angular/core';
|
||||
import { Observable, of as ObservableOf } from 'rxjs';
|
||||
import { User } from 'thingbook-api';
|
||||
import { LoginInterceptor } from '../../user.interceptors';
|
||||
|
||||
export { User };
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class UserService {
|
||||
|
||||
private user: User = undefined;
|
||||
|
||||
constructor() {
|
||||
LoginInterceptor.s.subscribe({
|
||||
next: (v) => {
|
||||
this.user = v;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public onUserStatus(): Observable<User> {
|
||||
return ObservableOf(this.user);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1,23 +0,0 @@
|
|||
<nb-card size="giant">
|
||||
<nb-tabset fullWidth>
|
||||
|
||||
<nb-tab tabTitle="Contacts">
|
||||
<nb-list>
|
||||
<nb-list-item class="contact" *ngFor="let c of contacts">
|
||||
<nb-user [picture]="c.user.picture" [name]="c.user.name" [title]="c.type" size="large"></nb-user>
|
||||
<nb-icon icon="phone-outline" pack="eva"></nb-icon>
|
||||
</nb-list-item>
|
||||
</nb-list>
|
||||
</nb-tab>
|
||||
|
||||
<nb-tab tabTitle="Recent">
|
||||
<nb-list>
|
||||
<nb-list-item class="contact" *ngFor="let c of recent">
|
||||
<nb-user [picture]="c.user.picture" [name]="c.user.name" [title]="c.type" size="large"></nb-user>
|
||||
<span class="caption">{{ c.time | date: 'shortTime' }}</span>
|
||||
</nb-list-item>
|
||||
</nb-list>
|
||||
</nb-tab>
|
||||
|
||||
</nb-tabset>
|
||||
</nb-card>
|
||||
|
|
@ -1,34 +0,0 @@
|
|||
@import '../../../@theme/styles/themes';
|
||||
|
||||
@include nb-install-component() {
|
||||
nb-card {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
nb-tabset {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
::ng-deep ul {
|
||||
// make same size as card header
|
||||
padding-bottom: 1px;
|
||||
::ng-deep .tab-link {
|
||||
padding: 1.25rem 2rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nb-tab {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.contact {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
|
||||
&:first-child {
|
||||
border-top: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,34 +0,0 @@
|
|||
import { Component, OnDestroy } from '@angular/core';
|
||||
import { takeWhile } from 'rxjs/operators';
|
||||
import { forkJoin } from 'rxjs';
|
||||
|
||||
import { Contacts, RecentUsers, UserData } from '../../../@core/data/users';
|
||||
|
||||
@Component({
|
||||
selector: 'ngx-contacts',
|
||||
styleUrls: ['./contacts.component.scss'],
|
||||
templateUrl: './contacts.component.html',
|
||||
})
|
||||
export class ContactsComponent implements OnDestroy {
|
||||
|
||||
private alive = true;
|
||||
|
||||
contacts: any[];
|
||||
recent: any[];
|
||||
|
||||
constructor(private userService: UserData) {
|
||||
forkJoin(
|
||||
this.userService.getContacts(),
|
||||
this.userService.getRecentUsers(),
|
||||
)
|
||||
.pipe(takeWhile(() => this.alive))
|
||||
.subscribe(([contacts, recent]: [Contacts[], RecentUsers[]]) => {
|
||||
this.contacts = contacts;
|
||||
this.recent = recent;
|
||||
});
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.alive = false;
|
||||
}
|
||||
}
|
||||
|
|
@ -21,10 +21,6 @@
|
|||
<ngx-rooms></ngx-rooms>
|
||||
</div>
|
||||
|
||||
<div class="col-xxxl-3 col-xxl-4 col-lg-7 col-md-6">
|
||||
<ngx-contacts></ngx-contacts>
|
||||
</div>
|
||||
|
||||
<div class="col-xxxl-3 col-xxl-4 col-lg-5 col-md-6">
|
||||
<ngx-solar [chartValue]="solarValue"></ngx-solar>
|
||||
|
||||
|
|
@ -39,4 +35,4 @@
|
|||
<div class="col-xxxl-6 col-xxl-12 col-md-7">
|
||||
<ngx-security-cameras></ngx-security-cameras>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -15,7 +15,6 @@ import { NgxEchartsModule } from 'ngx-echarts';
|
|||
import { ThemeModule } from '../../@theme/theme.module';
|
||||
import { DashboardComponent } from './dashboard.component';
|
||||
import { StatusCardComponent } from './status-card/status-card.component';
|
||||
import { ContactsComponent } from './contacts/contacts.component';
|
||||
import { RoomsComponent } from './rooms/rooms.component';
|
||||
import { RoomSelectorComponent } from './rooms/room-selector/room-selector.component';
|
||||
import { TemperatureComponent } from './temperature/temperature.component';
|
||||
|
|
@ -51,7 +50,6 @@ import { FormsModule } from '@angular/forms';
|
|||
DashboardComponent,
|
||||
StatusCardComponent,
|
||||
TemperatureDraggerComponent,
|
||||
ContactsComponent,
|
||||
RoomSelectorComponent,
|
||||
TemperatureComponent,
|
||||
RoomsComponent,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,11 @@
|
|||
import { NbMenuItem } from '@nebular/theme';
|
||||
|
||||
export const MENU_ITEMS: NbMenuItem[] = [
|
||||
{
|
||||
title: 'Organizations',
|
||||
icon: 'keypad-outline',
|
||||
link: '/pages/org/list',
|
||||
},
|
||||
{
|
||||
title: 'E-commerce',
|
||||
icon: 'shopping-cart-outline',
|
||||
|
|
|
|||
|
|
@ -14,6 +14,16 @@ const routes: Routes = [{
|
|||
path: 'dashboard',
|
||||
component: ECommerceComponent,
|
||||
},
|
||||
{
|
||||
path: 'user',
|
||||
loadChildren: () => import('../modules/user/user.module')
|
||||
.then(m => m.UserModule)
|
||||
},
|
||||
{
|
||||
path: 'org',
|
||||
loadChildren: () => import('../modules/organization/organization.module')
|
||||
.then(m => m.OrganizationModule)
|
||||
},
|
||||
{
|
||||
path: 'iot-dashboard',
|
||||
component: DashboardComponent,
|
||||
|
|
|
|||
22
src/app/user.interceptors.ts
Normal file
22
src/app/user.interceptors.ts
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
import { HttpEvent, HttpHandler, HttpInterceptor, HttpRequest, HttpResponse } from "@angular/common/http";
|
||||
import { Injectable } from "@angular/core";
|
||||
import { BehaviorSubject, Observable, Subject } from "rxjs";
|
||||
import { filter, tap } from "rxjs/operators";
|
||||
import * as api from 'thingbook-api';
|
||||
|
||||
@Injectable()
|
||||
export class LoginInterceptor implements HttpInterceptor {
|
||||
|
||||
public static s: BehaviorSubject<api.User> = new BehaviorSubject<api.User>(undefined);
|
||||
|
||||
intercept(httpRequest: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
|
||||
return next.handle(httpRequest).pipe(
|
||||
tap((event: HttpResponse<any>) => {
|
||||
if (event instanceof HttpResponse && event.url.endsWith('/user/login')) {
|
||||
LoginInterceptor.s.next(<api.User>event.body);
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
6
src/app/widgets/date/date-calendar.component.html
Normal file
6
src/app/widgets/date/date-calendar.component.html
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
<time datetime="datestr" class="date-as-calendar inline-flex {{size}}">
|
||||
<span class="weekday">{{weekday}}</span>
|
||||
<span class="day">{{day}}</span>
|
||||
<span class="month">{{month}}</span>
|
||||
<span class="year">{{year}}</span>
|
||||
</time>
|
||||
175
src/app/widgets/date/date-calendar.component.scss
Normal file
175
src/app/widgets/date/date-calendar.component.scss
Normal file
|
|
@ -0,0 +1,175 @@
|
|||
/****************************************/
|
||||
/* Styling rules, such as font and colors */
|
||||
.date-as-calendar {
|
||||
font-variant: normal;
|
||||
font-style: normal;
|
||||
font-weight: normal;
|
||||
font-family: "Helvetica", "Arial", sans-serif;
|
||||
|
||||
/* It seems vertical-align: baseline does not work correctly with display: inline-flex. */
|
||||
vertical-align: top;
|
||||
|
||||
/* margin: 1ex; */
|
||||
|
||||
color: black;
|
||||
background: white;
|
||||
background : linear-gradient(to bottom right, #FFF 0%, #EEE 100%);
|
||||
|
||||
border: 1px solid #888;
|
||||
border-radius: 3px;
|
||||
overflow: hidden;
|
||||
|
||||
box-shadow: 2px 2px 2px -2px black;
|
||||
}
|
||||
.date-as-calendar .weekday,
|
||||
.date-as-calendar .day,
|
||||
.date-as-calendar .month,
|
||||
.date-as-calendar .year {
|
||||
text-align: center;
|
||||
line-height: 1.0;
|
||||
}
|
||||
.date-as-calendar .month {
|
||||
font-family: "Oswald", sans-serif;
|
||||
text-transform: uppercase;
|
||||
background: #B11;
|
||||
background : linear-gradient(to bottom right, #D66 0%, #A00 100%);
|
||||
color: white;
|
||||
}
|
||||
|
||||
/****************************************/
|
||||
/* Layout rules using position: absolute and pixels. */
|
||||
.position-pixels.date-as-calendar {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
width: 64px;
|
||||
height: 64px;
|
||||
}
|
||||
.position-pixels.date-as-calendar .weekday,
|
||||
.position-pixels.date-as-calendar .day,
|
||||
.position-pixels.date-as-calendar .month,
|
||||
.position-pixels.date-as-calendar .year {
|
||||
display: block;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
width: 100%;
|
||||
height: 1em;
|
||||
}
|
||||
.position-pixels.date-as-calendar .month {
|
||||
top: 0px;
|
||||
font-size: 12px;
|
||||
padding: 2px 0;
|
||||
}
|
||||
.position-pixels.date-as-calendar .weekday {
|
||||
top: 16px;
|
||||
font-size: 10px;
|
||||
}
|
||||
.position-pixels.date-as-calendar .day {
|
||||
top: 26px;
|
||||
font-size: 24px;
|
||||
}
|
||||
.position-pixels.date-as-calendar .year {
|
||||
top: 50px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
/****************************************/
|
||||
/* Layout rules using position: absolute and relative dimensions using em. */
|
||||
.position-em.date-as-calendar {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
|
||||
width: 4em;
|
||||
height: 4em;
|
||||
}
|
||||
.position-em.date-as-calendar .weekday,
|
||||
.position-em.date-as-calendar .day,
|
||||
.position-em.date-as-calendar .month,
|
||||
.position-em.date-as-calendar .year {
|
||||
display: block;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
width: 100%;
|
||||
height: 1em;
|
||||
}
|
||||
.position-em.date-as-calendar .month {
|
||||
top: 0px;
|
||||
font-size: 0.75em;
|
||||
padding: 0.1em 0;
|
||||
}
|
||||
.position-em.date-as-calendar .weekday {
|
||||
top: 1.6em;
|
||||
font-size: 0.6125em;
|
||||
}
|
||||
.position-em.date-as-calendar .day {
|
||||
top: 1.1em;
|
||||
font-size: 1.5em
|
||||
}
|
||||
.position-em.date-as-calendar .year {
|
||||
bottom: 0px;
|
||||
font-size: 0.87750em;
|
||||
}
|
||||
|
||||
/****************************************/
|
||||
/* Layout rules using display: inline-flex and relative dimensions using em. */
|
||||
.inline-flex.date-as-calendar {
|
||||
display: inline-flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: nowrap;
|
||||
justify-content: space-between;
|
||||
|
||||
width: 4em;
|
||||
height: 4em;
|
||||
}
|
||||
.inline-flex.date-as-calendar .weekday,
|
||||
.inline-flex.date-as-calendar .day,
|
||||
.inline-flex.date-as-calendar .month,
|
||||
.inline-flex.date-as-calendar .year {
|
||||
display: block;
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
.inline-flex.date-as-calendar .month {
|
||||
order: 1;
|
||||
font-size: 0.75em;
|
||||
padding: 0.1em 0;
|
||||
}
|
||||
.inline-flex.date-as-calendar .weekday {
|
||||
order: 2;
|
||||
font-size: 0.6125em;
|
||||
}
|
||||
.inline-flex.date-as-calendar .day {
|
||||
order: 3;
|
||||
font-size: 1.5em;
|
||||
}
|
||||
.inline-flex.date-as-calendar .year {
|
||||
order: 4;
|
||||
font-size: 0.87750em;
|
||||
}
|
||||
|
||||
/****************************************/
|
||||
/* Multiple sizes. */
|
||||
.date-as-calendar.size0_5x {
|
||||
font-size: 8px;
|
||||
}
|
||||
.date-as-calendar.size0_75x {
|
||||
font-size: 12px;
|
||||
}
|
||||
.date-as-calendar.size1x {
|
||||
font-size: 16px;
|
||||
}
|
||||
.date-as-calendar.size1_25x {
|
||||
font-size: 20px;
|
||||
}
|
||||
.date-as-calendar.size1_5x {
|
||||
font-size: 24px;
|
||||
}
|
||||
.date-as-calendar.size1_75x {
|
||||
font-size: 28px;
|
||||
}
|
||||
.date-as-calendar.size2x {
|
||||
font-size: 32px;
|
||||
}
|
||||
.date-as-calendar.size3x {
|
||||
font-size: 48px;
|
||||
}
|
||||
58
src/app/widgets/date/date-calendar.component.ts
Normal file
58
src/app/widgets/date/date-calendar.component.ts
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
import { getLocaleDateTimeFormat } from "@angular/common";
|
||||
import { Component, Input, OnInit } from "@angular/core";
|
||||
|
||||
@Component({
|
||||
selector: 'app-date-calendar',
|
||||
templateUrl: './date-calendar.component.html',
|
||||
styleUrls: ['./date-calendar.component.scss']
|
||||
})
|
||||
export class DateCalendarComponent implements OnInit {
|
||||
@Input() date: Date | string;
|
||||
@Input() size: string = "size1x";
|
||||
|
||||
datestr: string;
|
||||
weekday: string;
|
||||
day: string;
|
||||
month: string;
|
||||
year: string;
|
||||
|
||||
constructor() {
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
if (typeof this.date === 'string') {
|
||||
this.date = new Date(this.date);
|
||||
}
|
||||
|
||||
this.datestr = this.date.toISOString();
|
||||
|
||||
const dateParts: any = this.extract(this.date);
|
||||
|
||||
this.weekday = dateParts.weekday;
|
||||
this.day = dateParts.day;
|
||||
this.month = dateParts.month;
|
||||
this.year = dateParts.year;
|
||||
}
|
||||
|
||||
private extract(date: Date): object {
|
||||
const formatter: Intl.DateTimeFormat = new Intl.DateTimeFormat(navigator.language, {
|
||||
weekday: 'long',
|
||||
year: 'numeric',
|
||||
month: 'short',
|
||||
day: 'numeric',
|
||||
hour: 'numeric',
|
||||
minute: 'numeric',
|
||||
second: 'numeric',
|
||||
hour12: true,
|
||||
timeZone: 'UTC'
|
||||
});
|
||||
const parts: Intl.DateTimeFormatPart[] = formatter.formatToParts(date);
|
||||
|
||||
let result = {}
|
||||
for (let p of parts) {
|
||||
result[p.type] = p.value;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
<nb-icon [icon]='value ? "shield-outline" : "shield-off-outline"' [status]='value ? "success" : "danger"'>
|
||||
</nb-icon>
|
||||
12
src/app/widgets/verification/verification-icon.component.ts
Normal file
12
src/app/widgets/verification/verification-icon.component.ts
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
import { Component, Input } from "@angular/core";
|
||||
|
||||
@Component({
|
||||
selector: 'app-verification-icon',
|
||||
templateUrl: './verification-icon.component.html',
|
||||
styleUrls: ['./verification-icon.component.scss']
|
||||
})
|
||||
export class VerificationIconComponent {
|
||||
|
||||
@Input() value: boolean;
|
||||
|
||||
}
|
||||
19
src/app/widgets/widgets.module.ts
Normal file
19
src/app/widgets/widgets.module.ts
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
import { NgModule } from "@angular/core";
|
||||
import { NbIconModule } from "@nebular/theme";
|
||||
import { DateCalendarComponent } from "./date/date-calendar.component";
|
||||
import { VerificationIconComponent } from "./verification/verification-icon.component";
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
VerificationIconComponent,
|
||||
DateCalendarComponent,
|
||||
],
|
||||
exports: [
|
||||
VerificationIconComponent,
|
||||
DateCalendarComponent,
|
||||
],
|
||||
imports: [
|
||||
NbIconModule,
|
||||
]
|
||||
})
|
||||
export class WidgetsModule { }
|
||||
Loading…
Add table
Add a link
Reference in a new issue