committed by
GitHub
11 changed files with 201 additions and 189 deletions
@ -1,117 +0,0 @@ |
|||||
import { Button } from "@components/UI/Button.tsx"; |
|
||||
import { |
|
||||
Dialog, |
|
||||
DialogClose, |
|
||||
DialogContent, |
|
||||
DialogDescription, |
|
||||
DialogHeader, |
|
||||
DialogTitle, |
|
||||
} from "@components/UI/Dialog.tsx"; |
|
||||
import { Input } from "@components/UI/Input.tsx"; |
|
||||
import { useDevice } from "@core/stores/deviceStore.ts"; |
|
||||
import { ClockIcon, RefreshCwIcon } from "lucide-react"; |
|
||||
import { useState } from "react"; |
|
||||
import { useTranslation } from "react-i18next"; |
|
||||
|
|
||||
export interface RebootOTADialogProps { |
|
||||
open: boolean; |
|
||||
onOpenChange: (open: boolean) => void; |
|
||||
} |
|
||||
|
|
||||
const DEFAULT_REBOOT_DELAY = 5; // seconds
|
|
||||
|
|
||||
export const RebootOTADialog = ({ |
|
||||
open, |
|
||||
onOpenChange, |
|
||||
}: RebootOTADialogProps) => { |
|
||||
const { t } = useTranslation("dialog"); |
|
||||
const { connection } = useDevice(); |
|
||||
const [time, setTime] = useState<number>(DEFAULT_REBOOT_DELAY); |
|
||||
const [isScheduled, setIsScheduled] = useState(false); |
|
||||
const [inputValue, setInputValue] = useState(DEFAULT_REBOOT_DELAY.toString()); |
|
||||
|
|
||||
const handleSetTime = (e: React.ChangeEvent<HTMLInputElement>) => { |
|
||||
if (!e.target.validity.valid) { |
|
||||
e.preventDefault(); |
|
||||
return; |
|
||||
} |
|
||||
|
|
||||
const val = e.target.value; |
|
||||
setInputValue(val); |
|
||||
|
|
||||
const parsed = Number(val); |
|
||||
if (!Number.isNaN(parsed) && parsed > 0) { |
|
||||
setTime(parsed); |
|
||||
} |
|
||||
}; |
|
||||
|
|
||||
const handleRebootWithTimeout = async () => { |
|
||||
if (!connection) { |
|
||||
return; |
|
||||
} |
|
||||
setIsScheduled(true); |
|
||||
|
|
||||
const delay = time > 0 ? time : DEFAULT_REBOOT_DELAY; |
|
||||
|
|
||||
await new Promise<void>((resolve) => { |
|
||||
setTimeout(() => { |
|
||||
resolve(); |
|
||||
}, delay * 1000); |
|
||||
}).finally(() => { |
|
||||
setIsScheduled(false); |
|
||||
onOpenChange(false); |
|
||||
setInputValue(DEFAULT_REBOOT_DELAY.toString()); |
|
||||
}); |
|
||||
connection.rebootOta(0); |
|
||||
}; |
|
||||
|
|
||||
const handleInstantReboot = async () => { |
|
||||
if (!connection) { |
|
||||
return; |
|
||||
} |
|
||||
|
|
||||
await connection.rebootOta(DEFAULT_REBOOT_DELAY); |
|
||||
onOpenChange(false); |
|
||||
}; |
|
||||
|
|
||||
return ( |
|
||||
<Dialog open={open} onOpenChange={onOpenChange}> |
|
||||
<DialogContent> |
|
||||
<DialogClose /> |
|
||||
<DialogHeader> |
|
||||
<DialogTitle>{t("rebootOta.title")}</DialogTitle> |
|
||||
<DialogDescription>{t("rebootOta.description")}</DialogDescription> |
|
||||
</DialogHeader> |
|
||||
|
|
||||
<div className="flex gap-2 p-2 items-center relative"> |
|
||||
<Input |
|
||||
type="number" |
|
||||
min={1} |
|
||||
max={86400} |
|
||||
className="dark:text-slate-900 appearance-none" |
|
||||
value={inputValue} |
|
||||
onChange={handleSetTime} |
|
||||
placeholder={t("rebootOta.enterDelay")} |
|
||||
/> |
|
||||
<Button |
|
||||
onClick={() => handleRebootWithTimeout()} |
|
||||
data-testid="scheduleRebootBtn" |
|
||||
className="w-9/12" |
|
||||
> |
|
||||
<ClockIcon className="mr-2" size={18} /> |
|
||||
{isScheduled ? t("rebootOta.scheduled") : t("rebootOta.title")} |
|
||||
</Button> |
|
||||
</div> |
|
||||
|
|
||||
<Button |
|
||||
variant="destructive" |
|
||||
name="rebootNow" |
|
||||
onClick={() => handleInstantReboot()} |
|
||||
> |
|
||||
<RefreshCwIcon className="mr-2" size={16} /> |
|
||||
{t("button.rebootOtaNow")} |
|
||||
</Button> |
|
||||
</DialogContent> |
|
||||
</Dialog> |
|
||||
); |
|
||||
}; |
|
||||
Loading…
Reference in new issue