2024-12-09 11:33:30 -05:00
|
|
|
import { useState, useCallback } from "react";
|
2024-12-05 10:34:41 -05:00
|
|
|
import { Button, Box, Stack, Typography } from "@mui/material";
|
|
|
|
|
import { ConfigBox } from "../../../Pages/Settings/styled";
|
|
|
|
|
import { useTheme } from "@emotion/react";
|
|
|
|
|
import TabPanel from "@mui/lab/TabPanel";
|
2024-12-09 11:33:30 -05:00
|
|
|
import { publicPageGeneralSettingsValidation } from "../../../Validation/validation";
|
2024-12-05 10:34:41 -05:00
|
|
|
import { buildErrors } from "../../../Validation/error";
|
|
|
|
|
import { hasValidationErrors } from "../../../Validation/error";
|
2024-12-09 11:33:30 -05:00
|
|
|
import Card from "./Card";
|
|
|
|
|
import update from "immutability-helper";
|
2024-12-10 16:07:42 -05:00
|
|
|
import Checkbox from "../../Inputs/Checkbox";
|
2024-12-09 11:33:30 -05:00
|
|
|
|
2024-12-05 10:34:41 -05:00
|
|
|
const ContentPanel = () => {
|
|
|
|
|
const theme = useTheme();
|
|
|
|
|
const [errors, setErrors] = useState({});
|
|
|
|
|
// Local state for form data, errors, and file handling
|
|
|
|
|
const [localData, setLocalData] = useState({
|
2024-12-09 11:33:30 -05:00
|
|
|
monitors: [],
|
2024-12-10 16:07:42 -05:00
|
|
|
showUptimePercentage: false,
|
|
|
|
|
showBarcode: false
|
|
|
|
|
|
2024-12-05 10:34:41 -05:00
|
|
|
});
|
2024-12-09 11:33:30 -05:00
|
|
|
|
|
|
|
|
const [cards, setCards] = useState(localData.monitors);
|
|
|
|
|
|
2024-12-05 10:34:41 -05:00
|
|
|
// Clears specific error from errors state
|
|
|
|
|
const clearError = (err) => {
|
|
|
|
|
setErrors((prev) => {
|
|
|
|
|
const updatedErrors = { ...prev };
|
|
|
|
|
if (updatedErrors[err]) delete updatedErrors[err];
|
|
|
|
|
return updatedErrors;
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
2024-12-09 11:33:30 -05:00
|
|
|
const moveCard = useCallback(
|
|
|
|
|
(dragIndex, hoverIndex) => {
|
|
|
|
|
const dragCard = cards[dragIndex];
|
|
|
|
|
setCards(
|
|
|
|
|
update(cards, {
|
|
|
|
|
$splice: [
|
|
|
|
|
[dragIndex, 1],
|
|
|
|
|
[hoverIndex, 0, dragCard],
|
|
|
|
|
],
|
|
|
|
|
})
|
|
|
|
|
);
|
|
|
|
|
},
|
|
|
|
|
[cards]
|
|
|
|
|
);
|
|
|
|
|
|
2024-12-05 10:34:41 -05:00
|
|
|
const handleChange = (event) => {
|
|
|
|
|
event.preventDefault();
|
|
|
|
|
const { value, id } = event.target;
|
|
|
|
|
setLocalData((prev) => ({
|
|
|
|
|
...prev,
|
|
|
|
|
[id]: value,
|
|
|
|
|
}));
|
|
|
|
|
};
|
|
|
|
|
|
2024-12-10 16:07:42 -05:00
|
|
|
const handleCardChange = (event) => {
|
|
|
|
|
event.preventDefault();
|
|
|
|
|
const { value, id } = event.target;
|
|
|
|
|
let idx = cards.findIndex((a) => a.id == id);
|
|
|
|
|
if (idx >= 0) {
|
|
|
|
|
let x = JSON.parse(JSON.stringify(cards[idx]));
|
|
|
|
|
x.url = value;
|
|
|
|
|
setCards(update(cards, { $splice: [[idx, 1, x]] }));
|
|
|
|
|
} else setCards(update(cards, { $push: [{ id: id, url: value }] }));
|
|
|
|
|
}
|
|
|
|
|
|
2024-12-05 10:34:41 -05:00
|
|
|
const handleSubmit = () => {
|
|
|
|
|
if (hasValidationErrors(localData, publicPageGeneralSettingsValidation, setErrors)) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2024-12-05 15:57:45 -05:00
|
|
|
const handleAddNew = () => {
|
2024-12-09 11:33:30 -05:00
|
|
|
setCards([...cards, { id: "" + Math.random() }]);
|
|
|
|
|
};
|
|
|
|
|
const removeCard = (id) => {
|
|
|
|
|
setCards(cards.filter((c) => c?.id != id));
|
|
|
|
|
};
|
2024-12-05 10:34:41 -05:00
|
|
|
const handleBlur = (event) => {
|
|
|
|
|
event.preventDefault();
|
|
|
|
|
const { value, id } = event.target;
|
|
|
|
|
const { error } = publicPageGeneralSettingsValidation.validate(
|
|
|
|
|
{ [id]: value },
|
|
|
|
|
{
|
|
|
|
|
abortEarly: false,
|
|
|
|
|
}
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
setErrors((prev) => {
|
|
|
|
|
return buildErrors(prev, id, error);
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<TabPanel
|
|
|
|
|
value="Contents"
|
|
|
|
|
sx={{
|
|
|
|
|
"& h1, & p, & input": {
|
|
|
|
|
color: theme.palette.text.tertiary,
|
|
|
|
|
},
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
<Stack
|
|
|
|
|
component="form"
|
|
|
|
|
className="status-contents-form"
|
|
|
|
|
noValidate
|
|
|
|
|
spellCheck="false"
|
|
|
|
|
gap={theme.spacing(12)}
|
|
|
|
|
mt={theme.spacing(6)}
|
|
|
|
|
>
|
|
|
|
|
<ConfigBox>
|
|
|
|
|
<Box>
|
|
|
|
|
<Stack gap={theme.spacing(6)}>
|
|
|
|
|
<Typography component="h2">Status page servers</Typography>
|
|
|
|
|
<Typography component="p">
|
|
|
|
|
You can add any number of servers that you monitor to your status page.
|
|
|
|
|
You can also reorder them for the best viewing experience.
|
|
|
|
|
</Typography>
|
|
|
|
|
</Stack>
|
|
|
|
|
</Box>
|
2024-12-05 15:57:45 -05:00
|
|
|
<Box
|
|
|
|
|
className="status-contents-server-list"
|
|
|
|
|
sx={{
|
2024-12-05 10:34:41 -05:00
|
|
|
height: "fit-content",
|
|
|
|
|
border: "solid",
|
|
|
|
|
borderRadius: theme.shape.borderRadius,
|
|
|
|
|
borderColor: theme.palette.border.light,
|
|
|
|
|
borderWidth: "2px",
|
|
|
|
|
transition: "0.2s",
|
|
|
|
|
"&:hover": {
|
|
|
|
|
borderColor: theme.palette.primary.main,
|
|
|
|
|
backgroundColor: "hsl(215, 87%, 51%, 0.05)",
|
2024-12-05 15:57:45 -05:00
|
|
|
},
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
<Box>
|
|
|
|
|
<Stack
|
|
|
|
|
direction="row"
|
|
|
|
|
justifyContent="space-around"
|
2024-12-05 10:34:41 -05:00
|
|
|
>
|
2024-12-05 15:57:45 -05:00
|
|
|
<Typography
|
|
|
|
|
component="p"
|
|
|
|
|
alignSelf={"center"}
|
|
|
|
|
>
|
|
|
|
|
{" "}
|
|
|
|
|
Servers list{" "}
|
|
|
|
|
</Typography>
|
|
|
|
|
<Button onClick={handleAddNew}>Add New</Button>
|
|
|
|
|
</Stack>
|
2024-12-09 11:33:30 -05:00
|
|
|
{cards.length > 0 && (
|
2024-12-05 15:57:45 -05:00
|
|
|
<Stack
|
|
|
|
|
direction="column"
|
|
|
|
|
alignItems="center"
|
|
|
|
|
gap={theme.spacing(6)}
|
2024-12-09 11:33:30 -05:00
|
|
|
sx={{
|
|
|
|
|
ml: theme.spacing(4),
|
2024-12-05 15:57:45 -05:00
|
|
|
mr: theme.spacing(8),
|
2024-12-09 11:33:30 -05:00
|
|
|
mb: theme.spacing(8),
|
2024-12-05 15:57:45 -05:00
|
|
|
}}
|
|
|
|
|
>
|
2024-12-09 11:33:30 -05:00
|
|
|
{cards.map((card, idx) => (
|
|
|
|
|
<Card
|
2024-12-05 15:57:45 -05:00
|
|
|
key={idx}
|
2024-12-09 11:33:30 -05:00
|
|
|
index={idx}
|
|
|
|
|
id={card?.id ?? "" + Math.random()}
|
|
|
|
|
text={"" + idx}
|
|
|
|
|
moveCard={moveCard}
|
|
|
|
|
removeCard={removeCard}
|
2024-12-10 16:07:42 -05:00
|
|
|
value={card?.url}
|
|
|
|
|
onChange = {handleCardChange}
|
2024-12-05 15:57:45 -05:00
|
|
|
/>
|
|
|
|
|
))}
|
|
|
|
|
</Stack>
|
|
|
|
|
)}
|
|
|
|
|
</Box>
|
2024-12-05 10:34:41 -05:00
|
|
|
</Box>
|
|
|
|
|
</ConfigBox>
|
2024-12-10 16:07:42 -05:00
|
|
|
<ConfigBox>
|
|
|
|
|
<Box>
|
|
|
|
|
<Stack gap={theme.spacing(6)}>
|
|
|
|
|
<Typography component="h2">Features</Typography>
|
|
|
|
|
<Typography component="p">Show more details on the status page</Typography>
|
|
|
|
|
</Stack>
|
|
|
|
|
</Box>
|
|
|
|
|
<Stack
|
|
|
|
|
>
|
|
|
|
|
<Checkbox
|
|
|
|
|
id="show-barcode"
|
|
|
|
|
label={`Show Barcode`}
|
|
|
|
|
isChecked={localData.showBarcode}
|
|
|
|
|
value={"localData.showBarcode"}
|
|
|
|
|
onChange={handleChange}
|
|
|
|
|
onBlur={handleBlur}
|
|
|
|
|
/>
|
|
|
|
|
<Checkbox
|
|
|
|
|
id="show-uptime-percentage"
|
|
|
|
|
label={`Show Uptime Percentage`}
|
|
|
|
|
isChecked={localData.showUptimePercentage}
|
|
|
|
|
value={"localData.showUptimePercentage"}
|
|
|
|
|
onChange={handleChange}
|
|
|
|
|
onBlur={handleBlur}
|
|
|
|
|
/>
|
|
|
|
|
</Stack>
|
|
|
|
|
</ConfigBox>
|
2024-12-05 10:34:41 -05:00
|
|
|
|
|
|
|
|
<Stack
|
|
|
|
|
direction="row"
|
|
|
|
|
justifyContent="flex-end"
|
|
|
|
|
>
|
|
|
|
|
<Button
|
|
|
|
|
variant="contained"
|
|
|
|
|
color="primary"
|
|
|
|
|
onClick={handleSubmit}
|
|
|
|
|
>
|
2024-12-06 10:28:42 -05:00
|
|
|
Save
|
2024-12-05 10:34:41 -05:00
|
|
|
</Button>
|
|
|
|
|
</Stack>
|
|
|
|
|
</Stack>
|
|
|
|
|
</TabPanel>
|
|
|
|
|
);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export default ContentPanel;
|