generated from ttipo/project-base
fix(frontend): 묶은 휴지통의 영구 삭제 글과 띄어 쓴 조사를 고친다
- 대화로 묶은 휴지통에서 줄을 골라 영구 삭제하면 확인 창 · 알림을
"휴지통에 있는 메일 N통을 …"으로 쓴다 — 줄의 통 수는 대화 전체라서
(옮기기 알림 "{메일함}에 있는 메일 N통을 …"과 같은 결)
- 값을 끼워 넣는 글의 띄어 쓴 조사를 붙인다(9단계 "@도메인에서",
11단계 "25MB를" · "2GB까지" · "20MB가"), 공개 내려받기 화면의 신고
주소는 끝 글자로 조사를 고른다
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -14,7 +14,8 @@ import { useMailStore, type MailBulkResult, type MoveOptions } from '@/stores/ma
|
||||
// - 열어 둔 메일을 옮기거나 지워 목록에서 빠졌으면 목록 주소로 바꿔 끼운다 (본문 칸이 없는 메일을 붙들지 않게).
|
||||
// 끝났을 때 다른 목록으로 옮겨 가 있으면(stale) 그 목록에 기대어 움직이지 않는다
|
||||
// - 대화로 묶은 메일함(14단계)은 고른 줄의 메일 모두에 한다(붙잡힌 메일은 빼고 — 스토어). "중요 해제"는 고른 줄이 모두 중요 표시가 있을 때.
|
||||
// 옮기기 · 삭제 · 스팸 알림은 "받은편지함에 있는 메일 2통을 휴지통으로 옮겼습니다." — 줄의 "4통"은 대화 전체라서 (2026-11-06 실사용 시험)
|
||||
// 옮기기 · 삭제 · 스팸 알림은 "받은편지함에 있는 메일 2통을 휴지통으로 옮겼습니다." — 줄의 "4통"은 대화 전체라서 (2026-11-06 실사용 시험).
|
||||
// 휴지통의 영구 삭제도 확인 창 · 알림이 "휴지통에 있는 메일 2통을 영구 삭제할까요? · …했습니다." (2026-11-07 — conversationFrom)
|
||||
|
||||
export function useBulkMailActions() {
|
||||
const mailStore = useMailStore()
|
||||
@@ -35,6 +36,13 @@ export function useBulkMailActions() {
|
||||
const inJunk = computed<boolean>(() => mailStore.currentMailbox?.role === 'junk')
|
||||
/** 스팸 단추가 옮길 곳 — 스팸 신고는 스팸메일함, 스팸 아님은 받은편지함. 그 메일함을 모르면 단추를 그리지 않는다 */
|
||||
const spamTarget = computed<Mailbox | null>(() => mailStore.mailboxByRole(inJunk.value ? 'inbox' : 'junk'))
|
||||
/**
|
||||
* 대화로 묶은 목록이면 지금 메일함의 이름 — 줄의 통 수는 대화 전체라 알림 · 영구 삭제 확인이 그 메일함의 메일임을 밝힌다
|
||||
* ("받은편지함에 있는 메일 2통을 …" · "휴지통에 있는 메일 2통을 영구 삭제할까요?"). 묶지 않은 목록이면 null (지금 글 그대로)
|
||||
*/
|
||||
const conversationFrom = computed<string | null>(() =>
|
||||
mailStore.isConversationList ? (mailStore.currentMailbox?.name ?? null) : null,
|
||||
)
|
||||
/** 이동 메뉴 — 지금 메일함 · 임시보관함 · 휴지통을 뺀 메일함 (메일함 패널 순서) */
|
||||
const moveTargets = computed<Mailbox[]>(() =>
|
||||
mailStore.orderedMailboxes
|
||||
@@ -66,7 +74,7 @@ export function useBulkMailActions() {
|
||||
async function moveTo(mailbox: Mailbox, options: MoveOptions = {}): Promise<void> {
|
||||
if (busy.value || mailStore.checkedCount === 0) return
|
||||
// 대화로 묶은 목록은 줄의 통 수가 대화 전체라 알림이 지금 메일함의 메일임을 밝힌다 — 시작할 때의 메일함 (기다리는 사이 목록이 바뀔 수 있다)
|
||||
const from = mailStore.isConversationList ? (mailStore.currentMailbox?.name ?? null) : null
|
||||
const from = conversationFrom.value
|
||||
busy.value = true
|
||||
try {
|
||||
const result = await mailStore.moveChecked(mailbox.id, options)
|
||||
@@ -103,11 +111,13 @@ export function useBulkMailActions() {
|
||||
/** 영구 삭제 — 확인 대화상자에서 「영구 삭제」를 누른 뒤에만 부른다 */
|
||||
async function purge(): Promise<void> {
|
||||
if (busy.value || mailStore.checkedCount === 0) return
|
||||
// 옮기기와 같은 까닭 — 대화로 묶은 휴지통이면 "휴지통에 있는 메일 N통을 영구 삭제했습니다." (시작할 때의 메일함)
|
||||
const from = conversationFrom.value
|
||||
busy.value = true
|
||||
try {
|
||||
const result = await mailStore.purgeChecked()
|
||||
await leaveRemovedMessage(result)
|
||||
feedback.announcePurge(result)
|
||||
feedback.announcePurge(result, { from })
|
||||
} finally {
|
||||
busy.value = false
|
||||
}
|
||||
@@ -119,6 +129,7 @@ export function useBulkMailActions() {
|
||||
inTrash,
|
||||
inJunk,
|
||||
spamTarget,
|
||||
conversationFrom,
|
||||
moveTargets,
|
||||
markRead,
|
||||
toggleFlagged,
|
||||
|
||||
@@ -336,7 +336,7 @@ describe('useLargeFileUploads', () => {
|
||||
|
||||
expect(uploads.items.value.map((item) => [item.name, item.phase, item.errorText])).toEqual([
|
||||
// 한도 글은 MB · GB 로 적는다 — 이 테스트의 12바이트 한도는 "0MB" 로 보인다
|
||||
['too-big.zip', 'rejected', '파일 하나는 0MB 까지 보낼 수 있습니다.'],
|
||||
['too-big.zip', 'rejected', '파일 하나는 0MB까지 보낼 수 있습니다.'],
|
||||
['first.zip', 'ready', null],
|
||||
['second.zip', 'rejected', '링크로 보내는 파일은 메일 한 통에 1개까지입니다.'],
|
||||
['setup.exe', 'rejected', '허용되지 않는 파일 형식입니다. 파일을 확인해 주세요.'],
|
||||
|
||||
@@ -6,7 +6,7 @@ import {
|
||||
purgedMessageText,
|
||||
restoredMessageText,
|
||||
type BulkOrigin,
|
||||
type MovedTextOptions,
|
||||
type BulkTextOptions,
|
||||
} from '@/shared/utils/mail-bulk'
|
||||
import { useMailStore, type BulkMoveResult, type MailBulkResult, type MoveOptions } from '@/stores/mail.store'
|
||||
|
||||
@@ -17,7 +17,7 @@ import { useMailStore, type BulkMoveResult, type MailBulkResult, type MoveOption
|
||||
* 스팸 신고는 같은 문구("…스팸메일함으로 옮겼습니다."), 스팸 아님은 "메일 N통을 스팸이 아닌 메일로 표시해 받은편지함으로 옮겼습니다."
|
||||
* — 스팸 신고 · 스팸 아님의 되돌리기는 원래 메일함으로 옮기며 표시도 되돌린다(보낸 값의 반대)
|
||||
* - 대화로 묶은 목록에서 줄에 한 일(14단계)은 "받은편지함에 있는 메일 2통을 휴지통으로 옮겼습니다." — 줄의 통 수는 대화 전체라서 (options.from)
|
||||
* - "메일 N통을 영구 삭제했습니다."
|
||||
* - "메일 N통을 영구 삭제했습니다." — 대화로 묶은 휴지통에서 줄에 한 일이면 "휴지통에 있는 메일 N통을 영구 삭제했습니다." (같은 까닭 · options.from)
|
||||
* - 일부만 처리했으면 뒤에 "N통은 그사이 옮겨졌거나 지워져 그대로 두었습니다." (하나도 못 했으면 그 문장만)
|
||||
* - 하나도 보내지 못했으면(요청 실패 — 인터셉터가 알렸다) 알리지 않는다
|
||||
* 되돌리기는 알림을 띄운 세션에서만 움직인다 (useToast)
|
||||
@@ -41,7 +41,7 @@ export function useMailMoveFeedback() {
|
||||
}
|
||||
|
||||
/** textOptions.from — 대화로 묶은 목록에서 줄에 한 일이면 그 목록의 메일함 이름 ("받은편지함에 있는 메일 2통을 …") */
|
||||
function announceMove(result: BulkMoveResult, mailboxName: string, textOptions: MovedTextOptions = {}) {
|
||||
function announceMove(result: BulkMoveResult, mailboxName: string, textOptions: BulkTextOptions = {}) {
|
||||
const done = result.doneIds.length
|
||||
const skipped = result.skippedIds.length
|
||||
if (done === 0 && skipped === 0) return
|
||||
@@ -57,10 +57,11 @@ export function useMailMoveFeedback() {
|
||||
)
|
||||
}
|
||||
|
||||
function announcePurge(result: MailBulkResult) {
|
||||
/** textOptions.from — 대화로 묶은 휴지통에서 줄에 한 일이면 그 메일함 이름 ("휴지통에 있는 메일 2통을 영구 삭제했습니다.") */
|
||||
function announcePurge(result: MailBulkResult, textOptions: BulkTextOptions = {}) {
|
||||
const done = result.doneIds.length
|
||||
const skipped = result.skippedIds.length
|
||||
if (done > 0 || skipped > 0) toast.success(purgedMessageText(done, skipped))
|
||||
if (done > 0 || skipped > 0) toast.success(purgedMessageText(done, skipped, textOptions))
|
||||
}
|
||||
|
||||
return { announceMove, announcePurge }
|
||||
|
||||
Reference in New Issue
Block a user