diff --git a/src/pages/ProjectDetail.tsx b/src/pages/ProjectDetail.tsx
index a0176f4..985cba7 100644
--- a/src/pages/ProjectDetail.tsx
+++ b/src/pages/ProjectDetail.tsx
@@ -3,7 +3,7 @@ import { useParams, Link } from "react-router-dom";
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import {
ArrowLeft, Plus, GanttChartSquare, Columns3, CalendarDays, Trash2, Upload, Download, Lock, Pencil,
- Mail, ChevronDown, ChevronRight, RefreshCw, EyeOff, Eye,
+ Mail, ChevronDown, ChevronRight, RefreshCw, EyeOff, Eye, ExternalLink,
} from "lucide-react";
import {
getProject, getProjectMembers, getContacts, getTasks, getContract, getContractFiles,
@@ -499,12 +499,23 @@ function Contacts({ projectId }: { projectId: string }) {
function MailTab({ projectId }: { projectId: string }) {
const { nameOf } = useDirectory();
const qc = useQueryClient();
- const q = useQuery({ queryKey: ["mails", projectId], queryFn: () => getProjectMails(projectId) });
const [showHidden, setShowHidden] = useState(false);
+ const [polling, setPolling] = useState(false);
+ const q = useQuery({
+ queryKey: ["mails", projectId],
+ queryFn: () => getProjectMails(projectId),
+ refetchInterval: (query) => (polling || query.state.data?.syncing ? 3000 : false),
+ });
const sync = useMutation({
mutationFn: () => syncProjectMails(projectId),
- onSuccess: () => setTimeout(() => qc.invalidateQueries({ queryKey: ["mails", projectId] }), 2500),
+ onMutate: () => setPolling(true),
+ onError: () => { setPolling(false); alert("동기화 요청에 실패했습니다. 잠시 후 다시 시도해 주세요."); },
+ onSettled: () => {
+ qc.invalidateQueries({ queryKey: ["mails", projectId] });
+ setTimeout(() => setPolling(false), 30000); // 백필 동안 자동 폴링 후 중단
+ },
});
+ const busy = sync.isPending || polling || !!q.data?.syncing;
if (q.isLoading) return
- {data.lastSyncedAt ? `마지막 동기화 ${formatDateTime(data.lastSyncedAt)}` : data.syncing ? "처음 동기화 중…" : "아직 동기화 안 됨"} - {data.error && · 일부 메일함 오류} + {busy ? "동기화 중…" : data.lastSyncedAt ? `마지막 동기화 ${formatDateTime(data.lastSyncedAt)}` : "아직 동기화 안 됨"} + {data.error && · 동기화 오류(연동 설정 확인)}