diff --git a/src/lib/api.ts b/src/lib/api.ts index b2bcfc9..29a35cd 100644 --- a/src/lib/api.ts +++ b/src/lib/api.ts @@ -2,7 +2,7 @@ import axios from "axios"; import type { Account, AcctSummary, ApprovalQueue, Attendance, AuditLog, ClientContact, Company, Contract, ContractFile, Dashboard, Department, DirectoryEntry, IncentiveConfig, - LeaveBalance, LeaveRequest, MailNote, Me, Member, MyIncentive, NavItem, Notification, + LeaveBalance, LeaveRequest, MailFull, MailNote, Me, Member, MyIncentive, NavItem, Notification, OvertimeRequest, PaymentSplit, PaymentStage, Product, Project, ProjectMailsResponse, ProjectMember, ProjectTask, Settlement, SimResult, TaskComment, TaxRecord, Timesheet, Transaction, UserIncentive, Version, WorkPolicy, WorkStatusEvent, WorkStatusKind, @@ -153,6 +153,12 @@ export const getMailNotes = (id: string) => api.get(`/projects/${id}/mail-notes`).then((r) => r.data); export const putMailNote = (id: string, messageId: string, body: string) => api.put(`/projects/${id}/mail-notes`, { messageId, body }).then((r) => r.data); +export const getMailFull = (id: string, messageId: string) => + api.get(`/projects/${id}/mails/full`, { params: { messageId } }).then((r) => r.data); +export const mailAttachmentUrl = ( + id: string, + p: { messageId: string; gmailMsgId: string; attachmentId: string; filename: string } +) => `/api/projects/${id}/mails/attachment?${new URLSearchParams(p).toString()}`; export const syncProjectMails = (id: string) => api.post(`/projects/${id}/mails/sync`).then((r) => r.data); export const hideMail = (id: string, messageId: string, hidden: boolean) => diff --git a/src/pages/ProjectDetail.tsx b/src/pages/ProjectDetail.tsx index 985cba7..17b9bdf 100644 --- a/src/pages/ProjectDetail.tsx +++ b/src/pages/ProjectDetail.tsx @@ -9,7 +9,7 @@ import { getProject, getProjectMembers, getContacts, getTasks, getContract, getContractFiles, getPayments, upsertProjectMember, deleteProjectMember, createTask, updateTask, deleteTask, getTaskComments, createTaskComment, deleteTaskComment, - getProjectMails, putMailNote, syncProjectMails, hideMail, + getProjectMails, putMailNote, syncProjectMails, hideMail, getMailFull, mailAttachmentUrl, upsertContact, deleteContact, patchProjectNotes, putContract, uploadContractFile, getFileDownloadUrl, deleteContractFile, createPayment, updatePayment, deletePayment, recomputeProject, updateProject, @@ -596,6 +596,13 @@ function MailRow({ projectId, mail, nameOf }: { projectId: string; mail: Project const hide = useMutation({ mutationFn: () => hideMail(projectId, mail.messageId, !mail.hidden), onSuccess: invalidate }); const when = mail.ts ? formatDateTime(new Date(mail.ts).toISOString()) : mail.date; const rcpt = recipientSummary(mail.to, mail.cc); + // 펼칠 때만 본문 전문 + 첨부 리스트를 온디맨드로 가져온다. + const fullQ = useQuery({ + queryKey: ["mail-full", projectId, mail.messageId], + queryFn: () => getMailFull(projectId, mail.messageId), + enabled: open, + staleTime: 5 * 60_000, + }); return ( @@ -640,7 +647,7 @@ function MailRow({ projectId, mail, nameOf }: { projectId: string; mail: Project {open && ( -
+
보낸사람 {mail.from}
받는사람 {mail.to || "—"}
@@ -648,6 +655,42 @@ function MailRow({ projectId, mail, nameOf }: { projectId: string; mail: Project
시각 {when}
발견 메일함 {nameOf(mail.mailbox)}
+ + {/* 메일 전문 (본문) */} +
+
+ 메일 전문 + Gmail에서 열기 +
+ {fullQ.isLoading ? ( +
본문 불러오는 중…
+ ) : fullQ.isError ? ( +
본문을 불러오지 못했습니다. (메일 연동/권한 확인)
+ ) : fullQ.data?.isHtml ? ( +