220 lines
10 KiB
TypeScript
220 lines
10 KiB
TypeScript
|
|
import React from "react";
|
||
|
|
import { useEffect } from "react"
|
||
|
|
import Card from "../../UI/Card";
|
||
|
|
import CardHeader from "../../UI/CardHeader";
|
||
|
|
import FormGroup from "../components/FormGroup";
|
||
|
|
import { sendBlobFileUpload } from "./Upload";
|
||
|
|
import { handleSoftReboot, handleHardReboot } from "./Reboots.tsx";
|
||
|
|
import { handleSystemRecall, handleSystemSave } from "./SettingSaveRecall.tsx";
|
||
|
|
|
||
|
|
const SystemCard = () => {
|
||
|
|
const [deviceName, setDeviceName] = React.useState("");
|
||
|
|
const [timeZone, setTimeZone] = React.useState("Europe/London (UTC+00:00");
|
||
|
|
const [sntpServer, setSntpServer] = React.useState("1.uk.pool.ntp.org");
|
||
|
|
const [sntpInterval, setSntpInterval] = React.useState(60);
|
||
|
|
const [selectedFile, setSelectedFile] = React.useState<File | null>(null);
|
||
|
|
const [error, setError] = React.useState("");
|
||
|
|
|
||
|
|
useEffect(() => {
|
||
|
|
(async () => {
|
||
|
|
const result = await handleSystemRecall(); // returns { deviceName, sntpServer, sntpInterval, timeZone } | null
|
||
|
|
if (result) {
|
||
|
|
const {
|
||
|
|
deviceName: dn,
|
||
|
|
sntpServer: ss,
|
||
|
|
sntpInterval: si,
|
||
|
|
timeZone: tz
|
||
|
|
} = result;
|
||
|
|
|
||
|
|
setDeviceName(dn ?? "");
|
||
|
|
setSntpServer(ss ?? "");
|
||
|
|
setSntpInterval(Number.isFinite(si) ? si : 60);
|
||
|
|
setTimeZone(tz ?? "UTC (UTC-00)");
|
||
|
|
}
|
||
|
|
})();
|
||
|
|
}, []);
|
||
|
|
|
||
|
|
const handleFileChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||
|
|
const file = e.target.files?.[0] ?? null;
|
||
|
|
setSelectedFile(file);
|
||
|
|
if (!file) {
|
||
|
|
setError("No file selected.");
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (file.size > 8 * 1024 * 1024) {
|
||
|
|
setError("File is too large (max 8MB).");
|
||
|
|
setSelectedFile(null);
|
||
|
|
return
|
||
|
|
};
|
||
|
|
setError("");
|
||
|
|
}
|
||
|
|
|
||
|
|
const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
|
||
|
|
e.preventDefault(); // prevent full page reload
|
||
|
|
if (!selectedFile) {
|
||
|
|
setError("Please select a file before uploading.");
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
setError("");
|
||
|
|
|
||
|
|
const result = await sendBlobFileUpload( selectedFile, {
|
||
|
|
timeoutMs: 30000,
|
||
|
|
fieldName: "upload",
|
||
|
|
});
|
||
|
|
|
||
|
|
// The helper returns a string (either success body or formatted error)
|
||
|
|
// You can decide how to distinguish. Here, we show it optimistically and let the text speak.
|
||
|
|
if (result.startsWith("Server returned") || result.startsWith("Timeout") || result.startsWith("HTTP error") || result.startsWith("Unexpected error")) {
|
||
|
|
setError(result);
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
return (
|
||
|
|
<Card className="flex flex-col items-center justify-center">
|
||
|
|
<CardHeader title={"System Config"} />
|
||
|
|
<div className="flex flex-col gap-4 w-full items-left max-w-md">
|
||
|
|
<FormGroup>
|
||
|
|
<label htmlFor="deviceName" className="font-medium whitespace-nowrap md:w-1/2 text-left">Device Name</label>
|
||
|
|
<div className="flex-1 flex justify-end md:w-2/3">
|
||
|
|
<input
|
||
|
|
id="deviceName"
|
||
|
|
name="deviceName"
|
||
|
|
type="text"
|
||
|
|
className="p-2 border border-gray-400 rounded-lg w-full max-w-xs"
|
||
|
|
placeholder="Enter device name"
|
||
|
|
value={deviceName}
|
||
|
|
onChange={e => setDeviceName(e.target.value)}
|
||
|
|
/>
|
||
|
|
</div>
|
||
|
|
</FormGroup>
|
||
|
|
<FormGroup>
|
||
|
|
<label htmlFor="timeZone" className="font-medium whitespace-nowrap md:w-1/2 text-left">Local Time Zone</label>
|
||
|
|
<div className="flex-1 flex justify-end md:w-2/3">
|
||
|
|
<select
|
||
|
|
id="timeZone"
|
||
|
|
name="timeZone"
|
||
|
|
className="p-2 border border-gray-400 rounded-lg text-white bg-[#253445] w-full max-w-xs"
|
||
|
|
value={timeZone}
|
||
|
|
onChange={e => setTimeZone(e.target.value)}
|
||
|
|
>
|
||
|
|
<option value="">Select Time Zone</option>
|
||
|
|
<option value="Europe/London (UTC+00)">UTC (UTC+00)</option>
|
||
|
|
<option value="Africa/Cairo (UTC+02)">Africa/Cairo (UTC+02)</option>
|
||
|
|
<option value="Africa/Johannesburg (UTC+02)">Africa/Johannesburg (UTC+02)</option>
|
||
|
|
<option value="Africa/Lagos (UTC+01)">Africa/Lagos (UTC+01)</option>
|
||
|
|
<option value="Africa/Monrousing (UTC+00)">Africa/Monrousing (UTC+00)</option>
|
||
|
|
<option value="America/Anchorage (UTC-09)">America/Anchorage (UTC-09)</option>
|
||
|
|
<option value="America/Chicago (UTC-06)">America/Chicago (UTC-06)</option>
|
||
|
|
<option value="America/Denver (UTC-07)">America/Denver (UTC-07)</option>
|
||
|
|
<option value="America/Edmonton (UTC-07)">America/Edmonton (UTC-07)</option>
|
||
|
|
<option value="America/Jamaica (UTC-05)">America/Jamaica (UTC-05)</option>
|
||
|
|
<option value="America/Los Angeles (UTC-08)">America/Los Angeles (UTC-08)</option>
|
||
|
|
<option value="America/Mexico City (UTC-06)">America/Mexico City (UTC-06)</option>
|
||
|
|
<option value="America/Montreal (UTC-05)">America/Montreal (UTC-05)</option>
|
||
|
|
<option value="America/New York (UTC-05)">America/New York (UTC-05)</option>
|
||
|
|
<option value="America/Phoenix (UTC-07)">America/Phoenix (UTC-07)</option>
|
||
|
|
<option value="America/Puerto Rico (UTC-04)">America/Puerto Rico (UTC-04)</option>
|
||
|
|
<option value="America/Sao Paulo (UTC-03)">America/Sao Paulo (UTC-03)</option>
|
||
|
|
<option value="America/Toronto (UTC-05)">America/Toronto (UTC-05)</option>
|
||
|
|
<option value="America/Vancouver (UTC-08)">America/Vancouver (UTC-08)</option>
|
||
|
|
<option value="Asia/Hong Kong (UTC+08)">Asia/Hong Kong (UTC+08)</option>
|
||
|
|
<option value="Asia/Jerusalem (UTC+02)">Asia/Jerusalem (UTC+02)</option>
|
||
|
|
<option value="Asia/Manila (UTC+08)">Asia/Manila (UTC+08)</option>
|
||
|
|
<option value="Asia/Seoul (UTC+09)">Asia/Seoul (UTC+09)</option>
|
||
|
|
<option value="Asia/Tokyo (UTC+09)">Asia/Tokyo (UTC+09)</option>
|
||
|
|
<option value="Atlantic/Reykjavik (UTC+00)">Atlantic/Reykjavik (UTC+00)</option>
|
||
|
|
<option value="Australia/Perth (UTC+08)">Australia/Perth (UTC+08)</option>
|
||
|
|
<option value="Australia/Sydney (UTC+10)">Australia/Sydney (UTC+10)</option>
|
||
|
|
<option value="Europe/Athens (UTC+02)">Europe/Athens (UTC+02)</option>
|
||
|
|
<option value="Europe/Berlin (UTC+01)">Europe/Berlin (UTC+01)</option>
|
||
|
|
<option value="Europe/Brussels (UTC+01)">Europe/Brussels (UTC+01)</option>
|
||
|
|
<option value="Europe/Copenhagen (UTC+01)">Europe/Copenhagen (UTC+01)</option>
|
||
|
|
<option value="Europe/London (UTC+00)">Europe/London (UTC+00)</option>
|
||
|
|
<option value="Europe/Madrid (UTC+01)">Europe/Madrid (UTC+01)</option>
|
||
|
|
<option value="Europe/Moscow (UTC+04)">Europe/Moscow (UTC+04)</option>
|
||
|
|
<option value="Europe/Paris (UTC+01)">Europe/Paris (UTC+01)</option>
|
||
|
|
<option value="Europe/Prague (UTC+01)">Europe/Prague (UTC+01)</option>
|
||
|
|
<option value="Europe/Rome (UTC+01)">Europe/Rome (UTC+01)</option>
|
||
|
|
<option value="Europe/Warsaw (UTC+01)">Europe/Warsaw (UTC+01)</option>
|
||
|
|
<option value="Pacific/Guam (UTC+10)">Pacific/Guam (UTC+10)</option>
|
||
|
|
<option value="Pacific/Honolulu (UTC-10)">Pacific/Honolulu (UTC-10)</option>
|
||
|
|
</select>
|
||
|
|
</div>
|
||
|
|
</FormGroup>
|
||
|
|
<FormGroup>
|
||
|
|
<label htmlFor="sntpServer" className="font-medium whitespace-nowrap md:w-1/2 text-left">SNTP Server</label>
|
||
|
|
<div className="flex-1 flex justify-end md:w-2/3">
|
||
|
|
<input
|
||
|
|
id="sntpServer"
|
||
|
|
name="sntpServer"
|
||
|
|
type="text"
|
||
|
|
className="p-2 border border-gray-400 rounded-lg w-full max-w-xs"
|
||
|
|
placeholder="Enter SNTP server address"
|
||
|
|
value={sntpServer}
|
||
|
|
onChange={e => setSntpServer(e.target.value)}
|
||
|
|
/>
|
||
|
|
</div>
|
||
|
|
</FormGroup>
|
||
|
|
<FormGroup>
|
||
|
|
<label htmlFor="sntpInterval" className="font-medium whitespace-nowrap md:w-1/2 text-left">SNTP Interval minutes</label>
|
||
|
|
<div className="flex-1 flex justify-end md:w-2/3">
|
||
|
|
<input
|
||
|
|
id="sntpInterval"
|
||
|
|
name="sntpInterval"
|
||
|
|
type="number"
|
||
|
|
min={1}
|
||
|
|
className="p-2 border border-gray-400 rounded-lg w-full max-w-xs"
|
||
|
|
value={sntpInterval}
|
||
|
|
onChange={e => setSntpInterval(Number(e.target.value))}
|
||
|
|
/>
|
||
|
|
</div>
|
||
|
|
</FormGroup>
|
||
|
|
<button
|
||
|
|
className="bg-[#26B170] text-white px-4 py-2 rounded hover:bg-green-700 transition w-full max-w-md"
|
||
|
|
onClick={() => handleSystemSave(deviceName, sntpServer, sntpInterval, timeZone)}
|
||
|
|
>
|
||
|
|
Save System Settings
|
||
|
|
</button>
|
||
|
|
<div className="py-8 w-full">
|
||
|
|
<form onSubmit={handleSubmit} className="flex flex-col items-center gap-2 w-full">
|
||
|
|
<FormGroup>
|
||
|
|
<div className="flex-1 flex justify-end md:w-2/3">
|
||
|
|
<input
|
||
|
|
type="file"
|
||
|
|
name="softwareUpdate"
|
||
|
|
id="softwareUpdate"
|
||
|
|
className="file:px-10 file:border file:border-gray-500 file:rounded-lg file:bg-blue-800 file:mr-5 w-full max-w-xs"
|
||
|
|
onChange={handleFileChange}
|
||
|
|
/>
|
||
|
|
</div>
|
||
|
|
</FormGroup>
|
||
|
|
<button
|
||
|
|
type="submit"
|
||
|
|
className="w-full max-w-md text-white bg-[#26B170] hover:bg-green-700 font-small rounded-lg text-sm px-2 py-2.5 disabled:opacity-50 disabled:cursor-not-allowed"
|
||
|
|
disabled={!selectedFile}
|
||
|
|
>
|
||
|
|
Upload Software Update
|
||
|
|
</button>
|
||
|
|
{error && <p className="text-red-500 text-sm">{error}</p>}
|
||
|
|
</form>
|
||
|
|
</div>
|
||
|
|
<button
|
||
|
|
className="bg-red-600 text-white px-4 py-2 rounded hover:bg-red-700 transition w-full max-w-md"
|
||
|
|
onClick={handleSoftReboot}
|
||
|
|
>
|
||
|
|
Software Reboot
|
||
|
|
</button>
|
||
|
|
<button
|
||
|
|
className="bg-red-600 text-white px-4 py-2 rounded hover:bg-red-700 transition w-full max-w-md"
|
||
|
|
onClick={handleHardReboot}
|
||
|
|
>
|
||
|
|
Hardware Reboot
|
||
|
|
</button>
|
||
|
|
</div>
|
||
|
|
</Card>
|
||
|
|
);
|
||
|
|
};
|
||
|
|
|
||
|
|
export default SystemCard;
|