Can select catchup hours
This commit is contained in:
		@@ -18,6 +18,7 @@ import { dayjsToTimeOfDay, timeOfDay } from "../utils/DateUtils";
 | 
			
		||||
import { lenValid } from "../utils/StringsUtils";
 | 
			
		||||
import { CheckboxInput } from "../widgets/forms/CheckboxInput";
 | 
			
		||||
import { TextInput } from "../widgets/forms/TextInput";
 | 
			
		||||
import { MultipleSelectInput } from "../widgets/forms/MultipleSelectInput";
 | 
			
		||||
 | 
			
		||||
export function EditDeviceRelaysDialog(p: {
 | 
			
		||||
  onClose: () => void;
 | 
			
		||||
@@ -243,16 +244,23 @@ export function EditDeviceRelaysDialog(p: {
 | 
			
		||||
                />
 | 
			
		||||
              </Grid>
 | 
			
		||||
              <Grid item xs={6}>
 | 
			
		||||
                <TimePicker
 | 
			
		||||
                  label="Catch up hours"
 | 
			
		||||
                  value={timeOfDay(relay.daily_runtime!.reset_time)}
 | 
			
		||||
                <MultipleSelectInput
 | 
			
		||||
                  label="Catchup hours"
 | 
			
		||||
                  helperText="The hours during which the relay should be turned on to reach expected runtime"
 | 
			
		||||
                  values={Array.apply(null, Array(24)).map((_y, i) => {
 | 
			
		||||
                    return {
 | 
			
		||||
                      label: `${i.toString().padStart(2, "0")}:00`,
 | 
			
		||||
                      value: i,
 | 
			
		||||
                    };
 | 
			
		||||
                  })}
 | 
			
		||||
                  selected={relay.daily_runtime!.catch_up_hours}
 | 
			
		||||
                  onChange={(d) =>
 | 
			
		||||
                    setRelay((r) => {
 | 
			
		||||
                      return {
 | 
			
		||||
                        ...r,
 | 
			
		||||
                        daily_runtime: {
 | 
			
		||||
                          ...r.daily_runtime!,
 | 
			
		||||
                          reset_time: d ? dayjsToTimeOfDay(d) : 0,
 | 
			
		||||
                          catch_up_hours: d,
 | 
			
		||||
                        },
 | 
			
		||||
                      };
 | 
			
		||||
                    })
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										113
									
								
								central_frontend/src/widgets/forms/MultipleSelectInput.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										113
									
								
								central_frontend/src/widgets/forms/MultipleSelectInput.tsx
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,113 @@
 | 
			
		||||
import {
 | 
			
		||||
  FormControl,
 | 
			
		||||
  InputLabel,
 | 
			
		||||
  Select,
 | 
			
		||||
  OutlinedInput,
 | 
			
		||||
  Box,
 | 
			
		||||
  Chip,
 | 
			
		||||
  MenuItem,
 | 
			
		||||
  Theme,
 | 
			
		||||
  useTheme,
 | 
			
		||||
  SelectChangeEvent,
 | 
			
		||||
  FormHelperText,
 | 
			
		||||
} from "@mui/material";
 | 
			
		||||
import React from "react";
 | 
			
		||||
 | 
			
		||||
export interface Value<E> {
 | 
			
		||||
  label: string;
 | 
			
		||||
  value: E;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const ITEM_HEIGHT = 48;
 | 
			
		||||
const ITEM_PADDING_TOP = 8;
 | 
			
		||||
 | 
			
		||||
const MenuProps = {
 | 
			
		||||
  PaperProps: {
 | 
			
		||||
    style: {
 | 
			
		||||
      maxHeight: ITEM_HEIGHT * 4.5 + ITEM_PADDING_TOP,
 | 
			
		||||
      width: 250,
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
function getStyles<E>(v: Value<E>, selected: readonly E[], theme: Theme) {
 | 
			
		||||
  return {
 | 
			
		||||
    fontWeight:
 | 
			
		||||
      selected.find((e) => e === v.value) === undefined
 | 
			
		||||
        ? theme.typography.fontWeightRegular
 | 
			
		||||
        : theme.typography.fontWeightMedium,
 | 
			
		||||
  };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function MultipleSelectInput<E>(p: {
 | 
			
		||||
  values: Value<E>[];
 | 
			
		||||
  selected: E[];
 | 
			
		||||
  label: string;
 | 
			
		||||
  onChange: (selected: E[]) => void;
 | 
			
		||||
  helperText?: string;
 | 
			
		||||
}): React.ReactElement {
 | 
			
		||||
  const [labelId] = React.useState(`id-multi-${Math.random()}`);
 | 
			
		||||
 | 
			
		||||
  const theme = useTheme();
 | 
			
		||||
 | 
			
		||||
  const handleChange = (event: SelectChangeEvent<E>) => {
 | 
			
		||||
    const {
 | 
			
		||||
      target: { value },
 | 
			
		||||
    } = event;
 | 
			
		||||
 | 
			
		||||
    const values: any[] =
 | 
			
		||||
      typeof value === "string" ? value.split(",") : (value as any);
 | 
			
		||||
 | 
			
		||||
    const newVals = values.map(
 | 
			
		||||
      (v) => p.values.find((e) => String(e.value) === String(v))!.value
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    // Values that appear multiple times are toggled
 | 
			
		||||
    const setVal = new Set<E>();
 | 
			
		||||
    for (const el of newVals) {
 | 
			
		||||
      if (!setVal.has(el)) setVal.add(el);
 | 
			
		||||
      else setVal.delete(el);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    p.onChange([...setVal]);
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  return (
 | 
			
		||||
    <div>
 | 
			
		||||
      <FormControl fullWidth>
 | 
			
		||||
        <InputLabel id={labelId}>{p.label}</InputLabel>
 | 
			
		||||
        <Select
 | 
			
		||||
          multiple
 | 
			
		||||
          labelId={labelId}
 | 
			
		||||
          id="bad"
 | 
			
		||||
          label={p.label}
 | 
			
		||||
          value={p.selected as any}
 | 
			
		||||
          onChange={handleChange}
 | 
			
		||||
          input={<OutlinedInput id="select-multiple-chip" label="Chip" />}
 | 
			
		||||
          renderValue={(selected) => (
 | 
			
		||||
            <Box sx={{ display: "flex", flexWrap: "wrap", gap: 0.5 }}>
 | 
			
		||||
              {(selected as Array<E>).map((value) => (
 | 
			
		||||
                <Chip
 | 
			
		||||
                  key={String(value)}
 | 
			
		||||
                  label={p.values.find((e) => e.value === value)!.label}
 | 
			
		||||
                />
 | 
			
		||||
              ))}
 | 
			
		||||
            </Box>
 | 
			
		||||
          )}
 | 
			
		||||
          MenuProps={MenuProps}
 | 
			
		||||
        >
 | 
			
		||||
          {p.values.map((v) => (
 | 
			
		||||
            <MenuItem
 | 
			
		||||
              key={v.label + String(v)}
 | 
			
		||||
              value={String(v.value)}
 | 
			
		||||
              style={getStyles(v, p.selected, theme)}
 | 
			
		||||
            >
 | 
			
		||||
              {v.label}
 | 
			
		||||
            </MenuItem>
 | 
			
		||||
          ))}
 | 
			
		||||
        </Select>
 | 
			
		||||
        {p.helperText && <FormHelperText>{p.helperText}</FormHelperText>}
 | 
			
		||||
      </FormControl>
 | 
			
		||||
    </div>
 | 
			
		||||
  );
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user