diff --git a/projects/common/src/fm/actions/app-common.actions.ts b/projects/common/src/fm/actions/app-common.actions.ts index 2407bd0..b37ed99 100644 --- a/projects/common/src/fm/actions/app-common.actions.ts +++ b/projects/common/src/fm/actions/app-common.actions.ts @@ -39,6 +39,8 @@ export const TASKPROGRESSEVENT = '[AppCommon] TaskProgressEvent'; export const DEVICEUPDATEEVENT = '[AppCommon] DeviceUpdateEvent'; +export const NOTIFICATIONEVENT = '[AppCommon] NotificationEvent'; + export const DELETEITEMS = '[AppCommon] DeleteItems'; export const DELETEITEMSSUCCESS = '[AppCommon] DeleteItemsSuccess'; @@ -62,6 +64,8 @@ export const TOGGLEACCOUNTMENU = '[AppCommon] ToggleAccountMenu'; export const TOGGLEAPPMENU = '[AppCommon] ToggleAppMenu'; +export const TOGGLENOTIFICATIONMENU = '[AppCommon] ToggleNotificationMenu'; + export const SETMENUVISIBLE = '[AppCommon] SetMenuVisible'; export const ONLINE = '[AppCommon] Online'; @@ -232,6 +236,12 @@ export class DeviceUpdateEvent implements Action { constructor(public itemCode: string, public attributes: any) { } } +export class NotificationEvent implements Action { + readonly type = NOTIFICATIONEVENT; + + constructor(public attributes: any) { } +} + export class DeleteItems implements Action { readonly type = DELETEITEMS; @@ -291,6 +301,12 @@ export class ToggleAppMenu implements Action { constructor() { } } +export class ToggleNotificationMenu implements Action { + readonly type = TOGGLENOTIFICATIONMENU; + + constructor() { } +} + export class SetMenuVisible implements Action { readonly type = SETMENUVISIBLE; @@ -355,6 +371,8 @@ export type Actions = OpenModal | Online | Offline | SetPageMode - | ToggleAppMenu; + | ToggleAppMenu + | ToggleNotificationMenu + | NotificationEvent; diff --git a/projects/common/src/fm/common.module.ts b/projects/common/src/fm/common.module.ts index 9e8b720..6076215 100644 --- a/projects/common/src/fm/common.module.ts +++ b/projects/common/src/fm/common.module.ts @@ -56,6 +56,7 @@ import { SecureOAuthStorage} from './shared/secureOAuthStorage'; import { GradientComponent } from './components/gradient/gradient.component'; import { GradientSelectComponent } from './components/gradient-select/gradient-select.component'; import { AppMenuComponent } from './components/app-menu/app-menu.component'; +import { NotificationMenuComponent} from './components/notification-menu/notification-menu.component'; import { BackButtonComponent } from './components/back-button/back-button.component'; export { @@ -131,6 +132,7 @@ export { GradientComponent, GradientSelectComponent, AppMenuComponent, + NotificationMenuComponent, BackButtonComponent ], exports: [ diff --git a/projects/common/src/fm/components/app/app.component.html b/projects/common/src/fm/components/app/app.component.html index 71c79e2..e9823ba 100644 --- a/projects/common/src/fm/components/app/app.component.html +++ b/projects/common/src/fm/components/app/app.component.html @@ -31,6 +31,7 @@
+
diff --git a/projects/common/src/fm/components/app/app.component.scss b/projects/common/src/fm/components/app/app.component.scss index b3c08b2..3735e89 100644 --- a/projects/common/src/fm/components/app/app.component.scss +++ b/projects/common/src/fm/components/app/app.component.scss @@ -125,7 +125,7 @@ body { background: #f1f1f1; line-height: 18px; user-select:none;font-family: Lat max-height:0em; } -fm-app-menu,fm-user-menu { +fm-app-menu,fm-user-menu,fm-notification-menu { display: inline-block; margin-left: 1rem; } diff --git a/projects/common/src/fm/components/app/app.component.ts b/projects/common/src/fm/components/app/app.component.ts index f11fbff..71dbb9d 100644 --- a/projects/common/src/fm/components/app/app.component.ts +++ b/projects/common/src/fm/components/app/app.component.ts @@ -43,6 +43,8 @@ export class AppComponent implements OnInit, OnDestroy { public menuVisible: Observable = this.store$.select(appReducers.SelectGetMenuVisible); public accountMenuVisible: Observable = this.store$.select(appReducers.SelectGetAccountMenuVisible); public appMenuVisible: Observable = this.store$.select(appReducers.SelectGetAppMenuVisible); + public notificationMenuVisible: Observable = this.store$.select(appReducers.SelectGetNotificationMenuVisible); + public unreadNotifications: Observable = this.store$.select(appReducers.SelectgetUnreadNotifications); public user: Observable = this.store$.select(appReducers.SelectGetUser); public isPageMode: Observable = this.store$.select(appReducers.SelectGetIsPageMode); @Input() showUploadProgress: boolean = true; @@ -98,6 +100,10 @@ export class AppComponent implements OnInit, OnDestroy { action = new commonActions.DeviceUpdateEvent(event.itemCode, event.attributes); break; } + case "notification": { + action = new commonActions.NotificationEvent(event.attributes); + break; + } } return action; } diff --git a/projects/common/src/fm/components/notification-menu/notification-menu.component.html b/projects/common/src/fm/components/notification-menu/notification-menu.component.html new file mode 100644 index 0000000..fab5e66 --- /dev/null +++ b/projects/common/src/fm/components/notification-menu/notification-menu.component.html @@ -0,0 +1,10 @@ +
+ +
+ diff --git a/projects/common/src/fm/components/notification-menu/notification-menu.component.scss b/projects/common/src/fm/components/notification-menu/notification-menu.component.scss new file mode 100644 index 0000000..6d4d098 --- /dev/null +++ b/projects/common/src/fm/components/notification-menu/notification-menu.component.scss @@ -0,0 +1,80 @@ +.menu-button { + background-color: gray; + display: inline-block; + width: 2.5em; + height: 2.5em; + line-height: 2.5em; + text-align: center; + font-size: 1rem; + position: relative; +} + +div.menu-button > span { + color:white; +} + +.menu { + max-height: calc( 100vh - 4rem); + //transition: max-height 0.2s; + overflow: hidden; + box-shadow: 0 0 20px rgba(0,0,0,.3); + position: fixed; + top: 3.4rem; + right:0.5rem; + left:0.5rem; + background-color: #fff; + border-radius: 0.25rem; + padding: 0.5rem; + z-index: 3; +} + +:host-context(.fullscreen) .menu { + top:4em; +} + +.card { + padding:0.5rem; + min-width: 10rem; +} + +.card-body { + text-align: left; +} + +.hidden { + max-height: 0; +} + +.menu.hidden { + padding: 0; +} + +.menu-button.hidden { + overflow: hidden; +} + + +@media screen and (min-width: 44rem) { + .menu { + position: absolute; + top: 3rem; + right:0; + left: unset; + max-width: 30em; + } + + :host-context(.fullscreen) .menu { + top: 3rem; + } +} + +.unread { + display: block; + position: absolute; + top:-0.5em; + right: -0.5em; +} + +.unread.hidden { + display: none; +} \ No newline at end of file diff --git a/projects/common/src/fm/components/notification-menu/notification-menu.component.spec.ts b/projects/common/src/fm/components/notification-menu/notification-menu.component.spec.ts new file mode 100644 index 0000000..b12d608 --- /dev/null +++ b/projects/common/src/fm/components/notification-menu/notification-menu.component.spec.ts @@ -0,0 +1,25 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { NotificationMenuComponent } from './notification-menu.component'; + +describe('NotificationMenuComponent', () => { + let component: NotificationMenuComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ NotificationMenuComponent ] + }) + .compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(NotificationMenuComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/projects/common/src/fm/components/notification-menu/notification-menu.component.ts b/projects/common/src/fm/components/notification-menu/notification-menu.component.ts new file mode 100644 index 0000000..c1b2ace --- /dev/null +++ b/projects/common/src/fm/components/notification-menu/notification-menu.component.ts @@ -0,0 +1,30 @@ +import { Component, OnInit, Input } from '@angular/core'; + + +import { IUser } from '../../models/user'; +import {Store} from '@ngrx/store'; +import * as appReducers from '../../reducers/app-common.reducer'; +import * as appActions from '../../actions/app-common.actions'; + +@Component({ + selector: 'fm-notification-menu', + templateUrl: './notification-menu.component.html', + styleUrls: ['./notification-menu.component.scss'] +}) +export class NotificationMenuComponent implements OnInit { + + @Input() unread:number; + @Input() user:IUser; + @Input() showMenu:boolean; + + constructor(private store: Store) { } + + ngOnInit(): void { + } + + toggle(event:MouseEvent) { + event.stopPropagation(); + this.store.dispatch(new appActions.ToggleNotificationMenu()); + } + +} diff --git a/projects/common/src/fm/reducers/app-common.reducer.ts b/projects/common/src/fm/reducers/app-common.reducer.ts index b554b5c..5db7304 100644 --- a/projects/common/src/fm/reducers/app-common.reducer.ts +++ b/projects/common/src/fm/reducers/app-common.reducer.ts @@ -22,6 +22,8 @@ export interface State { userSettingsRoot: IItem, accountMenuVisible: boolean, appMenuVisible: boolean, + notificationMenuVisible: boolean, + unreadNotifications: number, isOnline: boolean, isPageMode:boolean } @@ -39,6 +41,8 @@ export const initialState: State = { userSettingsRoot: null, accountMenuVisible: false, appMenuVisible: false, + notificationMenuVisible: false, + unreadNotifications: 0, isOnline: true, isPageMode: true } @@ -98,20 +102,23 @@ export function reducer(state = initialState, action: appCommonActions.Actions ) }); } case appCommonActions.TOGGLEMENU: { - return tassign(state, { menuVisible: !state.menuVisible,accountMenuVisible:!state.menuVisible?false:state.accountMenuVisible,appMenuVisible:!state.menuVisible?false:state.appMenuVisible }); + return tassign(state, { menuVisible: !state.menuVisible,accountMenuVisible:!state.menuVisible?false:state.accountMenuVisible,appMenuVisible:!state.menuVisible?false:state.appMenuVisible,notificationMenuVisible:!state.menuVisible?false:state.notificationMenuVisible }); } case appCommonActions.TOGGLEACCOUNTMENU: { - return tassign(state, { accountMenuVisible: !state.accountMenuVisible,appMenuVisible:false }); + return tassign(state, { accountMenuVisible: !state.accountMenuVisible,appMenuVisible:false,notificationMenuVisible:false }); } case appCommonActions.TOGGLEAPPMENU: { - return tassign(state, { appMenuVisible: !state.appMenuVisible,accountMenuVisible:false }); + return tassign(state, { appMenuVisible: !state.appMenuVisible,accountMenuVisible:false,notificationMenuVisible:false }); + } + case appCommonActions.TOGGLENOTIFICATIONMENU: { + return tassign(state, { notificationMenuVisible : !state.notificationMenuVisible,accountMenuVisible:false,appMenuVisible:false }); } case appCommonActions.ESCAPE: { - return tassign(state, { menuVisible: false,accountMenuVisible:false,appMenuVisible: false }); + return tassign(state, { menuVisible: false,accountMenuVisible:false,appMenuVisible: false,notificationMenuVisible:false }); } case appCommonActions.SETMENUVISIBLE: { let a = action as appCommonActions.SetMenuVisible; - return tassign(state, { menuVisible: a.visible,accountMenuVisible:a.visible?false:state.accountMenuVisible,appMenuVisible:a.visible?false:state.appMenuVisible }); + return tassign(state, { menuVisible: a.visible,accountMenuVisible:a.visible?false:state.accountMenuVisible,appMenuVisible:a.visible?false:state.appMenuVisible,notificationMenuVisible:a.visible?false:state.notificationMenuVisible }); } case appCommonActions.INITUSERPACKAGESSUCCESS:{ let a = action as appCommonActions.InitUserPackagesSuccess; @@ -144,6 +151,14 @@ export function reducer(state = initialState, action: appCommonActions.Actions ) let a = action as appCommonActions.SetPageMode; return tassign(state,{isPageMode:a.pageMode}); } + case appCommonActions.NOTIFICATIONEVENT: { + let a = action as appCommonActions.NotificationEvent; + let unread = 0; + if(a.attributes["unread"]) { + unread = parseInt(a.attributes["unread"]); + } + return tassign(state,{unreadNotifications:unread}); + } default: { return state; } @@ -162,6 +177,8 @@ export const getUserPackages = (state: State) => state.userPackages; export const getUserSettingsRoot = (state: State) => state.userSettingsRoot; export const getAccountMenuVisible = (state: State) => state.accountMenuVisible; export const getAppMenuVisible = (state: State) => state.appMenuVisible; +export const getNotificationMenuVisible = (state: State) => state.notificationMenuVisible; +export const getUnreadNotifications = (state: State) => state.unreadNotifications; export const getIsOnline = (state: State) => state.isOnline; export const getIsPageMode = (state: State) => state.isPageMode; @@ -179,6 +196,9 @@ export const SelectGetUserPackages = createSelector(selectAppCommonState,getUser export const SelectGetUserSettingsRoot = createSelector(selectAppCommonState,getUserSettingsRoot); export const SelectGetAccountMenuVisible = createSelector(selectAppCommonState,getAccountMenuVisible); export const SelectGetAppMenuVisible = createSelector(selectAppCommonState,getAppMenuVisible); +export const SelectGetNotificationMenuVisible = createSelector(selectAppCommonState,getNotificationMenuVisible); +export const SelectgetUnreadNotifications = createSelector(selectAppCommonState,getUnreadNotifications); + export const SelectGetIsOnline = createSelector(selectAppCommonState,getIsOnline); export const SelectGetIsPageMode = createSelector(selectAppCommonState,getIsPageMode);