Start to build relay dialog
This commit is contained in:
		@@ -8,6 +8,12 @@ export interface ServerConfig {
 | 
			
		||||
export interface ServerConstraint {
 | 
			
		||||
  dev_name_len: LenConstraint;
 | 
			
		||||
  dev_description_len: LenConstraint;
 | 
			
		||||
  relay_name_len: LenConstraint;
 | 
			
		||||
  relay_priority: LenConstraint;
 | 
			
		||||
  relay_consumption: LenConstraint;
 | 
			
		||||
  relay_minimal_uptime: LenConstraint;
 | 
			
		||||
  relay_minimal_downtime: LenConstraint;
 | 
			
		||||
  relay_daily_minimal_runtime: LenConstraint;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface LenConstraint {
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										283
									
								
								central_frontend/src/dialogs/EditDeviceRelaysDialog.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										283
									
								
								central_frontend/src/dialogs/EditDeviceRelaysDialog.tsx
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,283 @@
 | 
			
		||||
import {
 | 
			
		||||
  Button,
 | 
			
		||||
  Dialog,
 | 
			
		||||
  DialogActions,
 | 
			
		||||
  DialogContent,
 | 
			
		||||
  DialogTitle,
 | 
			
		||||
  Grid,
 | 
			
		||||
  Typography,
 | 
			
		||||
} from "@mui/material";
 | 
			
		||||
import { TimePicker } from "@mui/x-date-pickers";
 | 
			
		||||
import React from "react";
 | 
			
		||||
import { Device, DeviceRelay } from "../api/DeviceApi";
 | 
			
		||||
import { ServerApi } from "../api/ServerApi";
 | 
			
		||||
import { useAlert } from "../hooks/context_providers/AlertDialogProvider";
 | 
			
		||||
import { useLoadingMessage } from "../hooks/context_providers/LoadingMessageProvider";
 | 
			
		||||
import { useSnackbar } from "../hooks/context_providers/SnackbarProvider";
 | 
			
		||||
import { dayjsToTimeOfDay, timeOfDay } from "../utils/DateUtils";
 | 
			
		||||
import { lenValid } from "../utils/StringsUtils";
 | 
			
		||||
import { CheckboxInput } from "../widgets/forms/CheckboxInput";
 | 
			
		||||
import { TextInput } from "../widgets/forms/TextInput";
 | 
			
		||||
 | 
			
		||||
export function EditDeviceRelaysDialog(p: {
 | 
			
		||||
  onClose: () => void;
 | 
			
		||||
  relay?: DeviceRelay;
 | 
			
		||||
  device: Device;
 | 
			
		||||
  onUpdated: () => void;
 | 
			
		||||
}): React.ReactElement {
 | 
			
		||||
  const loadingMessage = useLoadingMessage();
 | 
			
		||||
  const alert = useAlert();
 | 
			
		||||
  const snackbar = useSnackbar();
 | 
			
		||||
 | 
			
		||||
  const [relay, setRelay] = React.useState<DeviceRelay>(
 | 
			
		||||
    p.relay ?? {
 | 
			
		||||
      id: "",
 | 
			
		||||
      name: "relay",
 | 
			
		||||
      enabled: false,
 | 
			
		||||
      priority: 1,
 | 
			
		||||
      consumption: 500,
 | 
			
		||||
      minimal_downtime: 60 * 5,
 | 
			
		||||
      minimal_uptime: 60 * 5,
 | 
			
		||||
      depends_on: [],
 | 
			
		||||
      conflicts_with: [],
 | 
			
		||||
    }
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
  const creating = !p.relay;
 | 
			
		||||
 | 
			
		||||
  const onSubmit = async () => {
 | 
			
		||||
    try {
 | 
			
		||||
      loadingMessage.show(
 | 
			
		||||
        `${creating ? "Creating" : "Updating"} relay information`
 | 
			
		||||
      );
 | 
			
		||||
 | 
			
		||||
      // TODO
 | 
			
		||||
 | 
			
		||||
      snackbar(
 | 
			
		||||
        `The relay have been successfully ${creating ? "created" : "updated"}!`
 | 
			
		||||
      );
 | 
			
		||||
      p.onUpdated();
 | 
			
		||||
    } catch (e) {
 | 
			
		||||
      console.error("Failed to update device relay information!" + e);
 | 
			
		||||
      alert(`Failed to ${creating ? "create" : "update"} relay! ${e}`);
 | 
			
		||||
    } finally {
 | 
			
		||||
      loadingMessage.hide();
 | 
			
		||||
    }
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  const canSubmit =
 | 
			
		||||
    lenValid(relay.name, ServerApi.Config.constraints.relay_name_len) &&
 | 
			
		||||
    relay.priority >= 0;
 | 
			
		||||
 | 
			
		||||
  return (
 | 
			
		||||
    <Dialog open>
 | 
			
		||||
      <DialogTitle>Edit relay information</DialogTitle>
 | 
			
		||||
      <DialogContent>
 | 
			
		||||
        <DialogFormTitle>General info</DialogFormTitle>
 | 
			
		||||
        <Grid container spacing={2}>
 | 
			
		||||
          <Grid item xs={6}>
 | 
			
		||||
            <TextInput
 | 
			
		||||
              editable
 | 
			
		||||
              label="Relay name"
 | 
			
		||||
              value={relay.name}
 | 
			
		||||
              onValueChange={(v) =>
 | 
			
		||||
                setRelay((r) => {
 | 
			
		||||
                  return {
 | 
			
		||||
                    ...r,
 | 
			
		||||
                    name: v ?? "",
 | 
			
		||||
                  };
 | 
			
		||||
                })
 | 
			
		||||
              }
 | 
			
		||||
              size={ServerApi.Config.constraints.dev_name_len}
 | 
			
		||||
            />
 | 
			
		||||
          </Grid>
 | 
			
		||||
          <Grid item xs={6}>
 | 
			
		||||
            <CheckboxInput
 | 
			
		||||
              editable
 | 
			
		||||
              label="Enable relay"
 | 
			
		||||
              checked={relay.enabled}
 | 
			
		||||
              onValueChange={(v) =>
 | 
			
		||||
                setRelay((r) => {
 | 
			
		||||
                  return {
 | 
			
		||||
                    ...r,
 | 
			
		||||
                    enabled: v,
 | 
			
		||||
                  };
 | 
			
		||||
                })
 | 
			
		||||
              }
 | 
			
		||||
            />
 | 
			
		||||
          </Grid>
 | 
			
		||||
          <Grid item xs={6}>
 | 
			
		||||
            <TextInput
 | 
			
		||||
              editable
 | 
			
		||||
              label="Priority"
 | 
			
		||||
              value={relay.priority.toString()}
 | 
			
		||||
              type="number"
 | 
			
		||||
              onValueChange={(v) =>
 | 
			
		||||
                setRelay((r) => {
 | 
			
		||||
                  return {
 | 
			
		||||
                    ...r,
 | 
			
		||||
                    priority: Number(v) ?? 0,
 | 
			
		||||
                  };
 | 
			
		||||
                })
 | 
			
		||||
              }
 | 
			
		||||
              size={ServerApi.Config.constraints.relay_priority}
 | 
			
		||||
              helperText="Relay priority when selecting relays to turn on. 0 = lowest priority"
 | 
			
		||||
            />
 | 
			
		||||
          </Grid>
 | 
			
		||||
          <Grid item xs={6}>
 | 
			
		||||
            <TextInput
 | 
			
		||||
              editable
 | 
			
		||||
              label="Consumption"
 | 
			
		||||
              value={relay.consumption.toString()}
 | 
			
		||||
              type="number"
 | 
			
		||||
              onValueChange={(v) =>
 | 
			
		||||
                setRelay((r) => {
 | 
			
		||||
                  return {
 | 
			
		||||
                    ...r,
 | 
			
		||||
                    consumption: Number(v) ?? 0,
 | 
			
		||||
                  };
 | 
			
		||||
                })
 | 
			
		||||
              }
 | 
			
		||||
              size={ServerApi.Config.constraints.relay_consumption}
 | 
			
		||||
              helperText="Estimated consumption of device powered by relay"
 | 
			
		||||
            />
 | 
			
		||||
          </Grid>
 | 
			
		||||
          <Grid item xs={6}>
 | 
			
		||||
            <TextInput
 | 
			
		||||
              editable
 | 
			
		||||
              label="Minimal uptime"
 | 
			
		||||
              value={relay.minimal_uptime.toString()}
 | 
			
		||||
              type="number"
 | 
			
		||||
              onValueChange={(v) =>
 | 
			
		||||
                setRelay((r) => {
 | 
			
		||||
                  return {
 | 
			
		||||
                    ...r,
 | 
			
		||||
                    minimal_uptime: Number(v) ?? 0,
 | 
			
		||||
                  };
 | 
			
		||||
                })
 | 
			
		||||
              }
 | 
			
		||||
              size={ServerApi.Config.constraints.relay_minimal_uptime}
 | 
			
		||||
              helperText="Minimal time this relay shall be left on before it can be turned off (in seconds)"
 | 
			
		||||
            />
 | 
			
		||||
          </Grid>
 | 
			
		||||
          <Grid item xs={6}>
 | 
			
		||||
            <TextInput
 | 
			
		||||
              editable
 | 
			
		||||
              label="Minimal downtime"
 | 
			
		||||
              value={relay.minimal_downtime.toString()}
 | 
			
		||||
              type="number"
 | 
			
		||||
              onValueChange={(v) =>
 | 
			
		||||
                setRelay((r) => {
 | 
			
		||||
                  return {
 | 
			
		||||
                    ...r,
 | 
			
		||||
                    minimal_downtime: Number(v) ?? 0,
 | 
			
		||||
                  };
 | 
			
		||||
                })
 | 
			
		||||
              }
 | 
			
		||||
              size={ServerApi.Config.constraints.relay_minimal_downtime}
 | 
			
		||||
              helperText="Minimal time this relay shall be left on before it can be turned off (in seconds)"
 | 
			
		||||
            />
 | 
			
		||||
          </Grid>
 | 
			
		||||
        </Grid>
 | 
			
		||||
 | 
			
		||||
        <DialogFormTitle>Daily runtime</DialogFormTitle>
 | 
			
		||||
        <Grid container spacing={2}>
 | 
			
		||||
          <Grid item xs={6}>
 | 
			
		||||
            <CheckboxInput
 | 
			
		||||
              editable
 | 
			
		||||
              label="Enable minimal runtime"
 | 
			
		||||
              checked={!!relay.daily_runtime}
 | 
			
		||||
              onValueChange={(v) =>
 | 
			
		||||
                setRelay((r) => {
 | 
			
		||||
                  return {
 | 
			
		||||
                    ...r,
 | 
			
		||||
                    daily_runtime: v
 | 
			
		||||
                      ? { reset_time: 0, min_runtime: 3600, catch_up_hours: [] }
 | 
			
		||||
                      : undefined,
 | 
			
		||||
                  };
 | 
			
		||||
                })
 | 
			
		||||
              }
 | 
			
		||||
            />
 | 
			
		||||
          </Grid>
 | 
			
		||||
 | 
			
		||||
          {!!relay.daily_runtime && (
 | 
			
		||||
            <>
 | 
			
		||||
              <Grid item xs={6}>
 | 
			
		||||
                <TextInput
 | 
			
		||||
                  editable
 | 
			
		||||
                  label="Minimal daily runtime"
 | 
			
		||||
                  value={relay.daily_runtime!.min_runtime.toString()}
 | 
			
		||||
                  type="number"
 | 
			
		||||
                  onValueChange={(v) =>
 | 
			
		||||
                    setRelay((r) => {
 | 
			
		||||
                      return {
 | 
			
		||||
                        ...r,
 | 
			
		||||
                        daily_runtime: {
 | 
			
		||||
                          ...r.daily_runtime!,
 | 
			
		||||
                          min_runtime: Number(v),
 | 
			
		||||
                        },
 | 
			
		||||
                      };
 | 
			
		||||
                    })
 | 
			
		||||
                  }
 | 
			
		||||
                  size={
 | 
			
		||||
                    ServerApi.Config.constraints.relay_daily_minimal_runtime
 | 
			
		||||
                  }
 | 
			
		||||
                  helperText="Minimum time, in seconds, that this relay should run each day"
 | 
			
		||||
                />
 | 
			
		||||
              </Grid>
 | 
			
		||||
              <Grid item xs={6}>
 | 
			
		||||
                <TimePicker
 | 
			
		||||
                  label="Reset time"
 | 
			
		||||
                  value={timeOfDay(relay.daily_runtime!.reset_time)}
 | 
			
		||||
                  onChange={(d) =>
 | 
			
		||||
                    setRelay((r) => {
 | 
			
		||||
                      return {
 | 
			
		||||
                        ...r,
 | 
			
		||||
                        daily_runtime: {
 | 
			
		||||
                          ...r.daily_runtime!,
 | 
			
		||||
                          reset_time: d ? dayjsToTimeOfDay(d) : 0,
 | 
			
		||||
                        },
 | 
			
		||||
                      };
 | 
			
		||||
                    })
 | 
			
		||||
                  }
 | 
			
		||||
                />
 | 
			
		||||
              </Grid>
 | 
			
		||||
              <Grid item xs={6}>
 | 
			
		||||
                <TimePicker
 | 
			
		||||
                  label="Catch up hours"
 | 
			
		||||
                  value={timeOfDay(relay.daily_runtime!.reset_time)}
 | 
			
		||||
                  onChange={(d) =>
 | 
			
		||||
                    setRelay((r) => {
 | 
			
		||||
                      return {
 | 
			
		||||
                        ...r,
 | 
			
		||||
                        daily_runtime: {
 | 
			
		||||
                          ...r.daily_runtime!,
 | 
			
		||||
                          reset_time: d ? dayjsToTimeOfDay(d) : 0,
 | 
			
		||||
                        },
 | 
			
		||||
                      };
 | 
			
		||||
                    })
 | 
			
		||||
                  }
 | 
			
		||||
                />
 | 
			
		||||
              </Grid>
 | 
			
		||||
            </>
 | 
			
		||||
          )}
 | 
			
		||||
        </Grid>
 | 
			
		||||
      </DialogContent>
 | 
			
		||||
      <DialogActions>
 | 
			
		||||
        <Button onClick={p.onClose}>Cancel</Button>
 | 
			
		||||
        <Button onClick={onSubmit} autoFocus disabled={!canSubmit}>
 | 
			
		||||
          Submit
 | 
			
		||||
        </Button>
 | 
			
		||||
      </DialogActions>
 | 
			
		||||
    </Dialog>
 | 
			
		||||
  );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function DialogFormTitle(p: React.PropsWithChildren): React.ReactElement {
 | 
			
		||||
  return (
 | 
			
		||||
    <>
 | 
			
		||||
      <span style={{ height: "2px" }}></span>
 | 
			
		||||
      <Typography variant="h6">{p.children}</Typography>
 | 
			
		||||
    </>
 | 
			
		||||
  );
 | 
			
		||||
}
 | 
			
		||||
@@ -13,24 +13,28 @@ import { SnackbarProvider } from "./hooks/context_providers/SnackbarProvider";
 | 
			
		||||
import "./index.css";
 | 
			
		||||
import { ServerApi } from "./api/ServerApi";
 | 
			
		||||
import { AsyncWidget } from "./widgets/AsyncWidget";
 | 
			
		||||
import { LocalizationProvider } from "@mui/x-date-pickers";
 | 
			
		||||
import { AdapterDayjs } from "@mui/x-date-pickers/AdapterDayjs";
 | 
			
		||||
 | 
			
		||||
ReactDOM.createRoot(document.getElementById("root")!).render(
 | 
			
		||||
  <React.StrictMode>
 | 
			
		||||
    <DarkThemeProvider>
 | 
			
		||||
      <AlertDialogProvider>
 | 
			
		||||
        <ConfirmDialogProvider>
 | 
			
		||||
          <SnackbarProvider>
 | 
			
		||||
            <LoadingMessageProvider>
 | 
			
		||||
              <AsyncWidget
 | 
			
		||||
                loadKey={1}
 | 
			
		||||
                load={async () => await ServerApi.LoadConfig()}
 | 
			
		||||
                errMsg="Failed to connect to backend to retrieve static config!"
 | 
			
		||||
                build={() => <App />}
 | 
			
		||||
              />
 | 
			
		||||
            </LoadingMessageProvider>
 | 
			
		||||
          </SnackbarProvider>
 | 
			
		||||
        </ConfirmDialogProvider>
 | 
			
		||||
      </AlertDialogProvider>
 | 
			
		||||
    </DarkThemeProvider>
 | 
			
		||||
    <LocalizationProvider dateAdapter={AdapterDayjs}>
 | 
			
		||||
      <DarkThemeProvider>
 | 
			
		||||
        <AlertDialogProvider>
 | 
			
		||||
          <ConfirmDialogProvider>
 | 
			
		||||
            <SnackbarProvider>
 | 
			
		||||
              <LoadingMessageProvider>
 | 
			
		||||
                <AsyncWidget
 | 
			
		||||
                  loadKey={1}
 | 
			
		||||
                  load={async () => await ServerApi.LoadConfig()}
 | 
			
		||||
                  errMsg="Failed to connect to backend to retrieve static config!"
 | 
			
		||||
                  build={() => <App />}
 | 
			
		||||
                />
 | 
			
		||||
              </LoadingMessageProvider>
 | 
			
		||||
            </SnackbarProvider>
 | 
			
		||||
          </ConfirmDialogProvider>
 | 
			
		||||
        </AlertDialogProvider>
 | 
			
		||||
      </DarkThemeProvider>
 | 
			
		||||
    </LocalizationProvider>
 | 
			
		||||
  </React.StrictMode>
 | 
			
		||||
);
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										50
									
								
								central_frontend/src/routes/DeviceRoute/DeviceRelays.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								central_frontend/src/routes/DeviceRoute/DeviceRelays.tsx
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,50 @@
 | 
			
		||||
import AddIcon from "@mui/icons-material/Add";
 | 
			
		||||
import { IconButton, Tooltip } from "@mui/material";
 | 
			
		||||
import React from "react";
 | 
			
		||||
import { Device, DeviceRelay } from "../../api/DeviceApi";
 | 
			
		||||
import { DeviceRouteCard } from "./DeviceRouteCard";
 | 
			
		||||
import { EditDeviceRelaysDialog } from "../../dialogs/EditDeviceRelaysDialog";
 | 
			
		||||
 | 
			
		||||
export function DeviceRelays(p: {
 | 
			
		||||
  device: Device;
 | 
			
		||||
  onReload: () => void;
 | 
			
		||||
}): React.ReactElement {
 | 
			
		||||
  const [dialogOpen, setDialogOpen] = React.useState(false);
 | 
			
		||||
  const [currRelay, setCurrRelay] = React.useState<DeviceRelay | undefined>();
 | 
			
		||||
 | 
			
		||||
  const createNewRelay = () => {
 | 
			
		||||
    setDialogOpen(true);
 | 
			
		||||
    setCurrRelay(undefined);
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  return (
 | 
			
		||||
    <>
 | 
			
		||||
      {dialogOpen && (
 | 
			
		||||
        <EditDeviceRelaysDialog
 | 
			
		||||
          device={p.device}
 | 
			
		||||
          onClose={() => setDialogOpen(false)}
 | 
			
		||||
          relay={currRelay}
 | 
			
		||||
          onUpdated={() => {
 | 
			
		||||
            setDialogOpen(false);
 | 
			
		||||
            p.onReload();
 | 
			
		||||
          }}
 | 
			
		||||
        />
 | 
			
		||||
      )}
 | 
			
		||||
      <DeviceRouteCard
 | 
			
		||||
        title="Device relays"
 | 
			
		||||
        actions={
 | 
			
		||||
          <Tooltip title="Create new relay">
 | 
			
		||||
            <IconButton
 | 
			
		||||
              onClick={createNewRelay}
 | 
			
		||||
              disabled={p.device.relays.length >= p.device.info.max_relays}
 | 
			
		||||
            >
 | 
			
		||||
              <AddIcon />
 | 
			
		||||
            </IconButton>
 | 
			
		||||
          </Tooltip>
 | 
			
		||||
        }
 | 
			
		||||
      >
 | 
			
		||||
        TODO : relays list ({p.device.relays.length}) relays now)
 | 
			
		||||
      </DeviceRouteCard>
 | 
			
		||||
    </>
 | 
			
		||||
  );
 | 
			
		||||
}
 | 
			
		||||
@@ -1,5 +1,5 @@
 | 
			
		||||
import DeleteIcon from "@mui/icons-material/Delete";
 | 
			
		||||
import { IconButton, Tooltip } from "@mui/material";
 | 
			
		||||
import { Grid, IconButton, Tooltip } from "@mui/material";
 | 
			
		||||
import React from "react";
 | 
			
		||||
import { useNavigate, useParams } from "react-router-dom";
 | 
			
		||||
import { Device, DeviceApi } from "../../api/DeviceApi";
 | 
			
		||||
@@ -10,6 +10,7 @@ import { useSnackbar } from "../../hooks/context_providers/SnackbarProvider";
 | 
			
		||||
import { AsyncWidget } from "../../widgets/AsyncWidget";
 | 
			
		||||
import { SolarEnergyRouteContainer } from "../../widgets/SolarEnergyRouteContainer";
 | 
			
		||||
import { GeneralDeviceInfo } from "./GeneralDeviceInfo";
 | 
			
		||||
import { DeviceRelays } from "./DeviceRelays";
 | 
			
		||||
 | 
			
		||||
export function DeviceRoute(): React.ReactElement {
 | 
			
		||||
  const { id } = useParams();
 | 
			
		||||
@@ -79,7 +80,14 @@ function DeviceRouteInner(p: {
 | 
			
		||||
        </Tooltip>
 | 
			
		||||
      }
 | 
			
		||||
    >
 | 
			
		||||
      <GeneralDeviceInfo {...p} />
 | 
			
		||||
      <Grid container spacing={2}>
 | 
			
		||||
        <Grid item xs={12} md={6}>
 | 
			
		||||
          <GeneralDeviceInfo {...p} />
 | 
			
		||||
        </Grid>
 | 
			
		||||
        <Grid item xs={12} md={6}>
 | 
			
		||||
          <DeviceRelays {...p} />
 | 
			
		||||
        </Grid>
 | 
			
		||||
      </Grid>
 | 
			
		||||
    </SolarEnergyRouteContainer>
 | 
			
		||||
  );
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -62,6 +62,7 @@ export function GeneralDeviceInfo(p: {
 | 
			
		||||
            <DeviceInfoProperty
 | 
			
		||||
              label="Enabled"
 | 
			
		||||
              value={p.device.enabled ? "YES" : "NO"}
 | 
			
		||||
              color={p.device.enabled ? "green" : "red"}
 | 
			
		||||
            />
 | 
			
		||||
            <DeviceInfoProperty
 | 
			
		||||
              label="Maximum number of relays"
 | 
			
		||||
@@ -82,11 +83,12 @@ function DeviceInfoProperty(p: {
 | 
			
		||||
  icon?: React.ReactElement;
 | 
			
		||||
  label: string;
 | 
			
		||||
  value: string;
 | 
			
		||||
  color?: string;
 | 
			
		||||
}): React.ReactElement {
 | 
			
		||||
  return (
 | 
			
		||||
    <TableRow hover sx={{ "&:last-child td, &:last-child th": { border: 0 } }}>
 | 
			
		||||
      <TableCell>{p.label}</TableCell>
 | 
			
		||||
      <TableCell>{p.value}</TableCell>
 | 
			
		||||
      <TableCell style={{ color: p.color }}>{p.value}</TableCell>
 | 
			
		||||
    </TableRow>
 | 
			
		||||
  );
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,29 @@
 | 
			
		||||
import dayjs, { Dayjs } from "dayjs";
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Get current UNIX time, in seconds
 | 
			
		||||
 */
 | 
			
		||||
export function time(): number {
 | 
			
		||||
  return Math.floor(new Date().getTime() / 1000);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Get dayjs representation of given time of day
 | 
			
		||||
 */
 | 
			
		||||
export function timeOfDay(time: number): Dayjs {
 | 
			
		||||
  const hours = Math.floor(time / 3600);
 | 
			
		||||
  const minutes = Math.floor(time / 60) - hours * 60;
 | 
			
		||||
 | 
			
		||||
  return dayjs(
 | 
			
		||||
    `2022-04-17T${hours.toString().padStart(2, "0")}:${minutes
 | 
			
		||||
      .toString()
 | 
			
		||||
      .padStart(2, "0")}`
 | 
			
		||||
  );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Get time of day (in secs) from a given dayjs representation
 | 
			
		||||
 */
 | 
			
		||||
export function dayjsToTimeOfDay(d: Dayjs): number {
 | 
			
		||||
  return d.hour() * 3600 + d.minute() * 60 + d.second();
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user