feat: add alarm and distance
This commit is contained in:
parent
d23e7661ae
commit
266f874f1a
|
|
@ -8,5 +8,5 @@ charset = utf-8
|
||||||
[{*.css,*.scss,*.less,*.overrides,*.variables}]
|
[{*.css,*.scss,*.less,*.overrides,*.variables}]
|
||||||
indent_size = 4
|
indent_size = 4
|
||||||
|
|
||||||
[{*.js,*.json}]
|
[{*.js,*.json,*.ts,*.tsx,*.jsx}]
|
||||||
indent_size = 2
|
indent_size = 2
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
{
|
{
|
||||||
"name": "walk-up-alarm",
|
"name": "walk-up-alarm",
|
||||||
|
"author": "nzambello",
|
||||||
|
"license": "MIT",
|
||||||
"version": "0.0.0",
|
"version": "0.0.0",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
|
|
@ -7,12 +9,16 @@
|
||||||
"serve": "vite preview"
|
"serve": "vite preview"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"geolib": "^3.3.3",
|
||||||
|
"rc-time-picker": "^3.7.3",
|
||||||
"react": "^17.0.0",
|
"react": "^17.0.0",
|
||||||
"react-dom": "^17.0.0"
|
"react-dom": "^17.0.0",
|
||||||
|
"use-position": "^1.0.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/react": "^17.0.0",
|
"@types/react": "^17.0.0",
|
||||||
"@types/react-dom": "^17.0.0",
|
"@types/react-dom": "^17.0.0",
|
||||||
|
"@types/use-position": "^0.0.0",
|
||||||
"@vitejs/plugin-react": "^1.0.0",
|
"@vitejs/plugin-react": "^1.0.0",
|
||||||
"typescript": "^4.3.2",
|
"typescript": "^4.3.2",
|
||||||
"vite": "^2.6.4",
|
"vite": "^2.6.4",
|
||||||
|
|
|
||||||
153
src/App.tsx
153
src/App.tsx
|
|
@ -1,45 +1,130 @@
|
||||||
import { useState } from 'react'
|
import { useCallback, useState, useRef, useEffect } from "react";
|
||||||
import logo from './logo.svg'
|
import { usePosition } from "use-position";
|
||||||
import './App.css'
|
import { getDistance } from "geolib";
|
||||||
|
import TimePicker from "rc-time-picker";
|
||||||
|
import moment from "moment";
|
||||||
|
|
||||||
|
import "./App.css";
|
||||||
|
import "rc-time-picker/assets/index.css";
|
||||||
|
|
||||||
|
import alarmMp3 from "./alarm.mp3";
|
||||||
|
import blankMp3 from "./blank.mp3";
|
||||||
|
|
||||||
function App() {
|
function App() {
|
||||||
const [count, setCount] = useState(0)
|
const [alarm, setAlarm] = useState<moment.Moment | null>(null);
|
||||||
|
const [alarmSet, setAlarmSet] = useState(false);
|
||||||
|
const [stopDistance, setStopDistance] = useState(10);
|
||||||
|
const audioRef = useRef<HTMLAudioElement>(null);
|
||||||
|
|
||||||
|
const { latitude, longitude, timestamp, accuracy } = usePosition(true, {
|
||||||
|
enableHighAccuracy: true,
|
||||||
|
timeout: Infinity,
|
||||||
|
maximumAge: 0,
|
||||||
|
});
|
||||||
|
|
||||||
|
interface ICoords {
|
||||||
|
latitude: number;
|
||||||
|
longitude: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
const [startCoords, setStartCoords] = useState<ICoords | null>(null);
|
||||||
|
useEffect(() => {
|
||||||
|
if (latitude && longitude && !startCoords) {
|
||||||
|
setStartCoords({ latitude, longitude });
|
||||||
|
}
|
||||||
|
}, [latitude, longitude, startCoords]);
|
||||||
|
|
||||||
|
const distance =
|
||||||
|
startCoords && latitude && longitude
|
||||||
|
? getDistance(startCoords, { latitude, longitude }, 0.01)
|
||||||
|
: 0;
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (alarmSet && distance > stopDistance) {
|
||||||
|
setAlarmSet(false);
|
||||||
|
setAlarm(null);
|
||||||
|
}
|
||||||
|
}, [distance, alarmSet]);
|
||||||
|
|
||||||
|
const showAlarm = () => {
|
||||||
|
console.log("ALARM! Wake up!");
|
||||||
|
audioRef.current?.play();
|
||||||
|
|
||||||
|
if (!("Notification" in window)) {
|
||||||
|
alert("This browser does not support desktop notification");
|
||||||
|
} else if (Notification.permission === "granted") {
|
||||||
|
var notification = new Notification("Wake up!");
|
||||||
|
} else if (Notification.permission !== "denied") {
|
||||||
|
Notification.requestPermission().then(function (permission) {
|
||||||
|
// If the user accepts, let's create a notification
|
||||||
|
if (permission === "granted") {
|
||||||
|
var notification = new Notification("Wake up!");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const registerAlarm = useCallback(() => {
|
||||||
|
if (alarm) {
|
||||||
|
audioRef.current?.play().then(() => {
|
||||||
|
setAlarmSet(true);
|
||||||
|
if (latitude && longitude) setStartCoords({ latitude, longitude });
|
||||||
|
const delay = alarm.diff(moment());
|
||||||
|
console.log("set alarm", delay);
|
||||||
|
setTimeout(() => {
|
||||||
|
showAlarm();
|
||||||
|
}, delay);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, [alarm]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="App">
|
<div className="App">
|
||||||
<header className="App-header">
|
<div className="App-header">
|
||||||
<img src={logo} className="App-logo" alt="logo" />
|
<TimePicker
|
||||||
<p>Hello Vite + React!</p>
|
defaultValue={moment().add(1, "hour")}
|
||||||
|
value={alarm ?? undefined}
|
||||||
|
onChange={(newTime) => setAlarm(newTime)}
|
||||||
|
showSecond={false}
|
||||||
|
/>
|
||||||
|
<input
|
||||||
|
type="number"
|
||||||
|
placeholder="distance"
|
||||||
|
min={1}
|
||||||
|
value={stopDistance}
|
||||||
|
onChange={(e) => setStopDistance(e.target.value)}
|
||||||
|
/>
|
||||||
<p>
|
<p>
|
||||||
<button type="button" onClick={() => setCount((count) => count + 1)}>
|
<button type="button" onClick={registerAlarm}>
|
||||||
count is: {count}
|
Set alarm
|
||||||
</button>
|
</button>
|
||||||
|
{alarmSet && (
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={() => {
|
||||||
|
setAlarm(null);
|
||||||
|
setAlarmSet(false);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Reset
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<audio src={alarmSet ? alarmMp3 : blankMp3} ref={audioRef} />
|
||||||
Edit <code>App.tsx</code> and save to test HMR updates.
|
{startCoords && (
|
||||||
</p>
|
<code>
|
||||||
<p>
|
original: {startCoords.latitude}, {startCoords.longitude}
|
||||||
<a
|
<br />
|
||||||
className="App-link"
|
current: {latitude}, {longitude}
|
||||||
href="https://reactjs.org"
|
<br />
|
||||||
target="_blank"
|
accuracy: {accuracy && `${accuracy} meters`}
|
||||||
rel="noopener noreferrer"
|
<br />
|
||||||
>
|
distance: {distance && `${distance} meters`}
|
||||||
Learn React
|
</code>
|
||||||
</a>
|
)}
|
||||||
{' | '}
|
</div>
|
||||||
<a
|
|
||||||
className="App-link"
|
|
||||||
href="https://vitejs.dev/guide/features.html"
|
|
||||||
target="_blank"
|
|
||||||
rel="noopener noreferrer"
|
|
||||||
>
|
|
||||||
Vite Docs
|
|
||||||
</a>
|
|
||||||
</p>
|
|
||||||
</header>
|
|
||||||
</div>
|
</div>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default App
|
export default App;
|
||||||
|
|
|
||||||
BIN
src/alarm.mp3
Normal file
BIN
src/alarm.mp3
Normal file
Binary file not shown.
BIN
src/blank.mp3
Normal file
BIN
src/blank.mp3
Normal file
Binary file not shown.
Loading…
Reference in a new issue