Skip to content
This repository has been archived by the owner on Jan 1, 2023. It is now read-only.

Commit

Permalink
Merge pull request #63 from norkator/feature/desktop-notifications
Browse files Browse the repository at this point in the history
Feature/desktop notifications
  • Loading branch information
norkator committed Sep 27, 2020
2 parents f0b35c8 + 1ac5e76 commit 4de96a3
Show file tree
Hide file tree
Showing 6 changed files with 113 additions and 8 deletions.
2 changes: 2 additions & 0 deletions api/front-end/src/pages/Cameras/Cameras.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React, {Component} from "react";
import axios, {GET_LATEST_CAMERA_IMAGES_PATH} from '../../axios';
import {LoadingIndicator} from "../../components/LoadingIndicator/LoadingIndicator";
import Notifications from "./Notifications/Notifications";

interface ImageDataInterface {
id: string,
Expand Down Expand Up @@ -79,6 +80,7 @@ class Cameras extends Component {

return (
<div>
<Notifications/>
<div className={cameraFlexStyle.join(' ')}>
{cameraImages}
</div>
Expand Down
93 changes: 93 additions & 0 deletions api/front-end/src/pages/Cameras/Notifications/Notifications.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
import React, {Component} from "react";
import {
WithTranslation,
withTranslation
} from "react-i18next";
import {
getLicensePlateDetections,
LicensePlateDetectionsInterface
} from "../../../utils/HttpUtils";
import {DateIsOlderThanHour, getNowISODate} from "../../../utils/DateUtils";


class Notifications extends Component<WithTranslation> {
private _isMounted: boolean;

state = {
hasPermission: true,
notificationsEnabled: true,
resultOption: 'distinct_detection', // this will return results from known plates only
lastLicensePlate: '',
intervalId: 0,
};

constructor(props: any) {
super(props);
this._isMounted = false;
}

componentDidMount(): void {
this._isMounted = true;
this.checkPermission();
const intervalId = setInterval(() => this.getLastSeenLicensePlate(), 60 * 1000);
this.setState({intervalId: intervalId});
}

componentWillUnmount(): void {
clearInterval(this.state.intervalId);
this._isMounted = false;
}

async getLastSeenLicensePlate() {
if (this.state.hasPermission && this.state.notificationsEnabled) {
const licensePlateDetections = await getLicensePlateDetections(
this.state.resultOption, getNowISODate(), '', '') as LicensePlateDetectionsInterface[];
if (licensePlateDetections.length > 0) {
const lastItem: LicensePlateDetectionsInterface = licensePlateDetections[licensePlateDetections.length - 1];
if (!DateIsOlderThanHour(Date.parse(lastItem.title))) {
if (this.state.lastLicensePlate !== lastItem.detectionCorrected) {
this.setState({lastLicensePlate: lastItem.detectionCorrected});
this.notificationHandler(
lastItem.detectionCorrected + ' - ' + lastItem.ownerName + ' seen ' + lastItem.title
);
}
}
}
}
}

render() {
return (
<></>
)
}

checkPermission = () => {
const this_ = this;
if (Notification.permission === "granted") {
this.setState({hasPermission: true});
} else if (Notification.permission !== "denied") {
Notification.requestPermission().then((permission: string) => {
// If the user accepts, let's create a notification
if (permission === "granted") {
this_.setState({hasPermission: true})
}
});
}
};

/**
* Show desktop notification
* @param message for notification
*/
notificationHandler = (message: string) => {
if (this.state.hasPermission) {
new Notification(message);
}
}

}


export default (withTranslation('i18n')(Notifications));

9 changes: 3 additions & 6 deletions api/front-end/src/pages/Navbar/Navbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@ import {Button, Nav, Navbar, NavDropdown} from 'react-bootstrap'
import styles from './Navbar.module.css'
import {Link} from "react-router-dom";
import {withTranslation} from "react-i18next";
import {i18n} from "i18next";
import {saveLanguageSelection} from "../../i18nConfig";
// eslint-disable-next-line
import {i18n} from "i18next"; // Todo, why esLint whines even when it's in use?

class NavBar extends Component<any, any> {
state = {
Expand Down Expand Up @@ -32,15 +33,11 @@ class NavBar extends Component<any, any> {
};

render() {
const {i18n} = this.props;
const {t} = this.props;
const navBarImg = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAkCAYAAADhAJiYAAACHklEQVR4Ae3WAWTjUBjA8UNRFMVQFMUwHIahCI7hMBTFUBTDYQiG4RAUBRSHAIaiKIrhAFAURVAURREERVAMRe+PfTzP+faSJsy2Pz9M0rcvSdPk26foq+PxeIkBZlhi+2qOKR5xXvYQVfiI4doa/TKG6WCDvEXwihpmALsdntBFG61XHnqYYA+zA+5OGaSCKcwS3KPieIkDpDAb5h1oCLNn1HOs08QCZndZF7mF2QiVE2+IqXX5vCwfTiDNCrxLF5Ai1w8GkLaoFXi3NpFC6r99FMoH+PsBEUK0lHW+Y4IF+soBr98a6BrSxtrWhlmorPMX0gFN66D3kM61gUJIQ2ubD7OVsk4Ks661fQLpURtoCcmztjVwgPSgrPMH0g5Va3sP0lQbKIYkp9keykfb4Qv8E79Q/882D9JcW4SISn5QtyBt38NATUixtmMCqVHiQG1IC23HCNJViQN1Ic20HZ8gBcoPWtZ6+v/RX8SkyNpWR4ysLezXGuwgXWoD1fAC6ca+XbGHawkurDXuIcUu13cEaYWK/YLveKbWaNlnGQkk32WgOlJIofLCn8Auxm9U7UuFZ0gb/R1Lf275yr5n8PADFw5nXupkvTXHMAv1I1K/lzOYBXnf8OYwW+Emwxp9bGE2OfW1cwy7CAGu0LAeCR6G2MBuUNQvq48UeUtwW/TP/RlGeIFrKQJUy3xS19DBGBF2kGIsEeJaBvnqQ/cPDxGlXpRi3oIAAAAASUVORK5CYII=";
const navBarLinksClasses = ['nav-link', styles.Link];

const {i18n} = this.props;
const changeLanguage = (lng: any) => {
i18n.changeLanguage(lng);
};

return (
<>
<Navbar bg="dark" variant="dark" expand="lg">
Expand Down
2 changes: 1 addition & 1 deletion api/front-end/src/pages/Plates/Cars/Cars.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ class Cars extends Component<ReduxPropsInterface & WithTranslation> {

async loadLicensePlateDetections(startDate: string, endDate: string) {
const licensePlateDetections = await getLicensePlateDetections(
this.state.resultOption, startDate, endDate) as LicensePlateDetectionsInterface[];
this.state.resultOption, '', startDate, endDate) as LicensePlateDetectionsInterface[];
this.setState({
dateRangeStartDate: startDate,
dateRangeEndDate: endDate,
Expand Down
12 changes: 12 additions & 0 deletions api/front-end/src/utils/DateUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,15 @@ export const ChangeDate = (selectedDate: string, days: number) => {
date.setDate(date.getDate() + days);
return date.toISOString().substr(0, 10);
};

/**
* Is provided date timestamp older than one hour
* @param date action date
* @constructor
* @return boolean
*/
export const DateIsOlderThanHour = (date: number): boolean => {
const hour = 1000 * 60 * 60;
const hourAgo = Date.now() - hour;
return date < hourAgo;
};
3 changes: 2 additions & 1 deletion api/front-end/src/utils/HttpUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -221,9 +221,10 @@ export interface LicensePlateDetectionsInterface {
objectDetectionFileName: string;
}

export async function getLicensePlateDetections(resultOption: string, startDate: string, endDate: string) {
export async function getLicensePlateDetections(resultOption: string, selectedDate: string, startDate: string, endDate: string) {
const response = await axios.post(GET_LICENSE_PLATE_DETECTIONS, {
resultOption: resultOption,
selectedDate: selectedDate,
selectedDateStart: startDate,
selectedDateEnd: endDate,
});
Expand Down

0 comments on commit 4de96a3

Please sign in to comment.