- 놓기 칸 = 파일 놓기 칸 부품(한 줄로 눕힘) · 임시 보관함 창 = 모달 + 고르는 카드 + 빈 상태 · 교체 확인 = 확인창 - 업로드 도중 window.confirm 둘 → 확인창 부품(글 그대로 · 단추 이름으로 선택 안내) · 예정노선 고름 줄 = 목록 줄 - 모달 CSS · 임시 목록 옛 CSS 걷음 · 가이드 촬영 선택자 · 지킴 시험 Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
138 lines
4.9 KiB
TypeScript
138 lines
4.9 KiB
TypeScript
/* =============================================================================
|
|
* B03_FileInput_UI_TempPicker.ts
|
|
* 임시 보관함 불러오기 — 대시보드에 미리 올려 둔 자료를 이 프로젝트로 가져온다.
|
|
*
|
|
* 파일 업로드 컨테이너 안에 버튼을 두고, 누르면 **완료된 보관 묶음만** 목록으로
|
|
* 보여 준다. 선택 후 [확인]을 누르면 지정 상태가 되고, 실제 이동은 화면의
|
|
* [업로드] 버튼을 눌렀을 때 일어난다(2026-08-08 사용자 지시).
|
|
* ========================================================================== */
|
|
|
|
import { createCard, createButton, setCardSelected, showToast } from "@ui/ui_template_elements";
|
|
import { createEmpty } from "@ui/ui_template_empty";
|
|
import { currentLanguageIndex, ui_locales } from "@ui/ui_template_locale";
|
|
import { openModal as openDialog } from "@ui/ui_template_modal";
|
|
import { createText } from "@ui/ui_template_text";
|
|
import { fetchTempBatches, type TempBatchItem } from "../B01_Dashboard/B01_Dashboard_Api_Temp";
|
|
import "./B03_FileInput_UI_Style_Temp.css";
|
|
|
|
function L(key: keyof typeof ui_locales): string {
|
|
return ui_locales[key][currentLanguageIndex];
|
|
}
|
|
|
|
function formatBytes(bytes: number): string {
|
|
const gb = bytes / 1024 / 1024 / 1024;
|
|
if (gb >= 1) return `${gb.toFixed(2)} GB`;
|
|
return `${(bytes / 1024 / 1024).toFixed(1)} MB`;
|
|
}
|
|
|
|
export interface TempPickerHandle {
|
|
/** 업로드 컨테이너에 붙일 요소(버튼 + 선택 안내). */
|
|
root: HTMLElement;
|
|
/** 지금 선택된 보관 묶음(없으면 null). */
|
|
selected(): TempBatchItem | null;
|
|
/** 연결 완료 후 선택 표시를 지운다. */
|
|
clear(): void;
|
|
}
|
|
|
|
/**
|
|
* 불러오기 버튼과 선택 모달을 만든다.
|
|
* `onSelected`는 선택이 바뀔 때마다 호출된다 — 호출측이 업로드 버튼 활성화를 조정한다.
|
|
*/
|
|
export function createTempPicker(
|
|
onSelected: (batch: TempBatchItem | null) => void,
|
|
): TempPickerHandle {
|
|
const root = document.createElement("div");
|
|
root.className = "b03-file__temp-picker";
|
|
|
|
const openButton = createButton({
|
|
label: L("B03_Temp_Btn_Open"),
|
|
variant: "ghost",
|
|
onClick: () => void openModal(),
|
|
});
|
|
// 선택 요약(「선택된 보관 자료 없음」·묶음 이름)은 두지 않는다 — 불러온 자료는 카드가
|
|
// 곧바로 보여 주고, 고르기 전 상태는 [파일 업로드]가 잠긴 것으로 이미 드러난다
|
|
// (2026-09-03 사용자 지시).
|
|
root.append(openButton);
|
|
|
|
let selectedBatch: TempBatchItem | null = null;
|
|
|
|
function applySelection(batch: TempBatchItem | null): void {
|
|
selectedBatch = batch;
|
|
onSelected(batch);
|
|
}
|
|
|
|
async function openModal(): Promise<void> {
|
|
let batches: TempBatchItem[] = [];
|
|
try {
|
|
const response = await fetchTempBatches();
|
|
// 프로젝트에 넣을 수 있는 것은 필수 파일이 다 찬 미연결 묶음뿐이다.
|
|
batches = response.batches.filter(
|
|
(item) => item.required_complete && item.status !== "linked",
|
|
);
|
|
} catch (error) {
|
|
showToast(error instanceof Error ? error.message : L("B03_Temp_Load_Failed"), "error");
|
|
return;
|
|
}
|
|
|
|
let pending: TempBatchItem | null = selectedBatch;
|
|
|
|
openDialog({
|
|
title: L("B03_Temp_Modal_Title"),
|
|
closeLabel: L("Common_Btn_Cancel"),
|
|
width: "40rem",
|
|
dialogClass: "b03-file__temp-modal",
|
|
mount: (body, close, actions) => {
|
|
const list = document.createElement("div");
|
|
list.className = "b03-file__temp-list";
|
|
if (batches.length === 0) {
|
|
list.append(createEmpty({ text: L("B03_Temp_Modal_Empty"), small: true }));
|
|
}
|
|
for (const batch of batches) {
|
|
const files = batch.files.map((file) => file.file_type.toUpperCase()).join(", ");
|
|
const option = createCard({
|
|
title: batch.name,
|
|
pad: 12,
|
|
selected: pending?.batch_id === batch.batch_id,
|
|
body: [
|
|
createText(
|
|
`${batch.files.length}${L("B03_Temp_FileCount")} · ${formatBytes(
|
|
batch.total_size_bytes,
|
|
)}`,
|
|
),
|
|
createText(files),
|
|
],
|
|
onSelect: () => {
|
|
pending = batch;
|
|
list
|
|
.querySelectorAll<HTMLElement>(".ui-card--select")
|
|
.forEach((card) => setCardSelected(card, card === option));
|
|
},
|
|
});
|
|
list.append(option);
|
|
}
|
|
body.append(list);
|
|
actions.append(
|
|
createButton({
|
|
label: L("Common_Btn_Confirm"),
|
|
variant: "filled",
|
|
onClick: () => {
|
|
if (!pending) {
|
|
showToast(L("B03_Temp_Select_Required"), "warning");
|
|
return;
|
|
}
|
|
applySelection(pending);
|
|
close();
|
|
},
|
|
}),
|
|
);
|
|
},
|
|
});
|
|
}
|
|
|
|
return {
|
|
root,
|
|
selected: () => selectedBatch,
|
|
clear: () => applySelection(null),
|
|
};
|
|
}
|