Files
parcer/src/components/api/ApiKey.tsx

255 lines
7.5 KiB
TypeScript
Raw Normal View History

2024-10-03 02:47:29 +05:30
import React, { useState, useEffect } from 'react';
import {
Box,
Button,
Typography,
IconButton,
2024-10-03 04:52:29 +05:30
CircularProgress,
2024-10-03 05:06:11 +05:30
Table,
TableBody,
TableCell,
TableContainer,
TableHead,
TableRow,
Tooltip,
2024-10-03 05:09:23 +05:30
Paper,
Dialog,
DialogTitle,
DialogContent,
DialogContentText,
DialogActions,
2024-10-03 02:47:29 +05:30
} from '@mui/material';
2025-02-08 15:44:36 +05:30
import { ContentCopy, Visibility, VisibilityOff, Delete } from '@mui/icons-material';
2024-10-03 02:47:29 +05:30
import styled from 'styled-components';
import axios from 'axios';
import { useGlobalInfoStore } from '../../context/globalInfo';
2024-11-01 08:25:33 +05:30
import { apiUrl } from '../../apiConfig';
2024-12-20 21:13:44 +05:30
import { useTranslation } from 'react-i18next';
2024-10-03 02:47:29 +05:30
const Container = styled(Box)`
display: flex;
flex-direction: column;
align-items: center;
margin-top: 50px;
margin-left: 70px;
margin-right: 70px;
2024-10-03 02:47:29 +05:30
`;
2024-10-03 03:29:38 +05:30
const ApiKeyManager = () => {
2024-12-20 21:13:44 +05:30
const { t } = useTranslation();
2024-10-03 02:47:29 +05:30
const [apiKey, setApiKey] = useState<string | null>(null);
2024-12-20 21:13:44 +05:30
const [apiKeyName, setApiKeyName] = useState<string>(t('apikey.default_name'));
2025-12-30 00:34:10 +05:30
const [apiKeyCreatedAt, setApiKeyCreatedAt] = useState<string | null>(null);
2024-10-03 02:47:29 +05:30
const [loading, setLoading] = useState<boolean>(true);
2024-10-03 05:06:11 +05:30
const [showKey, setShowKey] = useState<boolean>(false);
2024-10-03 02:47:29 +05:30
const [copySuccess, setCopySuccess] = useState<boolean>(false);
const [confirmDeleteOpen, setConfirmDeleteOpen] = useState<boolean>(false);
2024-10-03 02:51:08 +05:30
const { notify } = useGlobalInfoStore();
2024-10-03 02:47:29 +05:30
useEffect(() => {
const fetchApiKey = async () => {
try {
2024-11-01 08:25:33 +05:30
const { data } = await axios.get(`${apiUrl}/auth/api-key`);
2024-10-03 02:47:29 +05:30
setApiKey(data.api_key);
2025-12-30 00:34:10 +05:30
setApiKeyCreatedAt(data.api_key_created_at);
2024-10-03 05:27:15 +05:30
} catch (error: any) {
2025-02-24 21:45:16 +05:30
notify('error', t('apikey.notifications.fetch_error', { error: error.message }));
2024-10-03 02:47:29 +05:30
} finally {
setLoading(false);
}
};
fetchApiKey();
}, []);
const generateApiKey = async () => {
setLoading(true);
try {
2024-11-01 08:25:33 +05:30
const { data } = await axios.post(`${apiUrl}/auth/generate-api-key`);
2025-02-24 21:45:16 +05:30
setApiKey(data.api_key);
2025-12-30 00:34:10 +05:30
setApiKeyCreatedAt(data.api_key_created_at);
2025-02-24 22:00:07 +05:30
notify('success', t('apikey.notifications.generate_success'));
2024-10-03 05:27:15 +05:30
} catch (error: any) {
2025-02-24 21:45:16 +05:30
notify('error', t('apikey.notifications.generate_error', { error: error.message }));
2024-10-03 02:47:29 +05:30
} finally {
setLoading(false);
}
};
2024-10-03 05:06:11 +05:30
const deleteApiKey = async () => {
setLoading(true);
try {
2025-02-24 21:45:16 +05:30
await axios.delete(`${apiUrl}/auth/delete-api-key`);
setApiKey(null);
2025-12-30 00:34:10 +05:30
setApiKeyCreatedAt(null);
2025-02-24 21:45:16 +05:30
notify('success', t('apikey.notifications.delete_success'));
2024-10-03 05:27:15 +05:30
} catch (error: any) {
2025-02-24 21:45:16 +05:30
notify('error', t('apikey.notifications.delete_error', { error: error.message }));
2024-10-03 05:06:11 +05:30
} finally {
setLoading(false);
setConfirmDeleteOpen(false);
2024-10-03 05:06:11 +05:30
}
};
2025-02-24 21:45:16 +05:30
const copyToClipboard = () => {
if (apiKey) {
navigator.clipboard.writeText(apiKey);
2024-10-03 02:47:29 +05:30
setCopySuccess(true);
setTimeout(() => setCopySuccess(false), 2000);
2025-02-24 21:45:16 +05:30
notify('info', t('apikey.notifications.copy_success'));
2024-10-03 02:47:29 +05:30
}
};
const handleDeleteClick = () => {
setConfirmDeleteOpen(true);
};
const handleDeleteCancel = () => {
setConfirmDeleteOpen(false);
};
const handleDeleteConfirm = () => {
deleteApiKey();
};
2024-11-29 22:32:30 +05:30
if (loading) {
return (
<Box
sx={{
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
height: '100vh',
width: '100vw',
2024-11-29 22:32:30 +05:30
}}
>
<CircularProgress />
</Box>
);
}
2024-10-03 02:47:29 +05:30
2024-10-03 01:56:52 +05:30
return (
2025-11-05 20:54:48 +05:30
<Container sx={{ alignSelf: 'flex-start' }}>
<Typography variant="body1" sx={{ marginBottom: '40px' }}>
Start by creating an API key below. Then,
<a
href={`${apiUrl}/api-docs/`}
target="_blank"
rel="noopener noreferrer"
style={{ textDecoration: 'none', marginLeft: '5px', marginRight: '5px' }}
>
2025-11-05 20:54:48 +05:30
test your API
</a>
or read the{' '}
<a
href="https://docs.maxun.dev/category/api-docs"
target="_blank"
rel="noopener noreferrer"
style={{ textDecoration: 'none' }}
>
2025-11-05 20:54:48 +05:30
API documentation
</a>{' '}
for setup instructions.
2025-11-05 20:54:48 +05:30
</Typography>
2025-11-05 20:54:48 +05:30
<Typography
variant="h6"
gutterBottom
component="div"
style={{ marginBottom: '20px', textAlign: 'left', width: '100%' }}
>
{t('apikey.title')}
</Typography>
2025-11-05 20:54:48 +05:30
{apiKey ? (
<TableContainer component={Paper} sx={{ width: '100%', overflow: 'hidden' }}>
2025-12-30 00:34:58 +05:30
<Table sx={{ tableLayout: 'fixed', width: '100%' }}>
2025-11-05 20:54:48 +05:30
<TableHead>
<TableRow>
<TableCell>{t('apikey.table.name')}</TableCell>
<TableCell>{t('apikey.table.key')}</TableCell>
{apiKeyCreatedAt && <TableCell>Created On</TableCell>}
<TableCell align="center" sx={{ width: 160 }}>
{t('apikey.table.actions')}
</TableCell>
2025-11-05 20:54:48 +05:30
</TableRow>
</TableHead>
<TableBody>
<TableRow>
<TableCell>{apiKeyName}</TableCell>
<TableCell>
2025-11-05 22:18:49 +05:30
<Box sx={{ fontFamily: 'monospace', width: '20ch' }}>
{showKey ? `${apiKey?.substring(0, 10)}...` : '**********'}
2025-11-05 20:54:48 +05:30
</Box>
</TableCell>
2025-12-30 00:34:10 +05:30
{apiKeyCreatedAt && (
<TableCell>
{new Date(apiKeyCreatedAt).toLocaleDateString('en-US', {
month: 'short',
day: 'numeric',
year: 'numeric',
})}
</TableCell>
)}
2025-12-30 00:34:36 +05:30
<TableCell align="right" sx={{ width: 160 }}>
2025-11-05 20:54:48 +05:30
<Tooltip title={t('apikey.actions.copy')}>
<IconButton onClick={copyToClipboard}>
<ContentCopy />
</IconButton>
</Tooltip>
2025-11-05 20:54:48 +05:30
<Tooltip title={showKey ? t('apikey.actions.hide') : t('apikey.actions.show')}>
<IconButton onClick={() => setShowKey(!showKey)}>
{showKey ? <VisibilityOff /> : <Visibility />}
</IconButton>
</Tooltip>
2025-11-05 20:54:48 +05:30
<Tooltip title={t('apikey.actions.delete')}>
<IconButton onClick={handleDeleteClick} color="error">
2025-11-05 20:54:48 +05:30
<Delete />
</IconButton>
</Tooltip>
</TableCell>
</TableRow>
</TableBody>
</Table>
</TableContainer>
) : (
<>
<Typography>{t('apikey.no_key_message')}</Typography>
<Button
onClick={generateApiKey}
variant="contained"
color="primary"
sx={{ marginTop: '20px' }}
>
2025-11-05 20:54:48 +05:30
{t('apikey.generate_button')}
</Button>
</>
)}
<Dialog open={confirmDeleteOpen} onClose={handleDeleteCancel}>
<DialogTitle>Delete API Key</DialogTitle>
<DialogContent>
<DialogContentText>
Are you sure you want to delete this API key? This action cannot be undone and
will immediately invalidate the key.
</DialogContentText>
</DialogContent>
<DialogActions>
2026-02-03 11:22:50 +05:30
<Button color='inherit' onClick={handleDeleteCancel}>
Cancel
</Button>
<Button onClick={handleDeleteConfirm} color="error" variant="contained">
Delete
</Button>
</DialogActions>
</Dialog>
2025-11-05 20:54:48 +05:30
</Container>
);
};
export default ApiKeyManager;