Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 2 additions & 5 deletions frontend/unified/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Box, Divider, Grid2 as Grid, Stack, Typography } from "@mui/material";
import { SessionSelector } from "./components/SessionSelector";
import { ScanSelector } from "./components/ScanSelector";

const VERTICAL_SPACING = 2;
const HORIZONTAL_SPACING = 2;
Expand All @@ -13,11 +14,7 @@ export const App: React.FC = () => {
<SessionSelector />
<Divider sx={{ width: "100%" }} />
<Typography variant="h5">Scan</Typography>
<PlaceholderComponent
placeholderText="Scan selector component placeholder"
height={100}
width={500}
/>
<ScanSelector />
<Divider sx={{ width: "100%" }} />
<Typography variant="h5">App</Typography>
<PlaceholderComponent
Expand Down
209 changes: 209 additions & 0 deletions frontend/unified/src/components/ScanSelector.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,209 @@
import {
Chip,
TextField,
ToggleButton,
ToggleButtonGroup,
Stack,
InputAdornment,
IconButton,
Box,
} from "@mui/material";
import AddIcon from "@mui/icons-material/Add";
import { useState } from "react";

enum ScanSelectionMode {
Single = "Single",
Multiple = "Multiple",
}

enum MultiScanSelectionMode {
Manual = "Manual",
Range = "Range",
}

const SingleScanSelector: React.FC = () => {
const [textInputValue, setTextInputValue] = useState<string>("");
return (
<Stack>
<TextField
label="Scan number"
value={textInputValue}
type="number"
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
setTextInputValue(e.currentTarget.value);
}}
/>
</Stack>
);
};

const MultiScanSelector: React.FC = () => {
const [mode, setMode] = useState<MultiScanSelectionMode>(
MultiScanSelectionMode.Range
);

return (
<>
<ToggleButtonGroup
exclusive
value={mode}
onChange={(_, toggleButtonLabel: string) => {
if (toggleButtonLabel === MultiScanSelectionMode.Manual) {
setMode(MultiScanSelectionMode.Manual);
} else if (toggleButtonLabel === MultiScanSelectionMode.Range) {
setMode(MultiScanSelectionMode.Range);
}
}}
>
<ToggleButton
sx={{ textTransform: "none" }}
value={MultiScanSelectionMode.Manual}
>
{MultiScanSelectionMode.Manual}
</ToggleButton>
<ToggleButton
sx={{ textTransform: "none" }}
value={MultiScanSelectionMode.Range}
>
{MultiScanSelectionMode.Range}
</ToggleButton>
</ToggleButtonGroup>
{mode === MultiScanSelectionMode.Manual ? (
<MultiScanManualSelector />
) : (
<MultiScanRangeSelector />
)}
</>
);
};

const MultiScanRangeSelector: React.FC = () => {
const [start, setStart] = useState<string>("1");
const [stop, setStop] = useState<string>("2");
const [step, setStep] = useState<string>("1");

return (
<Stack direction="row" spacing={2}>
<TextField
label="Start"
type="number"
value={Number(start)}
onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
setStart(e.target.value)
}
/>
<TextField
label="Stop"
type="number"
value={Number(stop)}
onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
setStop(e.target.value)
}
/>
<TextField
label="Step"
type="number"
value={Number(step)}
onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
setStep(e.target.value)
}
/>
</Stack>
);
};

const MultiScanManualSelector: React.FC = () => {
const [textInputValue, setTextInputValue] = useState<string>("4");
const [scanIds, setScanIds] = useState<number[]>([1, 2, 3]);

const handleDeleteScanIdChip = (idToDelete: number) => {
setScanIds((ids: number[]) => ids.filter((id) => id !== idToDelete));
};

const handleClickAddScanIdButton = (idToAdd: number) => {
if (scanIds.includes(idToAdd)) {
return;
}
setScanIds([...scanIds, idToAdd]);
setTextInputValue(String(Number(textInputValue) + 1));
};

return (
<Stack spacing={2}>
<TextField
label="Scan number"
value={textInputValue}
type="number"
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
setTextInputValue(e.currentTarget.value);
}}
slotProps={{
input: {
endAdornment: (
<InputAdornment position="end">
<IconButton
onClick={(_) =>
handleClickAddScanIdButton(Number(textInputValue))
}
>
<AddIcon />
</IconButton>
</InputAdornment>
),
},
}}
/>
<Box maxWidth={300}>
{scanIds.map((scanId: number) => {
return (
<Chip
key={scanId}
label={scanId}
onDelete={(_) => handleDeleteScanIdChip(scanId)}
></Chip>
);
})}
</Box>
</Stack>
);
};

export const ScanSelector: React.FC = () => {
const [scanSelectionMode, setScanSelectionMode] = useState<ScanSelectionMode>(
ScanSelectionMode.Single
);

return (
<Stack direction="column" spacing={2} alignItems={"start"}>
<ToggleButtonGroup
exclusive
value={scanSelectionMode}
onChange={(_, toggleButtonLabel: string) => {
if (toggleButtonLabel === ScanSelectionMode.Single) {
setScanSelectionMode(ScanSelectionMode.Single);
} else if (toggleButtonLabel === ScanSelectionMode.Multiple) {
setScanSelectionMode(ScanSelectionMode.Multiple);
}
}}
>
<ToggleButton
sx={{ textTransform: "none" }}
value={ScanSelectionMode.Single}
>
{ScanSelectionMode.Single}
</ToggleButton>
<ToggleButton
sx={{ textTransform: "none" }}
value={ScanSelectionMode.Multiple}
>
{ScanSelectionMode.Multiple}
</ToggleButton>
</ToggleButtonGroup>
{scanSelectionMode === ScanSelectionMode.Single ? (
<SingleScanSelector />
) : (
<MultiScanSelector />
)}
</Stack>
);
};
Loading