widget email 18
This commit is contained in:
parent
c83784ab44
commit
a48573c137
@ -5,101 +5,20 @@ import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
|||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import { RefreshCw, Mail } from "lucide-react";
|
import { RefreshCw, Mail } from "lucide-react";
|
||||||
import { useSession, signIn } from "next-auth/react";
|
import { useSession, signIn } from "next-auth/react";
|
||||||
import { formatDistance } from 'date-fns/formatDistance';
|
|
||||||
import { fr } from 'date-fns/locale/fr';
|
|
||||||
|
|
||||||
interface Email {
|
|
||||||
id: string;
|
|
||||||
subject: string;
|
|
||||||
sender: {
|
|
||||||
name: string;
|
|
||||||
email: string;
|
|
||||||
};
|
|
||||||
date: string;
|
|
||||||
isUnread: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface EmailResponse {
|
|
||||||
emails: Email[];
|
|
||||||
mailUrl: string;
|
|
||||||
error?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function Email() {
|
export function Email() {
|
||||||
const [emails, setEmails] = useState<Email[]>([]);
|
|
||||||
const [mailUrl, setMailUrl] = useState<string | null>(null);
|
|
||||||
const [loading, setLoading] = useState(true);
|
const [loading, setLoading] = useState(true);
|
||||||
const [error, setError] = useState<string | null>(null);
|
const [error, setError] = useState<string | null>(null);
|
||||||
const [refreshing, setRefreshing] = useState(false);
|
|
||||||
const { status } = useSession();
|
const { status } = useSession();
|
||||||
|
|
||||||
const fetchEmails = async (isRefresh = false) => {
|
|
||||||
if (isRefresh) setRefreshing(true);
|
|
||||||
if (!isRefresh) setLoading(true);
|
|
||||||
|
|
||||||
try {
|
|
||||||
const response = await fetch('/api/emails');
|
|
||||||
const data: EmailResponse = await response.json();
|
|
||||||
|
|
||||||
if (!response.ok) {
|
|
||||||
// Handle session expiration
|
|
||||||
if (response.status === 401) {
|
|
||||||
signIn(); // Redirect to login
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle specific error messages
|
|
||||||
if (response.status === 404) {
|
|
||||||
setError("L'application Mail n'est pas disponible sur Nextcloud. Veuillez contacter votre administrateur.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new Error(data.error || 'Failed to fetch emails');
|
|
||||||
}
|
|
||||||
|
|
||||||
setEmails(data.emails || []);
|
|
||||||
setMailUrl(data.mailUrl);
|
|
||||||
setError(null);
|
|
||||||
} catch (err) {
|
|
||||||
console.error('Error fetching emails:', err);
|
|
||||||
setError(err instanceof Error ? err.message : 'Erreur lors de la récupération des emails');
|
|
||||||
} finally {
|
|
||||||
setLoading(false);
|
|
||||||
setRefreshing(false);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Initial fetch
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (status === 'authenticated') {
|
if (status === 'authenticated') {
|
||||||
fetchEmails();
|
setLoading(false);
|
||||||
|
} else if (status === 'unauthenticated') {
|
||||||
|
signIn();
|
||||||
}
|
}
|
||||||
}, [status]);
|
}, [status]);
|
||||||
|
|
||||||
// Auto-refresh every 5 minutes
|
|
||||||
useEffect(() => {
|
|
||||||
if (status !== 'authenticated') return;
|
|
||||||
|
|
||||||
const interval = setInterval(() => {
|
|
||||||
fetchEmails(true);
|
|
||||||
}, 5 * 60 * 1000);
|
|
||||||
|
|
||||||
return () => clearInterval(interval);
|
|
||||||
}, [status]);
|
|
||||||
|
|
||||||
const formatDate = (dateString: string) => {
|
|
||||||
try {
|
|
||||||
const date = new Date(dateString);
|
|
||||||
return formatDistance(date, new Date(), {
|
|
||||||
addSuffix: true,
|
|
||||||
locale: fr
|
|
||||||
});
|
|
||||||
} catch (err) {
|
|
||||||
console.error('Error formatting date:', err);
|
|
||||||
return dateString;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if (status === 'loading' || loading) {
|
if (status === 'loading' || loading) {
|
||||||
return (
|
return (
|
||||||
<Card className="transition-transform duration-500 ease-in-out transform hover:scale-105 bg-white/95 backdrop-blur-sm border-0 shadow-lg h-full">
|
<Card className="transition-transform duration-500 ease-in-out transform hover:scale-105 bg-white/95 backdrop-blur-sm border-0 shadow-lg h-full">
|
||||||
@ -107,7 +26,7 @@ export function Email() {
|
|||||||
<CardTitle className="text-lg font-semibold text-gray-800">
|
<CardTitle className="text-lg font-semibold text-gray-800">
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<Mail className="h-5 w-5" />
|
<Mail className="h-5 w-5" />
|
||||||
<span>Emails non lus</span>
|
<span>Emails</span>
|
||||||
</div>
|
</div>
|
||||||
</CardTitle>
|
</CardTitle>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
@ -126,50 +45,16 @@ export function Email() {
|
|||||||
<CardTitle className="text-lg font-semibold text-gray-800">
|
<CardTitle className="text-lg font-semibold text-gray-800">
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<Mail className="h-5 w-5" />
|
<Mail className="h-5 w-5" />
|
||||||
<span>Emails non lus</span>
|
<span>Emails</span>
|
||||||
</div>
|
</div>
|
||||||
</CardTitle>
|
</CardTitle>
|
||||||
<Button
|
|
||||||
variant="ghost"
|
|
||||||
size="icon"
|
|
||||||
onClick={() => fetchEmails(true)}
|
|
||||||
disabled={refreshing}
|
|
||||||
className={`${refreshing ? 'animate-spin' : ''} text-gray-600 hover:text-gray-900`}
|
|
||||||
>
|
|
||||||
<RefreshCw className="h-4 w-4" />
|
|
||||||
</Button>
|
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent className="p-3">
|
<CardContent className="p-0 h-[calc(100%-3.5rem)]">
|
||||||
{error ? (
|
<iframe
|
||||||
<p className="text-center text-red-500">{error}</p>
|
src="https://lab.slm-lab.net/email"
|
||||||
) : (
|
className="w-full h-full border-0"
|
||||||
<div className="space-y-2 max-h-[220px] overflow-y-auto">
|
title="Email Inbox"
|
||||||
{emails.length === 0 ? (
|
/>
|
||||||
<p className="text-center text-gray-500">Aucun email non lu</p>
|
|
||||||
) : (
|
|
||||||
emails.map((email) => (
|
|
||||||
<div
|
|
||||||
key={email.id}
|
|
||||||
className="p-2 hover:bg-gray-50/50 rounded-lg transition-colors cursor-pointer"
|
|
||||||
onClick={() => mailUrl && window.open(mailUrl, '_blank')}
|
|
||||||
>
|
|
||||||
<div className="flex items-center justify-between mb-1">
|
|
||||||
<span className="text-sm text-gray-600 truncate max-w-[60%]" title={email.sender.name}>
|
|
||||||
{email.sender.name}
|
|
||||||
</span>
|
|
||||||
<div className="flex items-center space-x-2">
|
|
||||||
<span className="w-1.5 h-1.5 bg-blue-600 rounded-full"></span>
|
|
||||||
<span className="text-xs text-gray-500">{formatDate(email.date)}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<h3 className="text-sm font-semibold text-gray-800 line-clamp-2" title={email.subject}>
|
|
||||||
{email.subject}
|
|
||||||
</h3>
|
|
||||||
</div>
|
|
||||||
))
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
);
|
);
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user