Add notification menu
All checks were successful
FarmMaps.Develop/FarmMapsLib/pipeline/head This commit looks good
All checks were successful
FarmMaps.Develop/FarmMapsLib/pipeline/head This commit looks good
This commit is contained in:
parent
39993e75da
commit
142a1c9e58
@ -39,6 +39,8 @@ export const TASKPROGRESSEVENT = '[AppCommon] TaskProgressEvent';
|
|||||||
|
|
||||||
export const DEVICEUPDATEEVENT = '[AppCommon] DeviceUpdateEvent';
|
export const DEVICEUPDATEEVENT = '[AppCommon] DeviceUpdateEvent';
|
||||||
|
|
||||||
|
export const NOTIFICATIONEVENT = '[AppCommon] NotificationEvent';
|
||||||
|
|
||||||
export const DELETEITEMS = '[AppCommon] DeleteItems';
|
export const DELETEITEMS = '[AppCommon] DeleteItems';
|
||||||
export const DELETEITEMSSUCCESS = '[AppCommon] DeleteItemsSuccess';
|
export const DELETEITEMSSUCCESS = '[AppCommon] DeleteItemsSuccess';
|
||||||
|
|
||||||
@ -62,6 +64,8 @@ export const TOGGLEACCOUNTMENU = '[AppCommon] ToggleAccountMenu';
|
|||||||
|
|
||||||
export const TOGGLEAPPMENU = '[AppCommon] ToggleAppMenu';
|
export const TOGGLEAPPMENU = '[AppCommon] ToggleAppMenu';
|
||||||
|
|
||||||
|
export const TOGGLENOTIFICATIONMENU = '[AppCommon] ToggleNotificationMenu';
|
||||||
|
|
||||||
export const SETMENUVISIBLE = '[AppCommon] SetMenuVisible';
|
export const SETMENUVISIBLE = '[AppCommon] SetMenuVisible';
|
||||||
|
|
||||||
export const ONLINE = '[AppCommon] Online';
|
export const ONLINE = '[AppCommon] Online';
|
||||||
@ -232,6 +236,12 @@ export class DeviceUpdateEvent implements Action {
|
|||||||
constructor(public itemCode: string, public attributes: any) { }
|
constructor(public itemCode: string, public attributes: any) { }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class NotificationEvent implements Action {
|
||||||
|
readonly type = NOTIFICATIONEVENT;
|
||||||
|
|
||||||
|
constructor(public attributes: any) { }
|
||||||
|
}
|
||||||
|
|
||||||
export class DeleteItems implements Action {
|
export class DeleteItems implements Action {
|
||||||
readonly type = DELETEITEMS;
|
readonly type = DELETEITEMS;
|
||||||
|
|
||||||
@ -291,6 +301,12 @@ export class ToggleAppMenu implements Action {
|
|||||||
constructor() { }
|
constructor() { }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class ToggleNotificationMenu implements Action {
|
||||||
|
readonly type = TOGGLENOTIFICATIONMENU;
|
||||||
|
|
||||||
|
constructor() { }
|
||||||
|
}
|
||||||
|
|
||||||
export class SetMenuVisible implements Action {
|
export class SetMenuVisible implements Action {
|
||||||
readonly type = SETMENUVISIBLE;
|
readonly type = SETMENUVISIBLE;
|
||||||
|
|
||||||
@ -355,6 +371,8 @@ export type Actions = OpenModal
|
|||||||
| Online
|
| Online
|
||||||
| Offline
|
| Offline
|
||||||
| SetPageMode
|
| SetPageMode
|
||||||
| ToggleAppMenu;
|
| ToggleAppMenu
|
||||||
|
| ToggleNotificationMenu
|
||||||
|
| NotificationEvent;
|
||||||
|
|
||||||
|
|
||||||
|
@ -56,6 +56,7 @@ import { SecureOAuthStorage} from './shared/secureOAuthStorage';
|
|||||||
import { GradientComponent } from './components/gradient/gradient.component';
|
import { GradientComponent } from './components/gradient/gradient.component';
|
||||||
import { GradientSelectComponent } from './components/gradient-select/gradient-select.component';
|
import { GradientSelectComponent } from './components/gradient-select/gradient-select.component';
|
||||||
import { AppMenuComponent } from './components/app-menu/app-menu.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';
|
import { BackButtonComponent } from './components/back-button/back-button.component';
|
||||||
|
|
||||||
export {
|
export {
|
||||||
@ -131,6 +132,7 @@ export {
|
|||||||
GradientComponent,
|
GradientComponent,
|
||||||
GradientSelectComponent,
|
GradientSelectComponent,
|
||||||
AppMenuComponent,
|
AppMenuComponent,
|
||||||
|
NotificationMenuComponent,
|
||||||
BackButtonComponent
|
BackButtonComponent
|
||||||
],
|
],
|
||||||
exports: [
|
exports: [
|
||||||
|
@ -31,6 +31,7 @@
|
|||||||
<fm-resumable-file-upload></fm-resumable-file-upload>
|
<fm-resumable-file-upload></fm-resumable-file-upload>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
<div class="user-menu apponly">
|
<div class="user-menu apponly">
|
||||||
|
<fm-notification-menu [user]="user|async" [unread]="unreadNotifications|async" [showMenu]="notificationMenuVisible|async"></fm-notification-menu>
|
||||||
<fm-app-menu [user]="user|async" [showMenu]="appMenuVisible|async"></fm-app-menu>
|
<fm-app-menu [user]="user|async" [showMenu]="appMenuVisible|async"></fm-app-menu>
|
||||||
<fm-user-menu [user]="user|async" [showMenu]="accountMenuVisible|async"></fm-user-menu>
|
<fm-user-menu [user]="user|async" [showMenu]="accountMenuVisible|async"></fm-user-menu>
|
||||||
</div>
|
</div>
|
||||||
|
@ -125,7 +125,7 @@ body { background: #f1f1f1; line-height: 18px; user-select:none;font-family: Lat
|
|||||||
max-height:0em;
|
max-height:0em;
|
||||||
}
|
}
|
||||||
|
|
||||||
fm-app-menu,fm-user-menu {
|
fm-app-menu,fm-user-menu,fm-notification-menu {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
margin-left: 1rem;
|
margin-left: 1rem;
|
||||||
}
|
}
|
||||||
|
@ -43,6 +43,8 @@ export class AppComponent implements OnInit, OnDestroy {
|
|||||||
public menuVisible: Observable<boolean> = this.store$.select(appReducers.SelectGetMenuVisible);
|
public menuVisible: Observable<boolean> = this.store$.select(appReducers.SelectGetMenuVisible);
|
||||||
public accountMenuVisible: Observable<boolean> = this.store$.select(appReducers.SelectGetAccountMenuVisible);
|
public accountMenuVisible: Observable<boolean> = this.store$.select(appReducers.SelectGetAccountMenuVisible);
|
||||||
public appMenuVisible: Observable<boolean> = this.store$.select(appReducers.SelectGetAppMenuVisible);
|
public appMenuVisible: Observable<boolean> = this.store$.select(appReducers.SelectGetAppMenuVisible);
|
||||||
|
public notificationMenuVisible: Observable<boolean> = this.store$.select(appReducers.SelectGetNotificationMenuVisible);
|
||||||
|
public unreadNotifications: Observable<number> = this.store$.select(appReducers.SelectgetUnreadNotifications);
|
||||||
public user: Observable<IUser> = this.store$.select(appReducers.SelectGetUser);
|
public user: Observable<IUser> = this.store$.select(appReducers.SelectGetUser);
|
||||||
public isPageMode: Observable<boolean> = this.store$.select(appReducers.SelectGetIsPageMode);
|
public isPageMode: Observable<boolean> = this.store$.select(appReducers.SelectGetIsPageMode);
|
||||||
@Input() showUploadProgress: boolean = true;
|
@Input() showUploadProgress: boolean = true;
|
||||||
@ -98,6 +100,10 @@ export class AppComponent implements OnInit, OnDestroy {
|
|||||||
action = new commonActions.DeviceUpdateEvent(event.itemCode, event.attributes);
|
action = new commonActions.DeviceUpdateEvent(event.itemCode, event.attributes);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case "notification": {
|
||||||
|
action = new commonActions.NotificationEvent(event.attributes);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return action;
|
return action;
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,10 @@
|
|||||||
|
<div>
|
||||||
|
<div (click)="toggle($event)" class="rounded-circle menu-button hidden" [ngClass]="{'hidden':!user}">
|
||||||
|
<span class="unread badge bg-info notification rounded-pill hidden" [ngClass]="{'hidden':unread==0}">{{unread}}</span>
|
||||||
|
<span i18n-title title="Notifications"><i class="fas fa-bell" [ngClass]="{'fa-bell-on':unread!=0}" aria-hidden="true"></i></span>
|
||||||
|
<div class="menu hidden" [ngClass]="{'hidden':!showMenu}">
|
||||||
|
<router-outlet name="notification-menu"></router-outlet>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
@ -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;
|
||||||
|
}
|
@ -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<NotificationMenuComponent>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
declarations: [ NotificationMenuComponent ]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(NotificationMenuComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
@ -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<appReducers.State>) { }
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
}
|
||||||
|
|
||||||
|
toggle(event:MouseEvent) {
|
||||||
|
event.stopPropagation();
|
||||||
|
this.store.dispatch(new appActions.ToggleNotificationMenu());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -22,6 +22,8 @@ export interface State {
|
|||||||
userSettingsRoot: IItem,
|
userSettingsRoot: IItem,
|
||||||
accountMenuVisible: boolean,
|
accountMenuVisible: boolean,
|
||||||
appMenuVisible: boolean,
|
appMenuVisible: boolean,
|
||||||
|
notificationMenuVisible: boolean,
|
||||||
|
unreadNotifications: number,
|
||||||
isOnline: boolean,
|
isOnline: boolean,
|
||||||
isPageMode:boolean
|
isPageMode:boolean
|
||||||
}
|
}
|
||||||
@ -39,6 +41,8 @@ export const initialState: State = {
|
|||||||
userSettingsRoot: null,
|
userSettingsRoot: null,
|
||||||
accountMenuVisible: false,
|
accountMenuVisible: false,
|
||||||
appMenuVisible: false,
|
appMenuVisible: false,
|
||||||
|
notificationMenuVisible: false,
|
||||||
|
unreadNotifications: 0,
|
||||||
isOnline: true,
|
isOnline: true,
|
||||||
isPageMode: true
|
isPageMode: true
|
||||||
}
|
}
|
||||||
@ -98,20 +102,23 @@ export function reducer(state = initialState, action: appCommonActions.Actions )
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
case appCommonActions.TOGGLEMENU: {
|
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: {
|
case appCommonActions.TOGGLEACCOUNTMENU: {
|
||||||
return tassign(state, { accountMenuVisible: !state.accountMenuVisible,appMenuVisible:false });
|
return tassign(state, { accountMenuVisible: !state.accountMenuVisible,appMenuVisible:false,notificationMenuVisible:false });
|
||||||
}
|
}
|
||||||
case appCommonActions.TOGGLEAPPMENU: {
|
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: {
|
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: {
|
case appCommonActions.SETMENUVISIBLE: {
|
||||||
let a = action as 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:{
|
case appCommonActions.INITUSERPACKAGESSUCCESS:{
|
||||||
let a = action as 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;
|
let a = action as appCommonActions.SetPageMode;
|
||||||
return tassign(state,{isPageMode:a.pageMode});
|
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: {
|
default: {
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
@ -162,6 +177,8 @@ export const getUserPackages = (state: State) => state.userPackages;
|
|||||||
export const getUserSettingsRoot = (state: State) => state.userSettingsRoot;
|
export const getUserSettingsRoot = (state: State) => state.userSettingsRoot;
|
||||||
export const getAccountMenuVisible = (state: State) => state.accountMenuVisible;
|
export const getAccountMenuVisible = (state: State) => state.accountMenuVisible;
|
||||||
export const getAppMenuVisible = (state: State) => state.appMenuVisible;
|
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 getIsOnline = (state: State) => state.isOnline;
|
||||||
export const getIsPageMode = (state: State) => state.isPageMode;
|
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 SelectGetUserSettingsRoot = createSelector(selectAppCommonState,getUserSettingsRoot);
|
||||||
export const SelectGetAccountMenuVisible = createSelector(selectAppCommonState,getAccountMenuVisible);
|
export const SelectGetAccountMenuVisible = createSelector(selectAppCommonState,getAccountMenuVisible);
|
||||||
export const SelectGetAppMenuVisible = createSelector(selectAppCommonState,getAppMenuVisible);
|
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 SelectGetIsOnline = createSelector(selectAppCommonState,getIsOnline);
|
||||||
export const SelectGetIsPageMode = createSelector(selectAppCommonState,getIsPageMode);
|
export const SelectGetIsPageMode = createSelector(selectAppCommonState,getIsPageMode);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user