Qortal-Hub/src/components/Apps/useHandlePrivateApps.tsx
2025-04-29 22:25:20 +03:00

227 lines
6.9 KiB
TypeScript

import React, { useContext, useState } from 'react';
import { executeEvent } from '../../utils/events';
import { getBaseApiReact, MyContext } from '../../App';
import { createEndpoint } from '../../background';
import {
settingsLocalLastUpdatedAtom,
sortablePinnedAppsAtom,
} from '../../atoms/global';
import { saveToLocalStorage } from './AppsNavBarDesktop';
import { base64ToBlobUrl } from '../../utils/fileReading';
import { base64ToUint8Array } from '../../qdn/encryption/group-encryption';
import { uint8ArrayToObject } from '../../backgroundFunctions/encryption';
import { useAtom, useSetAtom } from 'jotai';
export const useHandlePrivateApps = () => {
const [status, setStatus] = useState('');
const {
openSnackGlobal,
setOpenSnackGlobal,
infoSnackCustom,
setInfoSnackCustom,
} = useContext(MyContext);
const setSortablePinnedApps = useSetAtom(sortablePinnedAppsAtom);
const setSettingsLocalLastUpdated = useSetAtom(settingsLocalLastUpdatedAtom);
const openApp = async (
privateAppProperties,
addToPinnedApps,
setLoadingStatePrivateApp
) => {
try {
if (setLoadingStatePrivateApp) {
setLoadingStatePrivateApp(`Downloading and decrypting private app.`);
}
setOpenSnackGlobal(true);
setInfoSnackCustom({
type: 'info',
message: 'Fetching app data',
duration: null,
});
const urlData = `${getBaseApiReact()}/arbitrary/${
privateAppProperties?.service
}/${privateAppProperties?.name}/${
privateAppProperties?.identifier
}?encoding=base64`;
let data;
try {
const responseData = await fetch(urlData, {
method: 'GET',
headers: {
'Content-Type': 'application/json',
},
});
if (!responseData?.ok) {
if (setLoadingStatePrivateApp) {
setLoadingStatePrivateApp('Error! Unable to download private app.');
}
throw new Error('Unable to fetch app');
}
data = await responseData.text();
if (data?.error) {
if (setLoadingStatePrivateApp) {
setLoadingStatePrivateApp('Error! Unable to download private app.');
}
throw new Error('Unable to fetch app');
}
} catch (error) {
if (setLoadingStatePrivateApp) {
setLoadingStatePrivateApp('Error! Unable to download private app.');
}
throw error;
}
let decryptedData;
// eslint-disable-next-line no-useless-catch
try {
decryptedData = await window.sendMessage(
'DECRYPT_QORTAL_GROUP_DATA',
{
base64: data,
groupId: privateAppProperties?.groupId,
}
);
if (decryptedData?.error) {
if (setLoadingStatePrivateApp) {
setLoadingStatePrivateApp('Error! Unable to decrypt private app.');
}
throw new Error(decryptedData?.error);
}
} catch (error) {
if (setLoadingStatePrivateApp) {
setLoadingStatePrivateApp('Error! Unable to decrypt private app.');
}
throw error;
}
try {
const convertToUint = base64ToUint8Array(decryptedData);
const UintToObject = uint8ArrayToObject(convertToUint);
if (decryptedData) {
setInfoSnackCustom({
type: 'info',
message: 'Building app',
});
const endpoint = await createEndpoint(
`/arbitrary/APP/${privateAppProperties?.name}/zip?preview=true`
);
const response = await fetch(endpoint, {
method: 'POST',
headers: {
'Content-Type': 'text/plain',
},
body: UintToObject?.app,
});
const previewPath = await response.text();
const refreshfunc = async (tabId, privateAppProperties) => {
const checkIfPreviewLinkStillWorksUrl = await createEndpoint(
`/render/hash/HmtnZpcRPwisMfprUXuBp27N2xtv5cDiQjqGZo8tbZS?secret=E39WTiG4qBq3MFcMPeRZabtQuzyfHg9ZuR5SgY7nW1YH`
);
const res = await fetch(checkIfPreviewLinkStillWorksUrl);
if (res.ok) {
executeEvent('refreshApp', {
tabId: tabId,
});
} else {
const endpoint = await createEndpoint(
`/arbitrary/APP/${privateAppProperties?.name}/zip?preview=true`
);
const response = await fetch(endpoint, {
method: 'POST',
headers: {
'Content-Type': 'text/plain',
},
body: UintToObject?.app,
});
const previewPath = await response.text();
executeEvent('updateAppUrl', {
tabId: tabId,
url: await createEndpoint(previewPath),
});
setTimeout(() => {
executeEvent('refreshApp', {
tabId: tabId,
});
}, 300);
}
};
const appName = UintToObject?.name;
const logo = UintToObject?.logo
? `data:image/png;base64,${UintToObject?.logo}`
: null;
const dataBody = {
url: await createEndpoint(previewPath),
isPreview: true,
isPrivate: true,
privateAppProperties: { ...privateAppProperties, logo, appName },
filePath: '',
refreshFunc: (tabId) => {
refreshfunc(tabId, privateAppProperties);
},
};
executeEvent('addTab', {
data: dataBody,
});
setInfoSnackCustom({
type: 'success',
message: 'Opened',
});
if (setLoadingStatePrivateApp) {
setLoadingStatePrivateApp(``);
}
if (addToPinnedApps) {
setSortablePinnedApps((prev) => {
const updatedApps = [
...prev,
{
isPrivate: true,
isPreview: true,
privateAppProperties: {
...privateAppProperties,
logo,
appName,
},
},
];
saveToLocalStorage(
'ext_saved_settings',
'sortablePinnedApps',
updatedApps
);
return updatedApps;
});
setSettingsLocalLastUpdated(Date.now());
}
}
} catch (error) {
if (setLoadingStatePrivateApp) {
setLoadingStatePrivateApp(
`Error! ${error?.message || 'Unable to build private app.'}`
);
}
throw error;
}
} catch (error) {
setInfoSnackCustom({
type: 'error',
message: error?.message || 'Unable to fetch app',
});
}
};
return {
openApp,
status,
};
};