Files
balikci/frontend/src/pages/CompanyDetail.jsx
salvacybersec aed4f759b3 fix: Clean up export statements in detail pages
- Removed extra blank lines after export default in TokenDetail, CompanyDetail, Templates
- Trigger Vite HMR to reload modules with fresh exports
2025-11-10 19:15:13 +03:00

333 lines
10 KiB
JavaScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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 { useParams, useNavigate } from 'react-router-dom';
import {
Box,
Button,
Paper,
Typography,
Grid,
Card,
CardContent,
Table,
TableBody,
TableCell,
TableContainer,
TableHead,
TableRow,
Chip,
CircularProgress,
Dialog,
DialogTitle,
DialogContent,
DialogActions,
TextField,
IconButton,
} from '@mui/material';
import {
ArrowBack,
Edit,
Delete,
Token as TokenIcon,
CheckCircle,
TrendingUp,
} from '@mui/icons-material';
import { companyService } from '../services/companyService';
import { format } from 'date-fns';
function CompanyDetail() {
const { id } = useParams();
const navigate = useNavigate();
const [company, setCompany] = useState(null);
const [tokens, setTokens] = useState([]);
const [stats, setStats] = useState(null);
const [loading, setLoading] = useState(true);
const [editDialog, setEditDialog] = useState(false);
const [deleteDialog, setDeleteDialog] = useState(false);
const [formData, setFormData] = useState({
name: '',
description: '',
industry: '',
});
useEffect(() => {
loadData();
}, [id]);
const loadData = async () => {
try {
const [companyData, tokensData, statsData] = await Promise.all([
companyService.getById(id),
companyService.getTokens(id),
companyService.getStats(id),
]);
setCompany(companyData.data);
setTokens(tokensData.data);
setStats(statsData.data);
setFormData({
name: companyData.data.name,
description: companyData.data.description || '',
industry: companyData.data.industry || '',
});
} catch (error) {
console.error('Failed to load company:', error);
alert('Şirket yüklenemedi');
navigate('/companies');
} finally {
setLoading(false);
}
};
const handleUpdate = async () => {
try {
await companyService.update(id, formData);
setEditDialog(false);
loadData();
} catch (error) {
console.error('Failed to update company:', error);
alert('Şirket güncellenemedi');
}
};
const handleDelete = async () => {
try {
await companyService.delete(id);
navigate('/companies');
} catch (error) {
console.error('Failed to delete company:', error);
alert('Şirket silinemedi: Önce tokenları silmelisiniz');
}
};
if (loading) {
return (
<Box display="flex" justifyContent="center" alignItems="center" minHeight="400px">
<CircularProgress />
</Box>
);
}
return (
<Box>
{/* Header */}
<Box display="flex" alignItems="center" mb={3}>
<IconButton onClick={() => navigate('/companies')} sx={{ mr: 2 }}>
<ArrowBack />
</IconButton>
<Typography variant="h4" sx={{ flexGrow: 1 }}>
{company.name}
</Typography>
<Button
startIcon={<Edit />}
onClick={() => setEditDialog(true)}
sx={{ mr: 1 }}
>
Düzenle
</Button>
<Button
startIcon={<Delete />}
color="error"
onClick={() => setDeleteDialog(true)}
>
Sil
</Button>
</Box>
{/* Stats Cards */}
<Grid container spacing={3} sx={{ mb: 3 }}>
<Grid item xs={12} sm={4}>
<Card>
<CardContent>
<Box display="flex" justifyContent="space-between" alignItems="center">
<Box>
<Typography color="textSecondary" variant="body2">
Toplam Token
</Typography>
<Typography variant="h4">{stats.total_tokens}</Typography>
</Box>
<TokenIcon color="primary" sx={{ fontSize: 40 }} />
</Box>
</CardContent>
</Card>
</Grid>
<Grid item xs={12} sm={4}>
<Card>
<CardContent>
<Box display="flex" justifyContent="space-between" alignItems="center">
<Box>
<Typography color="textSecondary" variant="body2">
Toplam Tıklama
</Typography>
<Typography variant="h4">{stats.total_clicks}</Typography>
</Box>
<CheckCircle color="success" sx={{ fontSize: 40 }} />
</Box>
</CardContent>
</Card>
</Grid>
<Grid item xs={12} sm={4}>
<Card>
<CardContent>
<Box display="flex" justifyContent="space-between" alignItems="center">
<Box>
<Typography color="textSecondary" variant="body2">
Başarı Oranı
</Typography>
<Typography variant="h4">{stats.click_rate}%</Typography>
</Box>
<TrendingUp
color={stats.click_rate > 30 ? 'error' : 'warning'}
sx={{ fontSize: 40 }}
/>
</Box>
</CardContent>
</Card>
</Grid>
</Grid>
{/* Company Info */}
<Paper sx={{ p: 3, mb: 3 }}>
<Typography variant="h6" gutterBottom>
Şirket Bilgileri
</Typography>
<Grid container spacing={2}>
<Grid item xs={12} sm={6}>
<Typography variant="body2" color="textSecondary">
Sektör
</Typography>
<Typography variant="body1">
{company.industry || 'Belirtilmemiş'}
</Typography>
</Grid>
<Grid item xs={12} sm={6}>
<Typography variant="body2" color="textSecondary">
Oluşturulma Tarihi
</Typography>
<Typography variant="body1">
{format(new Date(company.created_at), 'dd/MM/yyyy HH:mm')}
</Typography>
</Grid>
{company.description && (
<Grid item xs={12}>
<Typography variant="body2" color="textSecondary">
ıklama
</Typography>
<Typography variant="body1">{company.description}</Typography>
</Grid>
)}
</Grid>
</Paper>
{/* Tokens Table */}
<Paper sx={{ p: 2 }}>
<Typography variant="h6" gutterBottom>
Tokenlar ({tokens.length})
</Typography>
<TableContainer>
<Table>
<TableHead>
<TableRow>
<TableCell>Email</TableCell>
<TableCell>Çalışan</TableCell>
<TableCell>Durum</TableCell>
<TableCell align="right">Tıklama</TableCell>
<TableCell>Tarih</TableCell>
</TableRow>
</TableHead>
<TableBody>
{tokens.length === 0 ? (
<TableRow>
<TableCell colSpan={5} align="center">
<Typography color="textSecondary">
Henüz token oluşturulmamış
</Typography>
</TableCell>
</TableRow>
) : (
tokens.map((token) => (
<TableRow key={token.id} hover>
<TableCell>{token.target_email}</TableCell>
<TableCell>{token.employee_name || '-'}</TableCell>
<TableCell>
<Chip
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>
</Paper>
{/* Edit Dialog */}
<Dialog open={editDialog} onClose={() => setEditDialog(false)} maxWidth="sm" fullWidth>
<DialogTitle>Şirket Düzenle</DialogTitle>
<DialogContent>
<TextField
autoFocus
margin="dense"
label="Şirket Adı"
fullWidth
required
value={formData.name}
onChange={(e) => setFormData({ ...formData, name: e.target.value })}
/>
<TextField
margin="dense"
label="Açıklama"
fullWidth
multiline
rows={2}
value={formData.description}
onChange={(e) => setFormData({ ...formData, description: e.target.value })}
/>
<TextField
margin="dense"
label="Sektör"
fullWidth
value={formData.industry}
onChange={(e) => setFormData({ ...formData, industry: e.target.value })}
/>
</DialogContent>
<DialogActions>
<Button onClick={() => setEditDialog(false)}>İptal</Button>
<Button onClick={handleUpdate} variant="contained">
Güncelle
</Button>
</DialogActions>
</Dialog>
{/* Delete Confirmation */}
<Dialog open={deleteDialog} onClose={() => setDeleteDialog(false)}>
<DialogTitle>Şirketi Sil?</DialogTitle>
<DialogContent>
<Typography>
<strong>{company.name}</strong> şirketini silmek istediğinizden emin misiniz?
Bu işlem geri alınamaz.
</Typography>
{tokens.length > 0 && (
<Typography color="error" sx={{ mt: 2 }}>
Bu şirkete ait {tokens.length} token var. Önce tokenları silmelisiniz.
</Typography>
)}
</DialogContent>
<DialogActions>
<Button onClick={() => setDeleteDialog(false)}>İptal</Button>
<Button onClick={handleDelete} color="error" variant="contained">
Sil
</Button>
</DialogActions>
</Dialog>
</Box>
);
}
export default CompanyDetail;