scottlamb / moonfire-nvr

Moonfire NVR, a security camera network video recorder
Other
1.24k stars 137 forks source link

Date picker is unclickable #93

Closed slayerjain closed 3 years ago

slayerjain commented 4 years ago

I recently installed this on an OrangePi Plus 2 with Armbian (based on Ubuntu 20.04). The installation process was smooth.

However, the calendar seems to be unclickable, and the date logged in the console is 1 day older than today. Hence, it's not showing any recordings. When I manually change the from/to timestamps in the API call, I'm able to see recordings in the API call.

I suspect this is related to timezones. I'm in GMT+5:30 and the server has the right timezone, along with the browser. To avoid this maybe you could allow picking dates in the calendar even though there were no recordings. I'd really appreciate an easy fix so that I can test the setup :)

Screenshot 2020-08-09 at 8 28 18 PM
scottlamb commented 4 years ago

Thanks for the clear bug report! I am able to reproduce by using time zone Asia/Kolkata.

I think the problem is here:

https://github.com/scottlamb/moonfire-nvr/blob/459615a616cdf1783f5eec636aa74860b77cc245/ui-src/lib/views/CalendarView.js#L164

Date.toISOString() uses UTC when converting to a date. That's not right for my time zone either (America/Los_Angeles, currently UTC-07:00), which leaves me wondering why I can select the current day if I load the page after 17:00 local time.

scottlamb commented 4 years ago

Oh, the date object it receives is always midnight in the local time (according to the browser). It's broken if and only if your time zone is east of the International Date Line UTC.

new Date('2020-08-10T00:00:00+0000').toUTCString()
"Mon, 10 Aug 2020 00:00:00 GMT"
new Date('2020-08-10T00:00:00+0001').toUTCString()
"Sun, 09 Aug 2020 23:59:00 GMT"
new Date('2020-08-10T00:00:00+0000').toUTCString()
"Mon, 10 Aug 2020 00:00:00 GMT"
new Date('2020-08-10T00:00:00-0001').toUTCString()
"Mon, 10 Aug 2020 00:01:00 GMT"
slayerjain commented 4 years ago

That's very interesting. Can you please suggest what's the easiest way to apply a patch to the frontend without going through a 4 hour reinstall? (In case of OrangePi Plus 2)

scottlamb commented 4 years ago

The good news is that it shouldn't take four hours. The most time-consuming part was probably the clean build of the Rust stuff, and you don't need to repeat that. You can just patch the code, run yarn build to rebuild the Javascript UI, and re-install it (copy files from ui-dist/ to /usr/local/lib/moonfire-nvr/ui or wherever you put them before).

As for a patch, you might try this:

diff --git a/ui-src/lib/views/CalendarView.js b/ui-src/lib/views/CalendarView.js
index b1c1f72..1ea1c2d 100644
--- a/ui-src/lib/views/CalendarView.js
+++ b/ui-src/lib/views/CalendarView.js
@@ -161,7 +161,10 @@ export default class CalendarView {
     const fromPickerView = this.fromPickerView_;
     const toPickerView = this.toPickerView_;
     const beforeShowDay = function(date) {
-      const dateStr = date.toISOString().substr(0, 10);
+      const year = date.getYear() + 1900;
+      const month = (date.getMonth() + 1).toString().padStart(2, '0');
+      const day = date.getDate().toString().padStart(2, '0');
+      const dateStr = [year, month, day].join('-');
       return [dateSet.has(dateStr), '', ''];
     };

@@ -170,6 +173,7 @@ export default class CalendarView {
         dateFormat: DatePickerView.datepicker.ISO_8601,
         minDate: minDateStr,
         maxDate: maxDateStr,
+        defaultDate: maxDateStr,
         onSelect: (dateStr /* , picker */) =>
           this.updateRangeDates_(dateStr, dateStr),
         beforeShowDay: beforeShowDay,
@@ -181,6 +185,8 @@ export default class CalendarView {
       fromPickerView.option({
         dateFormat: DatePickerView.datepicker.ISO_8601,
         minDate: minDateStr,
+        maxDate: maxDateStr,
+        defaultDate: maxDateStr,
         onSelect: (dateStr /* , picker */) => {
           toPickerView.minDate = this.fromDateISO;
           this.updateRangeDates_(dateStr, this.toDateISO);
@@ -192,6 +198,7 @@ export default class CalendarView {
         dateFormat: DatePickerView.datepicker.ISO_8601,
         minDate: fromPickerView.dateISO,
         maxDate: maxDateStr,
+        defaultDate: maxDateStr,
         onSelect: (dateStr /* , picker */) => {
           fromPickerView.maxDate = this.toDateISO;
           this.updateRangeDates_(this.fromDateISO, dateStr);
diff --git a/ui-src/lib/views/DatePickerView.js b/ui-src/lib/views/DatePickerView.js
index fb08122..20ee2e7 100644
--- a/ui-src/lib/views/DatePickerView.js
+++ b/ui-src/lib/views/DatePickerView.js
@@ -215,7 +215,10 @@ export default class DatePickerView {
    * @return {String} Date portion of ISO-8601 formatted selected date
    */
   get dateISO() {
-    return this.date.toISOString().substr(0, 10);
+    const year = this.date.getYear() + 1900;
+    const month = (this.date.getMonth() + 1).toString().padStart(2, '0');
+    const day = this.date.getDate().toString().padStart(2, '0');
+    return [year, month, day].join('-');
   }

   /**

I haven't committed it because the date picker logic is a little strange and I haven't tested this thoroughly. But it at least shouldn't make it impossible for most of the world's population to select today.

slayerjain commented 4 years ago

Thanks a lot, It worked! 👍