Skip to content

Commit ebd4b76

Browse files
authored
Reduce UI artefact size by removing moment.js
Remove moment.js dependency
1 parent 7b59fb2 commit ebd4b76

File tree

8 files changed

+92
-40
lines changed

8 files changed

+92
-40
lines changed

interface/.env.development

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
# Change the IP address to that of your ESP device to enable local development of the UI.
22
# Remember to also enable CORS in platformio.ini before uploading the code to the device.
3-
REACT_APP_HTTP_ROOT=http://192.168.0.88
4-
REACT_APP_WEB_SOCKET_ROOT=ws://192.168.0.88
3+
REACT_APP_HTTP_ROOT=http://192.168.0.24
4+
REACT_APP_WEB_SOCKET_ROOT=ws://192.168.0.24

interface/package-lock.json

+5-5
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

interface/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@
1616
"jwt-decode": "^3.1.2",
1717
"lodash": "^4.17.20",
1818
"mime-types": "^2.1.28",
19-
"moment": "^2.29.1",
2019
"notistack": "^1.0.3",
20+
"parse-ms": "^2.1.0",
2121
"react": "^17.0.1",
2222
"react-dom": "^17.0.1",
2323
"react-dropzone": "^11.2.4",

interface/src/ntp/NTPStatusForm.tsx

+18-19
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import React, { Component, Fragment } from 'react';
2-
import moment from 'moment';
32

43
import { WithTheme, withTheme } from '@material-ui/core/styles';
54
import { Avatar, Divider, List, ListItem, ListItemAvatar, ListItemText, Button } from '@material-ui/core';
@@ -14,7 +13,7 @@ import RefreshIcon from '@material-ui/icons/Refresh';
1413

1514
import { RestFormProps, FormButton, HighlightAvatar } from '../components';
1615
import { isNtpActive, ntpStatusHighlight, ntpStatus } from './NTPStatus';
17-
import { formatIsoDateTime, formatLocalDateTime } from './TimeFormat';
16+
import { formatDuration, formatDateTime, formatLocalDateTime } from './TimeFormat';
1817
import { NTPStatus, Time } from './types';
1918
import { redirectingAuthorizedFetch, withAuthenticatedContext, AuthenticatedContextProps } from '../authentication';
2019
import { TIME_ENDPOINT } from '../api';
@@ -39,34 +38,34 @@ class NTPStatusForm extends Component<NTPStatusFormProps, NTPStatusFormState> {
3938
}
4039

4140
updateLocalTime = (event: React.ChangeEvent<HTMLInputElement>) => {
42-
this.setState({ localTime: event.target.value });
41+
this.setState({
42+
localTime: event.target.value
43+
});
4344
}
4445

4546
openSetTime = () => {
46-
this.setState({ localTime: formatLocalDateTime(moment()), settingTime: true, });
47+
this.setState({
48+
localTime: formatLocalDateTime(new Date()),
49+
settingTime: true
50+
});
4751
}
4852

4953
closeSetTime = () => {
50-
this.setState({ settingTime: false });
54+
this.setState({
55+
settingTime: false
56+
});
5157
}
5258

53-
createAdjustedTime = (): Time => {
54-
const currentLocalTime = moment(this.props.data.time_local);
55-
const newLocalTime = moment(this.state.localTime);
56-
newLocalTime.subtract(currentLocalTime.utcOffset())
57-
newLocalTime.milliseconds(0);
58-
newLocalTime.utc();
59-
return {
60-
time_utc: newLocalTime.format()
61-
}
62-
}
59+
createTime = (): Time => ({
60+
local_time: formatLocalDateTime(new Date(this.state.localTime))
61+
});
6362

6463
configureTime = () => {
6564
this.setState({ processing: true });
6665
redirectingAuthorizedFetch(TIME_ENDPOINT,
6766
{
6867
method: 'POST',
69-
body: JSON.stringify(this.createAdjustedTime()),
68+
body: JSON.stringify(this.createTime()),
7069
headers: {
7170
'Content-Type': 'application/json'
7271
}
@@ -153,7 +152,7 @@ class NTPStatusForm extends Component<NTPStatusFormProps, NTPStatusFormState> {
153152
<AccessTimeIcon />
154153
</Avatar>
155154
</ListItemAvatar>
156-
<ListItemText primary="Local Time" secondary={formatIsoDateTime(data.time_local)} />
155+
<ListItemText primary="Local Time" secondary={formatDateTime(data.local_time)} />
157156
</ListItem>
158157
<Divider variant="inset" component="li" />
159158
<ListItem>
@@ -162,7 +161,7 @@ class NTPStatusForm extends Component<NTPStatusFormProps, NTPStatusFormState> {
162161
<SwapVerticalCircleIcon />
163162
</Avatar>
164163
</ListItemAvatar>
165-
<ListItemText primary="UTC Time" secondary={formatIsoDateTime(data.time_utc)} />
164+
<ListItemText primary="UTC Time" secondary={formatDateTime(data.utc_time)} />
166165
</ListItem>
167166
<Divider variant="inset" component="li" />
168167
<ListItem>
@@ -171,7 +170,7 @@ class NTPStatusForm extends Component<NTPStatusFormProps, NTPStatusFormState> {
171170
<AvTimerIcon />
172171
</Avatar>
173172
</ListItemAvatar>
174-
<ListItemText primary="Uptime" secondary={moment.duration(data.uptime, 'seconds').humanize()} />
173+
<ListItemText primary="Uptime" secondary={formatDuration(data.uptime)} />
175174
</ListItem>
176175
<Divider variant="inset" component="li" />
177176
</List>

interface/src/ntp/TimeFormat.ts

+43-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,45 @@
1-
import moment, { Moment } from 'moment';
1+
import parseMilliseconds from 'parse-ms';
22

3-
export const formatIsoDateTime = (isoDateString: string) => moment.parseZone(isoDateString).format('ll @ HH:mm:ss');
3+
const LOCALE_FORMAT = new Intl.DateTimeFormat(
4+
[...window.navigator.languages],
5+
{
6+
day: 'numeric',
7+
month: 'short',
8+
year: 'numeric',
9+
hour: 'numeric',
10+
minute: 'numeric',
11+
second: 'numeric',
12+
hour12: false
13+
}
14+
);
415

5-
export const formatLocalDateTime = (moment: Moment) => moment.format('YYYY-MM-DDTHH:mm');
16+
export const formatDateTime = (dateTime: string) => {
17+
return LOCALE_FORMAT.format(new Date(dateTime.substr(0, 19)));
18+
}
19+
20+
export const formatLocalDateTime = (date: Date) => {
21+
return new Date(date.getTime() - date.getTimezoneOffset() * 60000)
22+
.toISOString()
23+
.slice(0, -1)
24+
.substr(0, 19);
25+
}
26+
27+
export const formatDuration = (duration: number) => {
28+
const { days, hours, minutes, seconds } = parseMilliseconds(duration * 1000);
29+
var formatted = '';
30+
if (days) {
31+
formatted += pluralize(days, 'day');
32+
}
33+
if (formatted || hours) {
34+
formatted += pluralize(hours, 'hour');
35+
}
36+
if (formatted || minutes) {
37+
formatted += pluralize(minutes, 'minute');
38+
}
39+
if (formatted || seconds) {
40+
formatted += pluralize(seconds, 'second');
41+
}
42+
return formatted;
43+
}
44+
45+
const pluralize = (count: number, noun: string, suffix: string = 's') => ` ${count} ${noun}${count !== 1 ? suffix : ''} `;

interface/src/ntp/types.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ export enum NTPSyncStatus {
55

66
export interface NTPStatus {
77
status: NTPSyncStatus;
8-
time_utc: string;
9-
time_local: string;
8+
utc_time: string;
9+
local_time: string;
1010
server: string;
1111
uptime: number;
1212
}
@@ -19,5 +19,5 @@ export interface NTPSettings {
1919
}
2020

2121
export interface Time {
22-
time_utc: string;
22+
local_time: string;
2323
}

lib/framework/NTPSettingsService.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -73,9 +73,9 @@ void NTPSettingsService::configureNTP() {
7373

7474
void NTPSettingsService::configureTime(AsyncWebServerRequest* request, JsonVariant& json) {
7575
if (!sntp_enabled() && json.is<JsonObject>()) {
76-
String timeUtc = json["time_utc"];
7776
struct tm tm = {0};
78-
char* s = strptime(timeUtc.c_str(), "%Y-%m-%dT%H:%M:%SZ", &tm);
77+
String timeLocal = json["local_time"];
78+
char* s = strptime(timeLocal.c_str(), "%Y-%m-%dT%H:%M:%S", &tm);
7979
if (s != nullptr) {
8080
time_t time = mktime(&tm);
8181
struct timeval now = {.tv_sec = time};

lib/framework/NTPStatus.cpp

+18-5
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,25 @@ NTPStatus::NTPStatus(AsyncWebServer* server, SecurityManager* securityManager) {
77
AuthenticationPredicates::IS_AUTHENTICATED));
88
}
99

10-
String toISOString(tm* time, bool incOffset) {
10+
/*
11+
* Formats the time using the format provided.
12+
*
13+
* Uses a 25 byte buffer, large enough to fit an ISO time string with offset.
14+
*/
15+
String formatTime(tm* time, const char* format) {
1116
char time_string[25];
12-
strftime(time_string, 25, incOffset ? "%FT%T%z" : "%FT%TZ", time);
17+
strftime(time_string, 25, format, time);
1318
return String(time_string);
1419
}
1520

21+
String toUTCTimeString(tm* time) {
22+
return formatTime(time, "%FT%TZ");
23+
}
24+
25+
String toLocalTimeString(tm* time) {
26+
return formatTime(time, "%FT%T");
27+
}
28+
1629
void NTPStatus::ntpStatus(AsyncWebServerRequest* request) {
1730
AsyncJsonResponse* response = new AsyncJsonResponse(false, MAX_NTP_STATUS_SIZE);
1831
JsonObject root = response->getRoot();
@@ -24,10 +37,10 @@ void NTPStatus::ntpStatus(AsyncWebServerRequest* request) {
2437
root["status"] = sntp_enabled() ? 1 : 0;
2538

2639
// the current time in UTC
27-
root["time_utc"] = toISOString(gmtime(&now), false);
40+
root["utc_time"] = toUTCTimeString(gmtime(&now));
2841

29-
// local time as ISO String with TZ
30-
root["time_local"] = toISOString(localtime(&now), true);
42+
// local time with offset
43+
root["local_time"] = toLocalTimeString(localtime(&now));
3144

3245
// the sntp server name
3346
root["server"] = sntp_getservername(0);

0 commit comments

Comments
 (0)