diff --git a/frontend/components/common/ScreenModal.tsx b/frontend/components/common/ScreenModal.tsx index 8cf53d5c..f44e2227 100644 --- a/frontend/components/common/ScreenModal.tsx +++ b/frontend/components/common/ScreenModal.tsx @@ -31,7 +31,7 @@ interface ScreenModalProps { } export const ScreenModal: React.FC = ({ className }) => { - const { userId } = useAuth(); + const { userId, userName, user } = useAuth(); const [modalState, setModalState] = useState({ isOpen: false, @@ -587,6 +587,9 @@ export const ScreenModal: React.FC = ({ className }) => { id: modalState.screenId!, tableName: screenData.screenInfo?.tableName, }} + userId={userId} + userName={userName} + companyCode={user?.companyCode} /> ); })} diff --git a/frontend/components/screen/InteractiveScreenViewerDynamic.tsx b/frontend/components/screen/InteractiveScreenViewerDynamic.tsx index ba27c94e..df134685 100644 --- a/frontend/components/screen/InteractiveScreenViewerDynamic.tsx +++ b/frontend/components/screen/InteractiveScreenViewerDynamic.tsx @@ -42,6 +42,10 @@ interface InteractiveScreenViewerProps { onSave?: () => Promise; onRefresh?: () => void; onFlowRefresh?: () => void; + // ๐Ÿ†• ์™ธ๋ถ€์—์„œ ์ „๋‹ฌ๋ฐ›๋Š” ์‚ฌ์šฉ์ž ์ •๋ณด (ScreenModal ๋“ฑ์—์„œ ์‚ฌ์šฉ) + userId?: string; + userName?: string; + companyCode?: string; } export const InteractiveScreenViewerDynamic: React.FC = ({ @@ -54,9 +58,24 @@ export const InteractiveScreenViewerDynamic: React.FC { const { isPreviewMode } = useScreenPreview(); // ํ”„๋ฆฌ๋ทฐ ๋ชจ๋“œ ํ™•์ธ - const { userName, user } = useAuth(); + const { userName: authUserName, user: authUser } = useAuth(); + + // ์™ธ๋ถ€์—์„œ ์ „๋‹ฌ๋ฐ›์€ ์‚ฌ์šฉ์ž ์ •๋ณด๊ฐ€ ์žˆ์œผ๋ฉด ์šฐ์„  ์‚ฌ์šฉ (ScreenModal ๋“ฑ์—์„œ) + const userName = externalUserName || authUserName; + const user = + externalUserId && externalUserId !== authUser?.userId + ? { + userId: externalUserId, + userName: externalUserName || authUserName || "", + companyCode: externalCompanyCode || authUser?.companyCode || "", + isAdmin: authUser?.isAdmin || false, + } + : authUser; const [localFormData, setLocalFormData] = useState>({}); const [dateValues, setDateValues] = useState>({}); @@ -130,59 +149,55 @@ export const InteractiveScreenViewerDynamic: React.FC { if (e.key === "Enter" && !e.shiftKey) { const target = e.target as HTMLElement; - + // ํ•œ๊ธ€ ์กฐํ•ฉ ์ค‘์ด๋ฉด ๋ฌด์‹œ (ํ•œ๊ธ€ ์ž…๋ ฅ ๋ฌธ์ œ ๋ฐฉ์ง€) if ((e as any).isComposing || e.keyCode === 229) { return; } - + // textarea๋Š” ์ œ์™ธ (์—ฌ๋Ÿฌ ์ค„ ์ž…๋ ฅ) if (target.tagName === "TEXTAREA") { return; } - + // input, select ๋“ฑ์˜ ํผ ์š”์†Œ์—์„œ๋งŒ ์ž‘๋™ - if ( - target.tagName === "INPUT" || - target.tagName === "SELECT" || - target.getAttribute("role") === "combobox" - ) { + if (target.tagName === "INPUT" || target.tagName === "SELECT" || target.getAttribute("role") === "combobox") { e.preventDefault(); - + // ๋ชจ๋“  ํฌ์ปค์Šค ๊ฐ€๋Šฅํ•œ ์š”์†Œ ์ฐพ๊ธฐ const focusableElements = document.querySelectorAll( - 'input:not([disabled]):not([type="hidden"]), select:not([disabled]), textarea:not([disabled]), [role="combobox"]:not([disabled])' + 'input:not([disabled]):not([type="hidden"]), select:not([disabled]), textarea:not([disabled]), [role="combobox"]:not([disabled])', ); - + // ํ™”๋ฉด์— ๋ณด์ด๋Š” ์ˆœ์„œ(Y ์ขŒํ‘œ โ†’ X ์ขŒํ‘œ)๋Œ€๋กœ ์ •๋ ฌ const focusableArray = Array.from(focusableElements).sort((a, b) => { const rectA = a.getBoundingClientRect(); const rectB = b.getBoundingClientRect(); - + // Y ์ขŒํ‘œ ์ฐจ์ด๊ฐ€ 10px ์ด์ƒ์ด๋ฉด Y ์ขŒํ‘œ๋กœ ์ •๋ ฌ (์œ„์—์„œ ์•„๋ž˜๋กœ) if (Math.abs(rectA.top - rectB.top) > 10) { return rectA.top - rectB.top; } - + // ๊ฐ™์€ ์ค„์ด๋ฉด X ์ขŒํ‘œ๋กœ ์ •๋ ฌ (์™ผ์ชฝ์—์„œ ์˜ค๋ฅธ์ชฝ์œผ๋กœ) return rectA.left - rectB.left; }); - + const currentIndex = focusableArray.indexOf(target); - + if (currentIndex !== -1 && currentIndex < focusableArray.length - 1) { // ๋‹ค์Œ ์š”์†Œ๋กœ ํฌ์ปค์Šค ์ด๋™ const nextElement = focusableArray[currentIndex + 1]; nextElement.focus(); - + // select() ์ œ๊ฑฐ: ํ•œ๊ธ€ ์ž…๋ ฅ ์‹œ ์ด์ „ ํ•„๋“œ์˜ ๋งˆ์ง€๋ง‰ ๊ธ€์ž๊ฐ€ ๋ณต์‚ฌ๋˜๋Š” ๋ฒ„๊ทธ ๋ฐฉ์ง€ } } } }; - + document.addEventListener("keydown", handleEnterKey); - + return () => { document.removeEventListener("keydown", handleEnterKey); }; @@ -193,31 +208,26 @@ export const InteractiveScreenViewerDynamic: React.FC { for (const comp of allComponents) { // type: "component" ๋˜๋Š” type: "widget" ๋ชจ๋‘ ์ฒ˜๋ฆฌ - if (comp.type === 'widget' || comp.type === 'component') { + if (comp.type === "widget" || comp.type === "component") { const widget = comp as any; const fieldName = widget.columnName || widget.id; - + // autoFill ์ฒ˜๋ฆฌ (ํ…Œ์ด๋ธ” ์กฐํšŒ ๊ธฐ๋ฐ˜ ์ž๋™ ์ž…๋ ฅ) if (widget.autoFill?.enabled || (comp as any).autoFill?.enabled) { const autoFillConfig = widget.autoFill || (comp as any).autoFill; const currentValue = formData[fieldName]; - - if (currentValue === undefined || currentValue === '') { + + if (currentValue === undefined || currentValue === "") { const { sourceTable, filterColumn, userField, displayColumn } = autoFillConfig; - + // ์‚ฌ์šฉ์ž ์ •๋ณด์—์„œ ํ•„ํ„ฐ ๊ฐ’ ๊ฐ€์ ธ์˜ค๊ธฐ const userValue = user?.[userField]; - + if (userValue && sourceTable && filterColumn && displayColumn) { try { const { tableTypeApi } = await import("@/lib/api/screen"); - const result = await tableTypeApi.getTableRecord( - sourceTable, - filterColumn, - userValue, - displayColumn - ); - + const result = await tableTypeApi.getTableRecord(sourceTable, filterColumn, userValue, displayColumn); + updateFormData(fieldName, result.value); } catch (error) { console.error(`autoFill ์กฐํšŒ ์‹คํŒจ: ${fieldName}`, error); @@ -329,10 +339,13 @@ export const InteractiveScreenViewerDynamic: React.FC { - // ๋ถ€๋ชจ๋กœ๋ถ€ํ„ฐ ์ „๋‹ฌ๋ฐ›์€ onRefresh ๋˜๋Š” ๊ธฐ๋ณธ ๋™์ž‘ - console.log("๐Ÿ”„ InteractiveScreenViewerDynamic onRefresh ํ˜ธ์ถœ"); - })} + onRefresh={ + onRefresh || + (() => { + // ๋ถ€๋ชจ๋กœ๋ถ€ํ„ฐ ์ „๋‹ฌ๋ฐ›์€ onRefresh ๋˜๋Š” ๊ธฐ๋ณธ ๋™์ž‘ + console.log("๐Ÿ”„ InteractiveScreenViewerDynamic onRefresh ํ˜ธ์ถœ"); + }) + } onFlowRefresh={onFlowRefresh} onClose={() => { // buttonActions.ts๊ฐ€ ์ด๋ฏธ ์ฒ˜๋ฆฌํ•จ @@ -357,7 +370,7 @@ export const InteractiveScreenViewerDynamic: React.FC {label || "๋ฒ„ํŠผ"} @@ -689,18 +702,18 @@ export const InteractiveScreenViewerDynamic: React.FC([]); + const [loadingTables, setLoadingTables] = useState(false); // ๋ฏธ๋ฆฌ๋ณด๊ธฐ ๊ด€๋ จ ์ƒํƒœ const [previewDialogOpen, setPreviewDialogOpen] = useState(false); @@ -260,14 +263,31 @@ export default function ScreenList({ onScreenSelect, selectedScreen, onDesignScr onScreenSelect(screen); }; - const handleEdit = (screen: ScreenDefinition) => { + const handleEdit = async (screen: ScreenDefinition) => { setScreenToEdit(screen); setEditFormData({ screenName: screen.screenName, description: screen.description || "", isActive: screen.isActive, + tableName: screen.tableName || "", }); setEditDialogOpen(true); + + // ํ…Œ์ด๋ธ” ๋ชฉ๋ก ๋กœ๋“œ + try { + setLoadingTables(true); + const { tableManagementApi } = await import("@/lib/api/tableManagement"); + const response = await tableManagementApi.getTableList(); + if (response.success && response.data) { + // tableName๋งŒ ์ถ”์ถœ (camelCase) + const tableNames = response.data.map((table: any) => table.tableName); + setTables(tableNames); + } + } catch (error) { + console.error("ํ…Œ์ด๋ธ” ๋ชฉ๋ก ์กฐํšŒ ์‹คํŒจ:", error); + } finally { + setLoadingTables(false); + } }; const handleEditSave = async () => { @@ -1180,6 +1200,25 @@ export default function ScreenList({ onScreenSelect, selectedScreen, onDesignScr placeholder="ํ™”๋ฉด๋ช…์„ ์ž…๋ ฅํ•˜์„ธ์š”" /> +
+ + +