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 { lenValid } from "../utils/StringsUtils";
 | 
				
			||||||
import { CheckboxInput } from "../widgets/forms/CheckboxInput";
 | 
					import { CheckboxInput } from "../widgets/forms/CheckboxInput";
 | 
				
			||||||
import { TextInput } from "../widgets/forms/TextInput";
 | 
					import { TextInput } from "../widgets/forms/TextInput";
 | 
				
			||||||
 | 
					import { MultipleSelectInput } from "../widgets/forms/MultipleSelectInput";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export function EditDeviceRelaysDialog(p: {
 | 
					export function EditDeviceRelaysDialog(p: {
 | 
				
			||||||
  onClose: () => void;
 | 
					  onClose: () => void;
 | 
				
			||||||
@@ -243,16 +244,23 @@ export function EditDeviceRelaysDialog(p: {
 | 
				
			|||||||
                />
 | 
					                />
 | 
				
			||||||
              </Grid>
 | 
					              </Grid>
 | 
				
			||||||
              <Grid item xs={6}>
 | 
					              <Grid item xs={6}>
 | 
				
			||||||
                <TimePicker
 | 
					                <MultipleSelectInput
 | 
				
			||||||
                  label="Catch up hours"
 | 
					                  label="Catchup hours"
 | 
				
			||||||
                  value={timeOfDay(relay.daily_runtime!.reset_time)}
 | 
					                  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) =>
 | 
					                  onChange={(d) =>
 | 
				
			||||||
                    setRelay((r) => {
 | 
					                    setRelay((r) => {
 | 
				
			||||||
                      return {
 | 
					                      return {
 | 
				
			||||||
                        ...r,
 | 
					                        ...r,
 | 
				
			||||||
                        daily_runtime: {
 | 
					                        daily_runtime: {
 | 
				
			||||||
                          ...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