Custom time picker
This commit is contained in:
parent
d068782596
commit
71e7857e9a
101
package-lock.json
generated
101
package-lock.json
generated
@ -6,7 +6,6 @@
|
|||||||
"": {
|
"": {
|
||||||
"name": "example",
|
"name": "example",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"air-datepicker": "^3.4.0",
|
|
||||||
"axios": "^1.5.1",
|
"axios": "^1.5.1",
|
||||||
"bulma": "^0.9.4",
|
"bulma": "^0.9.4",
|
||||||
"luxon": "^3.4.3",
|
"luxon": "^3.4.3",
|
||||||
@ -22,6 +21,7 @@
|
|||||||
"eslint": "^8.50.0",
|
"eslint": "^8.50.0",
|
||||||
"eslint-config-preact": "^1.3.0",
|
"eslint-config-preact": "^1.3.0",
|
||||||
"prettier": "^3.0.3",
|
"prettier": "^3.0.3",
|
||||||
|
"react-datepicker": "^4.21.0",
|
||||||
"typescript": "^5.2.2",
|
"typescript": "^5.2.2",
|
||||||
"vite": "^4.3.2"
|
"vite": "^4.3.2"
|
||||||
}
|
}
|
||||||
@ -1047,6 +1047,16 @@
|
|||||||
"node": ">= 8"
|
"node": ">= 8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@popperjs/core": {
|
||||||
|
"version": "2.11.8",
|
||||||
|
"resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz",
|
||||||
|
"integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==",
|
||||||
|
"dev": true,
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/popperjs"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@preact/preset-vite": {
|
"node_modules/@preact/preset-vite": {
|
||||||
"version": "2.6.0",
|
"version": "2.6.0",
|
||||||
"resolved": "https://registry.npmjs.org/@preact/preset-vite/-/preset-vite-2.6.0.tgz",
|
"resolved": "https://registry.npmjs.org/@preact/preset-vite/-/preset-vite-2.6.0.tgz",
|
||||||
@ -1370,11 +1380,6 @@
|
|||||||
"acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
|
"acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/air-datepicker": {
|
|
||||||
"version": "3.4.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/air-datepicker/-/air-datepicker-3.4.0.tgz",
|
|
||||||
"integrity": "sha512-MFr+2QYdHgrbd6Ah32hxoSCsmNJdrhYSkhr6hhefLpJBtsvX7zdYSvizsCJg15B2000NrEXep8UCYOsWy39iiw=="
|
|
||||||
},
|
|
||||||
"node_modules/ajv": {
|
"node_modules/ajv": {
|
||||||
"version": "6.12.6",
|
"version": "6.12.6",
|
||||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
|
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
|
||||||
@ -1726,6 +1731,12 @@
|
|||||||
"node": ">=4"
|
"node": ">=4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/classnames": {
|
||||||
|
"version": "2.3.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/classnames/-/classnames-2.3.2.tgz",
|
||||||
|
"integrity": "sha512-CSbhY4cFEJRe6/GQzIk5qXZ4Jeg5pcsP7b5peFSDpffpe1cqjASH/n9UTjBwOp6XpMSTwQ8Za2K5V02ueA7Tmw==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"node_modules/color-convert": {
|
"node_modules/color-convert": {
|
||||||
"version": "1.9.3",
|
"version": "1.9.3",
|
||||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
|
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
|
||||||
@ -1777,6 +1788,22 @@
|
|||||||
"node": ">= 8"
|
"node": ">= 8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/date-fns": {
|
||||||
|
"version": "2.30.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.30.0.tgz",
|
||||||
|
"integrity": "sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@babel/runtime": "^7.21.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.11"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/date-fns"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/debug": {
|
"node_modules/debug": {
|
||||||
"version": "4.3.4",
|
"version": "4.3.4",
|
||||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
|
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
|
||||||
@ -3920,6 +3947,24 @@
|
|||||||
"react-dom": ">=16.8.0"
|
"react-dom": ">=16.8.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/react-datepicker": {
|
||||||
|
"version": "4.21.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-datepicker/-/react-datepicker-4.21.0.tgz",
|
||||||
|
"integrity": "sha512-z0DtuRrKMz9i7dcTusW29VacbM9pn08g1yw0cG+Y5GpodJDxSWv7zUMxl3IwKN9Ap/AMphiepvmT5P+iNCgEiA==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@popperjs/core": "^2.11.8",
|
||||||
|
"classnames": "^2.2.6",
|
||||||
|
"date-fns": "^2.30.0",
|
||||||
|
"prop-types": "^15.7.2",
|
||||||
|
"react-onclickoutside": "^6.13.0",
|
||||||
|
"react-popper": "^2.3.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": "^16.9.0 || ^17 || ^18",
|
||||||
|
"react-dom": "^16.9.0 || ^17 || ^18"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/react-dom": {
|
"node_modules/react-dom": {
|
||||||
"version": "18.2.0",
|
"version": "18.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz",
|
||||||
@ -3933,12 +3978,47 @@
|
|||||||
"react": "^18.2.0"
|
"react": "^18.2.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/react-fast-compare": {
|
||||||
|
"version": "3.2.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-3.2.2.tgz",
|
||||||
|
"integrity": "sha512-nsO+KSNgo1SbJqJEYRE9ERzo7YtYbou/OqjSQKxV7jcKox7+usiUVZOAC+XnDOABXggQTno0Y1CpVnuWEc1boQ==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"node_modules/react-is": {
|
"node_modules/react-is": {
|
||||||
"version": "16.13.1",
|
"version": "16.13.1",
|
||||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
||||||
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
|
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/react-onclickoutside": {
|
||||||
|
"version": "6.13.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-onclickoutside/-/react-onclickoutside-6.13.0.tgz",
|
||||||
|
"integrity": "sha512-ty8So6tcUpIb+ZE+1HAhbLROvAIJYyJe/1vRrrcmW+jLsaM+/powDRqxzo6hSh9CuRZGSL1Q8mvcF5WRD93a0A==",
|
||||||
|
"dev": true,
|
||||||
|
"funding": {
|
||||||
|
"type": "individual",
|
||||||
|
"url": "https://github.com/Pomax/react-onclickoutside/blob/master/FUNDING.md"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": "^15.5.x || ^16.x || ^17.x || ^18.x",
|
||||||
|
"react-dom": "^15.5.x || ^16.x || ^17.x || ^18.x"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/react-popper": {
|
||||||
|
"version": "2.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-popper/-/react-popper-2.3.0.tgz",
|
||||||
|
"integrity": "sha512-e1hj8lL3uM+sgSR4Lxzn5h1GxBlpa4CQz0XLF8kx4MDrDRWY0Ena4c97PUeSX9i5W3UAfDP0z0FXCTQkoXUl3Q==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"react-fast-compare": "^3.0.1",
|
||||||
|
"warning": "^4.0.2"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@popperjs/core": "^2.0.0",
|
||||||
|
"react": "^16.8.0 || ^17 || ^18",
|
||||||
|
"react-dom": "^16.8.0 || ^17 || ^18"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/react-query": {
|
"node_modules/react-query": {
|
||||||
"version": "3.39.3",
|
"version": "3.39.3",
|
||||||
"resolved": "https://registry.npmjs.org/react-query/-/react-query-3.39.3.tgz",
|
"resolved": "https://registry.npmjs.org/react-query/-/react-query-3.39.3.tgz",
|
||||||
@ -4626,6 +4706,15 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/warning": {
|
||||||
|
"version": "4.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz",
|
||||||
|
"integrity": "sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"loose-envify": "^1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/which": {
|
"node_modules/which": {
|
||||||
"version": "2.0.2",
|
"version": "2.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
|
||||||
|
@ -8,7 +8,6 @@
|
|||||||
"preview": "vite preview"
|
"preview": "vite preview"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"air-datepicker": "^3.4.0",
|
|
||||||
"axios": "^1.5.1",
|
"axios": "^1.5.1",
|
||||||
"bulma": "^0.9.4",
|
"bulma": "^0.9.4",
|
||||||
"luxon": "^3.4.3",
|
"luxon": "^3.4.3",
|
||||||
@ -24,6 +23,7 @@
|
|||||||
"eslint": "^8.50.0",
|
"eslint": "^8.50.0",
|
||||||
"eslint-config-preact": "^1.3.0",
|
"eslint-config-preact": "^1.3.0",
|
||||||
"prettier": "^3.0.3",
|
"prettier": "^3.0.3",
|
||||||
|
"react-datepicker": "^4.21.0",
|
||||||
"typescript": "^5.2.2",
|
"typescript": "^5.2.2",
|
||||||
"vite": "^4.3.2"
|
"vite": "^4.3.2"
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,7 @@ import { useReminder } from "./ReminderContext";
|
|||||||
import { Attachment } from "./Attachment";
|
import { Attachment } from "./Attachment";
|
||||||
import { TTS } from "./TTS";
|
import { TTS } from "./TTS";
|
||||||
import { useTimezone } from "../App/TimezoneProvider";
|
import { useTimezone } from "../App/TimezoneProvider";
|
||||||
|
import { TimeInput } from "./TimeInput";
|
||||||
|
|
||||||
export const Settings = () => {
|
export const Settings = () => {
|
||||||
const { isSuccess: userFetched, data: userInfo } = useQuery(fetchUserInfo());
|
const { isSuccess: userFetched, data: userInfo } = useQuery(fetchUserInfo());
|
||||||
@ -41,21 +42,15 @@ export const Settings = () => {
|
|||||||
<div class="control">
|
<div class="control">
|
||||||
<label class="label collapses">
|
<label class="label collapses">
|
||||||
Time*
|
Time*
|
||||||
<input
|
<TimeInput
|
||||||
class="input"
|
defaultValue={reminder.utc_time}
|
||||||
type="datetime-local"
|
onInput={(time: DateTime) => {
|
||||||
step="1"
|
|
||||||
name="time"
|
|
||||||
value={reminder.utc_time
|
|
||||||
.setZone(timezone)
|
|
||||||
.toFormat("yyyy-LL-dd'T'HH:mm:ss")}
|
|
||||||
onInput={(ev) => {
|
|
||||||
setReminder((reminder) => ({
|
setReminder((reminder) => ({
|
||||||
...reminder,
|
...reminder,
|
||||||
utc_time: DateTime.fromISO(ev.currentTarget.value).toUTC(),
|
utc_time: time,
|
||||||
}));
|
}));
|
||||||
}}
|
}}
|
||||||
></input>
|
/>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -102,28 +97,15 @@ export const Settings = () => {
|
|||||||
<div class="control">
|
<div class="control">
|
||||||
<label class="label">
|
<label class="label">
|
||||||
Expiration
|
Expiration
|
||||||
<input
|
<TimeInput
|
||||||
class="input"
|
defaultValue={reminder.expires}
|
||||||
type="datetime-local"
|
onInput={(time: DateTime) => {
|
||||||
step="1"
|
|
||||||
name="expiration"
|
|
||||||
value={
|
|
||||||
reminder.expires !== null &&
|
|
||||||
reminder.expires
|
|
||||||
.setZone(timezone)
|
|
||||||
.toFormat("yyyy-LL-dd'T'HH:mm:ss")
|
|
||||||
}
|
|
||||||
onInput={(ev) => {
|
|
||||||
setReminder((reminder) => ({
|
setReminder((reminder) => ({
|
||||||
...reminder,
|
...reminder,
|
||||||
expires: ev.currentTarget.value
|
expires: time,
|
||||||
? DateTime.fromISO(
|
|
||||||
ev.currentTarget.value,
|
|
||||||
).toUTC()
|
|
||||||
: null,
|
|
||||||
}));
|
}));
|
||||||
}}
|
}}
|
||||||
></input>
|
/>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
65
src/components/Reminder/TimeInput.tsx
Normal file
65
src/components/Reminder/TimeInput.tsx
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
import { useEffect, useRef, useState } from "preact/hooks";
|
||||||
|
import { DateTime } from "luxon";
|
||||||
|
import { useTimezone } from "../App/TimezoneProvider";
|
||||||
|
|
||||||
|
export const TimeInput = ({ defaultValue, onInput }) => {
|
||||||
|
const format = "yyyy-LL-dd, HH:mm:ss";
|
||||||
|
const ref = useRef(null);
|
||||||
|
|
||||||
|
const [zone] = useTimezone();
|
||||||
|
const [time, setTime] = useState(defaultValue);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
onInput(time);
|
||||||
|
}, [time]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div class={"input"}>
|
||||||
|
<input
|
||||||
|
placeholder={"YYYY-MM-DD, hh:mm:ss"}
|
||||||
|
style={{
|
||||||
|
border: "none",
|
||||||
|
fontSize: "16px",
|
||||||
|
}}
|
||||||
|
value={time && time.toFormat(format)}
|
||||||
|
onInput={(ev) => {
|
||||||
|
const dt = DateTime.fromFormat(ev.currentTarget.value, format);
|
||||||
|
if (dt.isValid) {
|
||||||
|
setTime(dt);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
></input>
|
||||||
|
<button
|
||||||
|
style={{
|
||||||
|
background: "none",
|
||||||
|
border: "none",
|
||||||
|
padding: "1px",
|
||||||
|
marginRight: "-3px",
|
||||||
|
}}
|
||||||
|
onClick={() => {
|
||||||
|
ref.current.showPicker();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<span class="is-sr-only">Clear interval</span>
|
||||||
|
<span class="icon">
|
||||||
|
<i class="fas fa-calendar"></i>
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<input
|
||||||
|
style={{
|
||||||
|
visibility: "hidden",
|
||||||
|
}}
|
||||||
|
type="datetime-local"
|
||||||
|
step="1"
|
||||||
|
name="time"
|
||||||
|
value={time && time.toFormat("yyyy-LL-dd'T'HH:mm:ss")}
|
||||||
|
ref={ref}
|
||||||
|
onInput={(ev) => {
|
||||||
|
setTime(DateTime.fromISO(ev.currentTarget.value));
|
||||||
|
}}
|
||||||
|
></input>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
Loading…
Reference in New Issue
Block a user