Files
balikci/frontend/src/pages/Tokens.jsx
salvacybersec dc16d0c549 feat: Add detail pages for Companies and Tokens
- Created CompanyDetail page with stats, info, and tokens list
- Created TokenDetail page with click history and full tracking info
- Added routes for /companies/:id and /tokens/:id
- Made table rows clickable to navigate to detail pages
- Added edit, delete, and mail resend functionality
- Shows IP addresses, GeoIP location, device and browser info in click logs
2025-11-10 17:13:05 +03:00

206 lines
6.2 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { useState, useEffect } from 'react';
import { useNavigate } from 'react-router-dom';
import {
Box,
Button,
Paper,
Typography,
Table,
TableBody,
TableCell,
TableContainer,
TableHead,
TableRow,
Chip,
CircularProgress,
Dialog,
DialogTitle,
DialogContent,
DialogActions,
TextField,
MenuItem,
} from '@mui/material';
import { Add, Check, Close } from '@mui/icons-material';
import { tokenService } from '../services/tokenService';
import { companyService } from '../services/companyService';
import { templateService } from '../services/templateService';
import { format } from 'date-fns';
function Tokens() {
const navigate = useNavigate();
const [tokens, setTokens] = useState([]);
const [companies, setCompanies] = useState([]);
const [templates, setTemplates] = useState([]);
const [loading, setLoading] = useState(true);
const [openDialog, setOpenDialog] = useState(false);
const [formData, setFormData] = useState({
company_id: '',
target_email: '',
employee_name: '',
template_type: 'bank',
});
useEffect(() => {
loadData();
}, []);
const loadData = async () => {
try {
const [tokensData, companiesData, templatesData] = await Promise.all([
tokenService.getAll(),
companyService.getAll(),
templateService.getAll(),
]);
setTokens(tokensData.data);
setCompanies(companiesData.data);
setTemplates(templatesData.data);
} catch (error) {
console.error('Failed to load data:', error);
} finally {
setLoading(false);
}
};
const handleCreateAndSend = async () => {
try {
await tokenService.createAndSend(formData);
setOpenDialog(false);
setFormData({ company_id: '', target_email: '', employee_name: '', template_type: 'bank' });
loadData();
alert('Token oluşturuldu ve mail gönderildi!');
} catch (error) {
console.error('Failed to create token:', error);
alert('Token oluşturulamadı: ' + (error.response?.data?.error || error.message));
}
};
if (loading) {
return (
<Box display="flex" justifyContent="center" alignItems="center" minHeight="400px">
<CircularProgress />
</Box>
);
}
return (
<Box>
<Box display="flex" justifyContent="space-between" alignItems="center" mb={3}>
<Typography variant="h4">Tracking Tokenlar</Typography>
<Button
variant="contained"
startIcon={<Add />}
onClick={() => setOpenDialog(true)}
>
Yeni Mail Oluştur
</Button>
</Box>
<TableContainer component={Paper}>
<Table>
<TableHead>
<TableRow>
<TableCell>Email</TableCell>
<TableCell>Şirket</TableCell>
<TableCell>Çalışan</TableCell>
<TableCell>Durum</TableCell>
<TableCell align="right">Tıklama</TableCell>
<TableCell>Tarih</TableCell>
</TableRow>
</TableHead>
<TableBody>
{tokens.map((token) => (
<TableRow
key={token.id}
hover
sx={{ cursor: 'pointer' }}
onClick={() => navigate(`/tokens/${token.id}`)}
>
<TableCell>{token.target_email}</TableCell>
<TableCell>{token.company?.name}</TableCell>
<TableCell>{token.employee_name || '-'}</TableCell>
<TableCell>
<Chip
icon={token.clicked ? <Check /> : <Close />}
label={token.clicked ? 'Tıklandı' : 'Bekliyor'}
color={token.clicked ? 'success' : 'default'}
size="small"
/>
</TableCell>
<TableCell align="right">{token.click_count}×</TableCell>
<TableCell>
{format(new Date(token.created_at), 'dd/MM/yyyy HH:mm')}
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</TableContainer>
<Dialog open={openDialog} onClose={() => setOpenDialog(false)} maxWidth="sm" fullWidth>
<DialogTitle>Yeni Token Oluştur ve Mail Gönder</DialogTitle>
<DialogContent>
<TextField
select
margin="dense"
label="Şirket Seç"
fullWidth
required
value={formData.company_id}
onChange={(e) => setFormData({ ...formData, company_id: e.target.value })}
>
{companies.map((company) => (
<MenuItem key={company.id} value={company.id}>
{company.name}
</MenuItem>
))}
</TextField>
<TextField
margin="dense"
label="Hedef Email"
type="email"
fullWidth
required
value={formData.target_email}
onChange={(e) => setFormData({ ...formData, target_email: e.target.value })}
/>
<TextField
margin="dense"
label="Çalışan Adı (Opsiyonel)"
fullWidth
value={formData.employee_name}
onChange={(e) => setFormData({ ...formData, employee_name: e.target.value })}
/>
<TextField
select
margin="dense"
label="Mail Şablonu"
fullWidth
required
value={formData.template_type}
onChange={(e) => setFormData({ ...formData, template_type: e.target.value })}
>
{templates.map((template) => (
<MenuItem key={template.id} value={template.template_type}>
{template.name}
</MenuItem>
))}
</TextField>
</DialogContent>
<DialogActions>
<Button onClick={() => setOpenDialog(false)}>İptal</Button>
<Button
onClick={handleCreateAndSend}
variant="contained"
disabled={!formData.company_id || !formData.target_email}
>
Oluştur ve Gönder
</Button>
</DialogActions>
</Dialog>
</Box>
);
}
export default Tokens;