import React, {
useCallback,
useContext,
useEffect,
useRef,
useState,
} from 'react';
import { Spacer } from '../common/Spacer';
import { CustomButton, TextP, TextSpan } from '../styles/App-styles';
import {
Box,
Button,
ButtonBase,
Dialog,
DialogActions,
DialogContent,
DialogTitle,
FormControlLabel,
Input,
styled,
Switch,
TextField,
Typography,
useTheme,
} from '@mui/material';
import Logo1Dark from '../assets/svgs/Logo1Dark.svg';
import HelpIcon from '@mui/icons-material/Help';
import { CustomizedSnackbars } from '../components/Snackbar/Snackbar';
import { cleanUrl, gateways } from '../background';
import { GlobalContext } from '../App';
import Tooltip, { TooltipProps, tooltipClasses } from '@mui/material/Tooltip';
import ThemeSelector from '../components/Theme/ThemeSelector';
import { useTranslation } from 'react-i18next';
import LanguageSelector from '../components/Language/LanguageSelector';
const manifestData = {
version: '0.5.3',
};
export const HtmlTooltip = styled(({ className, ...props }: TooltipProps) => (
))(({ theme }) => ({
[`& .${tooltipClasses.tooltip}`]: {
backgroundColor: theme.palette.background.paper,
color: theme.palette.text.primary,
maxWidth: 320,
padding: '20px',
fontSize: theme.typography.pxToRem(12),
},
}));
function removeTrailingSlash(url) {
return url.replace(/\/+$/, '');
}
export const NotAuthenticated = ({
getRootProps,
getInputProps,
setExtstate,
apiKey,
setApiKey,
globalApiKey,
handleSetGlobalApikey,
currentNode,
setCurrentNode,
useLocalNode,
setUseLocalNode,
}) => {
const [isValidApiKey, setIsValidApiKey] = useState(null);
const [hasLocalNode, setHasLocalNode] = useState(null);
// const [useLocalNode, setUseLocalNode] = useState(false);
const [openSnack, setOpenSnack] = React.useState(false);
const [infoSnack, setInfoSnack] = React.useState(null);
const [show, setShow] = React.useState(false);
const [mode, setMode] = React.useState('list');
const [customNodes, setCustomNodes] = React.useState(null);
// const [currentNode, setCurrentNode] = React.useState({
// url: "http://127.0.0.1:12391",
// });
const [importedApiKey, setImportedApiKey] = React.useState(null);
//add and edit states
const [url, setUrl] = React.useState('https://');
const [customApikey, setCustomApiKey] = React.useState('');
const [showSelectApiKey, setShowSelectApiKey] = useState(false);
const [enteredApiKey, setEnteredApiKey] = useState('');
const [customNodeToSaveIndex, setCustomNodeToSaveIndex] =
React.useState(null);
const { showTutorial, hasSeenGettingStarted } = useContext(GlobalContext);
const theme = useTheme();
const { t } = useTranslation(['auth', 'core']);
const importedApiKeyRef = useRef(null);
const currentNodeRef = useRef(null);
const hasLocalNodeRef = useRef(null);
const isLocal = cleanUrl(currentNode?.url) === '127.0.0.1:12391';
const handleFileChangeApiKey = (event) => {
setShowSelectApiKey(false);
const file = event.target.files[0]; // Get the selected file
if (file) {
const reader = new FileReader();
reader.onload = (e) => {
const text = e.target.result; // Get the file content
setImportedApiKey(text); // Store the file content in the state
if (customNodes) {
setCustomNodes((prev) => {
const copyPrev = [...prev];
const findLocalIndex = copyPrev?.findIndex(
(item) => item?.url === 'http://127.0.0.1:12391'
);
if (findLocalIndex === -1) {
copyPrev.unshift({
url: 'http://127.0.0.1:12391',
apikey: text,
});
} else {
copyPrev[findLocalIndex] = {
url: 'http://127.0.0.1:12391',
apikey: text,
};
}
window.sendMessage('setCustomNodes', copyPrev).catch((error) => {
console.error(
'Failed to set custom nodes:',
error.message || 'An error occurred'
);
});
return copyPrev;
});
}
};
reader.readAsText(file); // Read the file as text
}
};
const checkIfUserHasLocalNode = useCallback(async () => {
try {
const url = `http://127.0.0.1:12391/admin/status`;
const response = await fetch(url, {
method: 'GET',
headers: {
'Content-Type': 'application/json',
},
});
const data = await response.json();
if (data?.height) {
setHasLocalNode(true);
return true;
}
return false;
} catch (error) {
return false;
}
}, []);
useEffect(() => {
checkIfUserHasLocalNode();
}, []);
useEffect(() => {
window
.sendMessage('getCustomNodesFromStorage')
.then((response) => {
setCustomNodes(response || []);
if (window?.electronAPI?.setAllowedDomains) {
window.electronAPI.setAllowedDomains(
response?.map((node) => node.url)
);
}
if (Array.isArray(response)) {
const findLocal = response?.find(
(item) => item?.url === 'http://127.0.0.1:12391'
);
if (findLocal && findLocal?.apikey) {
setImportedApiKey(findLocal?.apikey);
}
}
})
.catch((error) => {
console.error(
'Failed to get custom nodes from storage:',
error.message || 'An error occurred'
);
});
}, []);
useEffect(() => {
importedApiKeyRef.current = importedApiKey;
}, [importedApiKey]);
useEffect(() => {
currentNodeRef.current = currentNode;
}, [currentNode]);
useEffect(() => {
hasLocalNodeRef.current = hasLocalNode;
}, [hasLocalNode]);
const validateApiKey = useCallback(async (key, fromStartUp) => {
try {
if (key === 'isGateway') return;
const isLocalKey = cleanUrl(key?.url) === '127.0.0.1:12391';
if (
fromStartUp &&
key?.url &&
key?.apikey &&
!isLocalKey &&
!gateways.some((gateway) => key?.url?.includes(gateway))
) {
setCurrentNode({
url: key?.url,
apikey: key?.apikey,
});
let isValid = false;
const url = `${key?.url}/admin/settings/localAuthBypassEnabled`;
const response = await fetch(url);
// Assuming the response is in plain text and will be 'true' or 'false'
const data = await response.text();
if (data && data === 'true') {
isValid = true;
} else {
const url2 = `${key?.url}/admin/apikey/test?apiKey=${key?.apikey}`;
const response2 = await fetch(url2);
// Assuming the response is in plain text and will be 'true' or 'false'
const data2 = await response2.text();
if (data2 === 'true') {
isValid = true;
}
}
if (isValid) {
setIsValidApiKey(true);
setUseLocalNode(true);
return;
}
}
if (!currentNodeRef.current) return;
const stillHasLocal = await checkIfUserHasLocalNode();
if (isLocalKey && !stillHasLocal && !fromStartUp) {
throw new Error('Please turn on your local node');
}
//check custom nodes
// !gateways.some(gateway => apiKey?.url?.includes(gateway))
const isCurrentNodeLocal =
cleanUrl(currentNodeRef.current?.url) === '127.0.0.1:12391';
if (isLocalKey && !isCurrentNodeLocal) {
setIsValidApiKey(false);
setUseLocalNode(false);
return;
}
let payload = {};
if (currentNodeRef.current?.url === 'http://127.0.0.1:12391') {
payload = {
apikey: importedApiKeyRef.current || key?.apikey,
url: currentNodeRef.current?.url,
};
if (!payload?.apikey) {
try {
const generateUrl = 'http://127.0.0.1:12391/admin/apikey/generate';
const generateRes = await fetch(generateUrl, {
method: 'POST',
});
let res;
try {
res = await generateRes.clone().json();
} catch (e) {
res = await generateRes.text();
}
if (res != null && !res.error && res.length >= 8) {
payload = {
apikey: res,
url: currentNodeRef.current?.url,
};
setImportedApiKey(res); // Store the file content in the state
setCustomNodes((prev) => {
const copyPrev = [...prev];
const findLocalIndex = copyPrev?.findIndex(
(item) => item?.url === 'http://127.0.0.1:12391'
);
if (findLocalIndex === -1) {
copyPrev.unshift({
url: 'http://127.0.0.1:12391',
apikey: res,
});
} else {
copyPrev[findLocalIndex] = {
url: 'http://127.0.0.1:12391',
apikey: res,
};
}
window
.sendMessage('setCustomNodes', copyPrev)
.catch((error) => {
console.error(
'Failed to set custom nodes:',
error.message || 'An error occurred'
);
});
return copyPrev;
});
}
} catch (error) {
console.error(error);
}
}
} else if (currentNodeRef.current) {
payload = currentNodeRef.current;
}
let isValid = false;
const url = `${payload?.url}/admin/settings/localAuthBypassEnabled`;
const response = await fetch(url);
// Assuming the response is in plain text and will be 'true' or 'false'
const data = await response.text();
if (data && data === 'true') {
isValid = true;
} else {
const url2 = `${payload?.url}/admin/apikey/test?apiKey=${payload?.apikey}`;
const response2 = await fetch(url2);
// Assuming the response is in plain text and will be 'true' or 'false'
const data2 = await response2.text();
if (data2 === 'true') {
isValid = true;
}
}
if (isValid) {
window
.sendMessage('setApiKey', payload)
.then((response) => {
if (response) {
handleSetGlobalApikey(payload);
setIsValidApiKey(true);
setUseLocalNode(true);
if (!fromStartUp) {
setApiKey(payload);
}
}
})
.catch((error) => {
console.error(
'Failed to set API key:',
error.message || t('core:error', { postProcess: 'capitalize' })
);
});
} else {
setIsValidApiKey(false);
setUseLocalNode(false);
if (!fromStartUp) {
setInfoSnack({
type: 'error',
message: t('auth:apikey.select_valid', {
postProcess: 'capitalize',
}),
});
setOpenSnack(true);
}
}
} catch (error) {
setIsValidApiKey(false);
setUseLocalNode(false);
if (fromStartUp) {
setCurrentNode({
url: 'http://127.0.0.1:12391',
});
window
.sendMessage('setApiKey', 'isGateway')
.then((response) => {
if (response) {
setApiKey(null);
handleSetGlobalApikey(null);
}
})
.catch((error) => {
console.error(
'Failed to set API key:',
error.message ||
t('core:error', {
postProcess: 'capitalize',
})
);
});
return;
}
if (!fromStartUp) {
setInfoSnack({
type: 'error',
message:
error?.message ||
t('auth:apikey.select_valid', {
postProcess: 'capitalize',
}),
});
setOpenSnack(true);
}
console.error('Error validating API key:', error);
}
}, []);
useEffect(() => {
if (apiKey) {
validateApiKey(apiKey, true);
}
}, [apiKey]);
const addCustomNode = () => {
setMode('add-node');
};
const saveCustomNodes = (myNodes, isFullListOfNodes) => {
let nodes = [...(myNodes || [])];
if (!isFullListOfNodes && customNodeToSaveIndex !== null) {
nodes.splice(customNodeToSaveIndex, 1, {
url: removeTrailingSlash(url),
apikey: customApikey,
});
} else if (!isFullListOfNodes && url) {
nodes.push({
url: removeTrailingSlash(url),
apikey: customApikey,
});
}
setCustomNodes(nodes);
setCustomNodeToSaveIndex(null);
if (!nodes) return;
window
.sendMessage('setCustomNodes', nodes)
.then((response) => {
if (response) {
setMode('list');
setUrl('https://');
setCustomApiKey('');
if (window?.electronAPI?.setAllowedDomains) {
window.electronAPI.setAllowedDomains(
nodes?.map((node) => node.url)
);
}
// add alert if needed
}
})
.catch((error) => {
console.error(
'Failed to set custom nodes:',
error.message || 'An error occurred'
);
});
};
return (
<>
{t('auth:welcome', { postProcess: 'capitalize' })}
{' '}
QORTAL
{t('auth:tips.digital_id', { postProcess: 'capitalize' })}
}
>
setExtstate('wallets')}>
{t('auth:account.account_many', { postProcess: 'capitalize' })}
{t('auth:tips.new_users', { postProcess: 'capitalize' })}
{t('auth:tips.new_account', { postProcess: 'capitalize' })}
}
>
{
setExtstate('create-wallet');
}}
sx={{
backgroundColor:
hasSeenGettingStarted === false && 'var(--green)',
color: hasSeenGettingStarted === false && 'black',
'&:hover': {
backgroundColor:
hasSeenGettingStarted === false && 'var(--green)',
color: hasSeenGettingStarted === false && 'black',
},
}}
>
{t('auth:create_account', { postProcess: 'capitalize' })}
{t('auth:node.using', { postProcess: 'capitalize' })}:{' '}
{currentNode?.url}
<>
<>
{t('auth:advanced_users', { postProcess: 'capitalize' })}
{
if (event.target.checked) {
validateApiKey(currentNode);
} else {
setCurrentNode({
url: 'http://127.0.0.1:12391',
});
setUseLocalNode(false);
window
.sendMessage('setApiKey', null)
.then((response) => {
if (response) {
setApiKey(null);
handleSetGlobalApikey(null);
}
})
.catch((error) => {
console.error(
'Failed to set API key:',
error.message || 'An error occurred'
);
});
}
}}
disabled={false}
/>
}
label={
isLocal
? t('auth:node.use_local', { postProcess: 'capitalize' })
: t('auth:node.use_custom', { postProcess: 'capitalize' })
}
/>
{currentNode?.url === 'http://127.0.0.1:12391' && (
<>
{t('auth:apikey.key', { postProcess: 'capitalize' })}:{' '}
{importedApiKey}
>
)}
>
{t('auth:build_version', { postProcess: 'capitalize' })}:
{manifestData?.version}
>
{show && (
)}
{showSelectApiKey && (
)}
{
showTutorial('create-account', true);
}}
sx={{
position: 'fixed',
bottom: '25px',
right: '25px',
}}
>
>
);
};