import { type FC, useState } from 'react'; import { toast } from 'react-toastify'; import DownloadIcon from '@mui/icons-material/GetApp'; import { Box, Button, Divider, Link, Typography } from '@mui/material'; import * as SystemApi from 'api/system'; import * as EMSESP from 'project/api'; import { useRequest } from 'alova'; import { FormLoader, SectionContent, SingleUpload, useLayoutTitle } from 'components'; import { useI18nContext } from 'i18n/i18n-react'; import type { APIcall } from 'project/types'; import RestartMonitor from './RestartMonitor'; const UploadDownload: FC = () => { const { LL } = useI18nContext(); const [restarting, setRestarting] = useState(); const [md5, setMd5] = useState(); const { send: getSettings, onSuccess: onSuccessGetSettings } = useRequest( EMSESP.getSettings(), { immediate: false } ); const { send: getCustomizations, onSuccess: onSuccessGetCustomizations } = useRequest(EMSESP.getCustomizations(), { immediate: false }); const { send: getEntities, onSuccess: onSuccessGetEntities } = useRequest( EMSESP.getEntities(), { immediate: false } ); const { send: getSchedule, onSuccess: onSuccessGetSchedule } = useRequest( EMSESP.getSchedule(), { immediate: false } ); const { send: getAPI, onSuccess: onGetAPI } = useRequest( (data: APIcall) => EMSESP.API(data), { immediate: false } ); const { data: data, send: loadData, error } = useRequest(SystemApi.readESPSystemStatus, { force: true }); const { data: latestVersion } = useRequest(SystemApi.getStableVersion, { immediate: true, force: true }); const { data: latestDevVersion } = useRequest(SystemApi.getDevVersion, { immediate: true, force: true }); const STABLE_URL = 'https://github.com/emsesp/EMS-ESP32/releases/download/'; const DEV_URL = 'https://github.com/emsesp/EMS-ESP32/releases/download/latest/'; const STABLE_RELNOTES_URL = 'https://github.com/emsesp/EMS-ESP32/blob/main/CHANGELOG.md'; const DEV_RELNOTES_URL = 'https://github.com/emsesp/EMS-ESP32/blob/dev/CHANGELOG_LATEST.md'; const getBinURL = (v: string) => 'EMS-ESP-' + v.replaceAll('.', '_') + '-' + data.esp_platform.replaceAll('-', '_') + '.bin'; const { loading: isUploading, uploading: progress, send: sendUpload, onSuccess: onSuccessUpload, abort: cancelUpload } = useRequest(SystemApi.uploadFile, { immediate: false, force: true }); onSuccessUpload(({ data }) => { if (data) { // eslint-disable-next-line @typescript-eslint/no-unsafe-argument setMd5(data.md5); toast.success(LL.UPLOAD() + ' MD5 ' + LL.SUCCESSFUL()); } else { setRestarting(true); } }); const startUpload = async (files: File[]) => { await sendUpload(files[0]).catch((error: Error) => { if (error.message === 'The user aborted a request') { toast.warning(LL.UPLOAD() + ' ' + LL.ABORTED()); } else if (error.message === 'Network Error') { toast.warning('Invalid file extension or incompatible bin file'); } else { toast.error(error.message); } }); }; const saveFile = (json: unknown, endpoint: string) => { const anchor = document.createElement('a'); anchor.href = URL.createObjectURL( new Blob([JSON.stringify(json, null, 2)], { type: 'text/plain' }) ); anchor.download = 'emsesp_' + endpoint; anchor.click(); URL.revokeObjectURL(anchor.href); toast.info(LL.DOWNLOAD_SUCCESSFUL()); }; onSuccessGetSettings((event) => { saveFile(event.data, 'settings.json'); }); onSuccessGetCustomizations((event) => { saveFile(event.data, 'customizations.json'); }); onSuccessGetEntities((event) => { saveFile(event.data, 'entities.json'); }); onSuccessGetSchedule((event) => { saveFile(event.data, 'schedule.json'); }); onGetAPI((event) => { saveFile( event.data, event.sendArgs[0].device + '_' + event.sendArgs[0].entity + '.txt' ); }); const downloadSettings = async () => { await getSettings().catch((error: Error) => { toast.error(error.message); }); }; const downloadCustomizations = async () => { await getCustomizations().catch((error: Error) => { toast.error(error.message); }); }; const downloadEntities = async () => { await getEntities().catch((error: Error) => { toast.error(error.message); }); }; const downloadSchedule = async () => { await getSchedule().catch((error: Error) => { toast.error(error.message); }); }; const callAPI = async (device: string, entity: string) => { await getAPI({ device, entity, id: 0 }).catch((error: Error) => { toast.error(error.message); }); }; useLayoutTitle(LL.UPLOAD_DOWNLOAD()); const content = () => { if (!data) { return ; } return ( <> {LL.EMS_ESP_VER()} {LL.VERSION_ON() + ' '} {data.emsesp_version} ({data.esp_platform}) {latestVersion && ( {LL.THE_LATEST()} {LL.OFFICIAL()} {LL.RELEASE_IS()}  {latestVersion}  ( {LL.RELEASE_NOTES()} ) ( {LL.DOWNLOAD(1)} ) )} {latestDevVersion && ( {LL.THE_LATEST()} {LL.DEVELOPMENT()} {LL.RELEASE_IS()}   {latestDevVersion}  ( {LL.RELEASE_NOTES()} ) ( {LL.DOWNLOAD(1)} ) )} {LL.UPLOAD()} {LL.UPLOAD_TEXT()}

{LL.RESTART_TEXT(1)}.
{md5 && ( {'MD5: ' + md5} )} {!isUploading && ( <> {LL.DOWNLOAD(0)} {LL.HELP_INFORMATION_4()} {LL.DOWNLOAD_SETTINGS_TEXT()} {LL.DOWNLOAD_CUSTOMIZATION_TEXT()} {LL.DOWNLOAD_SCHEDULE_TEXT()} )} ); }; return ( {restarting ? : content()} ); }; export default UploadDownload;