diff --git a/frontend/app/(main)/COMPANY_16/purchase/purchase-item/page.tsx b/frontend/app/(main)/COMPANY_16/purchase/purchase-item/page.tsx index 2ce10b78..1e44c7cd 100644 --- a/frontend/app/(main)/COMPANY_16/purchase/purchase-item/page.tsx +++ b/frontend/app/(main)/COMPANY_16/purchase/purchase-item/page.tsx @@ -616,6 +616,7 @@ export default function PurchaseItemPage() { page: 1, size: 500, dataFilter: { enabled: true, filters: [{ columnName: "item_id", operator: "equals", value: itemKey }] }, autoFilter: true, + sort: { columnName: "created_date", order: "asc" }, }); const mappings = mapRes.data?.data?.data || mapRes.data?.data?.rows || []; @@ -866,6 +867,7 @@ export default function PurchaseItemPage() { { columnName: "supplier_id", operator: "equals", value: custKey }, { columnName: "item_id", operator: "equals", value: selectedItem!.item_number }, ]}, autoFilter: true, + sort: { columnName: "created_date", order: "asc" }, }); const allMappings = mapRes.data?.data?.data || mapRes.data?.data?.rows || []; mappingRows = allMappings @@ -887,7 +889,8 @@ export default function PurchaseItemPage() { { columnName: "item_id", operator: "equals", value: selectedItem!.item_number }, ]}, autoFilter: true, }); - const allPriceData = priceRes.data?.data?.data || priceRes.data?.data?.rows || []; + const allPriceData = (priceRes.data?.data?.data || priceRes.data?.data?.rows || []) + .sort((a: any, b: any) => (a.start_date || "").localeCompare(b.start_date || "")); priceRows = allPriceData.map((p: any) => ({ _id: `p_existing_${p.id}`, start_date: p.start_date ? String(p.start_date).split("T")[0] : "", @@ -928,104 +931,104 @@ export default function PurchaseItemPage() { const mappingRows = suppMappings[custKey] || []; if (isEditingExisting && editSuppData?.id) { - // 매핑: 기존→UPDATE, 신규→INSERT, 삭제된→DELETE - const keptIds = new Set(); - let firstMappingId: string | null = null; + // 기존 매핑 조회 + let existingMaps: any[] = []; + try { + const existingMappings = await apiClient.post(`/table-management/tables/${MAPPING_TABLE}/data`, { + page: 1, size: 100, + dataFilter: { enabled: true, filters: [ + { columnName: "supplier_id", operator: "equals", value: custKey }, + { columnName: "item_id", operator: "equals", value: selectedItem.item_number }, + ]}, autoFilter: true, + sort: { columnName: "created_date", order: "asc" }, + }); + existingMaps = existingMappings.data?.data?.data || existingMappings.data?.data?.rows || []; + } catch { /* skip */ } + + // 매핑 upsert: 인덱스 기반 + const usedExistingIds = new Set(); + let firstMappingId: string | null = editSuppData.id; for (let mi = 0; mi < mappingRows.length; mi++) { - const m = mappingRows[mi]; - if (m._id?.startsWith("m_existing_")) { - const realId = m._id.replace("m_existing_", ""); - keptIds.add(realId); - if (mi === 0) firstMappingId = realId; + const existMap = existingMaps[mi]; + if (existMap) { await apiClient.put(`/table-management/tables/${MAPPING_TABLE}/edit`, { - originalData: { id: realId }, + originalData: { id: existMap.id }, updatedData: { - supplier_item_code: m.supplier_item_code || "", - supplier_item_name: m.supplier_item_name || "", + supplier_item_code: mappingRows[mi].supplier_item_code || "", + supplier_item_name: mappingRows[mi].supplier_item_name || "", }, }); + usedExistingIds.add(existMap.id); + if (mi === 0) firstMappingId = existMap.id; } else { - const res = await apiClient.post(`/table-management/tables/${MAPPING_TABLE}/add`, { + const mRes = await apiClient.post(`/table-management/tables/${MAPPING_TABLE}/add`, { id: crypto.randomUUID(), supplier_id: custKey, item_id: selectedItem.item_number, - supplier_item_code: m.supplier_item_code || "", - supplier_item_name: m.supplier_item_name || "", + supplier_item_code: mappingRows[mi].supplier_item_code || "", + supplier_item_name: mappingRows[mi].supplier_item_name || "", }); - if (mi === 0) firstMappingId = res.data?.data?.id || null; + if (mi === 0 && !firstMappingId) firstMappingId = mRes.data?.data?.id || null; } } - // 폼에서 삭제된 매핑 → DB 삭제 + // 초과분 delete + const toDeleteMaps = existingMaps.filter((m) => !usedExistingIds.has(m.id)); + if (toDeleteMaps.length > 0) { + await apiClient.delete(`/table-management/tables/${MAPPING_TABLE}/delete`, { + data: toDeleteMaps.map((m: any) => ({ id: m.id })), + }); + } + + // 기존 단가 조회 + let existingPriceRows: any[] = []; try { - const dbMappings = await apiClient.post(`/table-management/tables/${MAPPING_TABLE}/data`, { + const existingPrices = await apiClient.post(`/table-management/tables/supplier_item_prices/data`, { page: 1, size: 100, dataFilter: { enabled: true, filters: [ { columnName: "supplier_id", operator: "equals", value: custKey }, { columnName: "item_id", operator: "equals", value: selectedItem.item_number }, ]}, autoFilter: true, }); - const toDelete = (dbMappings.data?.data?.data || dbMappings.data?.data?.rows || []) - .filter((m: any) => !keptIds.has(m.id)); - if (toDelete.length > 0) { - await apiClient.delete(`/table-management/tables/${MAPPING_TABLE}/delete`, { - data: toDelete.map((m: any) => ({ id: m.id })), - }); - } + existingPriceRows = existingPrices.data?.data?.data || existingPrices.data?.data?.rows || []; } catch { /* skip */ } - if (!firstMappingId) firstMappingId = editSuppData.id; - - // 단가: 기존→UPDATE, 신규→INSERT, 삭제된→DELETE - const keptPriceIds = new Set(); + // 단가 upsert: 인덱스 기반 const priceRows = (suppPrices[custKey] || []).filter((p) => p.base_price || p.start_date || p.currency_code || p.base_price_type ); - for (const price of priceRows) { - if (price._id?.startsWith("p_existing_")) { - const realId = price._id.replace("p_existing_", ""); - keptPriceIds.add(realId); + const usedPriceIds = new Set(); + for (let pi = 0; pi < priceRows.length; pi++) { + const price = priceRows[pi]; + const priceData = { + mapping_id: firstMappingId || editSuppData.id, + supplier_id: custKey, item_id: selectedItem.item_number, + start_date: price.start_date || null, end_date: price.end_date || null, + currency_code: price.currency_code || null, base_price_type: price.base_price_type || null, + base_price: price.base_price ? Number(price.base_price) : null, + unit_price: price.calculated_price ? Number(price.calculated_price) : (price.base_price ? Number(price.base_price) : null), + discount_type: price.discount_type || null, discount_value: price.discount_value ? Number(price.discount_value) : null, + rounding_type: price.rounding_type || null, rounding_unit_value: price.rounding_unit_value || null, + calculated_price: price.calculated_price ? Number(price.calculated_price) : null, + }; + const existPrice = existingPriceRows[pi]; + if (existPrice) { await apiClient.put(`/table-management/tables/supplier_item_prices/edit`, { - originalData: { id: realId }, - updatedData: { - mapping_id: firstMappingId || "", - start_date: price.start_date || null, end_date: price.end_date || null, - currency_code: price.currency_code || null, base_price_type: price.base_price_type || null, - base_price: price.base_price ? Number(price.base_price) : null, - discount_type: price.discount_type || null, discount_value: price.discount_value ? Number(price.discount_value) : null, - rounding_type: price.rounding_type || null, rounding_unit_value: price.rounding_unit_value || null, - calculated_price: price.calculated_price ? Number(price.calculated_price) : null, - }, + originalData: { id: existPrice.id }, + updatedData: priceData, }); + usedPriceIds.add(existPrice.id); } else { await apiClient.post(`/table-management/tables/supplier_item_prices/add`, { - id: crypto.randomUUID(), - mapping_id: firstMappingId || "", - supplier_id: custKey, item_id: selectedItem.item_number, - start_date: price.start_date || null, end_date: price.end_date || null, - currency_code: price.currency_code || null, base_price_type: price.base_price_type || null, - base_price: price.base_price ? Number(price.base_price) : null, - discount_type: price.discount_type || null, discount_value: price.discount_value ? Number(price.discount_value) : null, - rounding_type: price.rounding_type || null, rounding_unit_value: price.rounding_unit_value || null, - calculated_price: price.calculated_price ? Number(price.calculated_price) : null, + id: crypto.randomUUID(), ...priceData, }); } } - // 폼에서 삭제된 단가 → DB 삭제 - try { - const dbPrices = await apiClient.post(`/table-management/tables/supplier_item_prices/data`, { - page: 1, size: 100, - dataFilter: { enabled: true, filters: [ - { columnName: "supplier_id", operator: "equals", value: custKey }, - { columnName: "item_id", operator: "equals", value: selectedItem.item_number }, - ]}, autoFilter: true, + // 초과분 delete + const toDeletePrices = existingPriceRows.filter((p) => !usedPriceIds.has(p.id)); + if (toDeletePrices.length > 0) { + await apiClient.delete(`/table-management/tables/supplier_item_prices/delete`, { + data: toDeletePrices.map((p: any) => ({ id: p.id })), }); - const toDeletePrices = (dbPrices.data?.data?.data || dbPrices.data?.data?.rows || []) - .filter((p: any) => !keptPriceIds.has(p.id)); - if (toDeletePrices.length > 0) { - await apiClient.delete(`/table-management/tables/supplier_item_prices/delete`, { - data: toDeletePrices.map((p: any) => ({ id: p.id })), - }); - } - } catch { /* skip */ } + } } else { // 신규 등록 const mappingRes = await apiClient.post(`/table-management/tables/${MAPPING_TABLE}/add`, { @@ -1055,6 +1058,7 @@ export default function PurchaseItemPage() { start_date: price.start_date || null, end_date: price.end_date || null, currency_code: price.currency_code || null, base_price_type: price.base_price_type || null, base_price: price.base_price ? Number(price.base_price) : null, + unit_price: price.calculated_price ? Number(price.calculated_price) : (price.base_price ? Number(price.base_price) : null), discount_type: price.discount_type || null, discount_value: price.discount_value ? Number(price.discount_value) : null, rounding_type: price.rounding_type || null, rounding_unit_value: price.rounding_unit_value || null, calculated_price: price.calculated_price ? Number(price.calculated_price) : null, @@ -1719,7 +1723,7 @@ export default function PurchaseItemPage() { {/* ── 공급업체 상세 입력/수정 모달 ── */} - + 공급업체 상세정보 {editSuppData ? "수정" : "입력"} — {selectedItem?.item_name || ""} @@ -1729,7 +1733,7 @@ export default function PurchaseItemPage() { -
+
{selectedSuppsForDetail.map((cust, idx) => { const custKey = cust.supplier_code || cust.id; const mappingRows = suppMappings[custKey] || []; diff --git a/frontend/app/(main)/COMPANY_16/sales/sales-item/page.tsx b/frontend/app/(main)/COMPANY_16/sales/sales-item/page.tsx index de794d28..7b9c09c6 100644 --- a/frontend/app/(main)/COMPANY_16/sales/sales-item/page.tsx +++ b/frontend/app/(main)/COMPANY_16/sales/sales-item/page.tsx @@ -264,6 +264,7 @@ export default function SalesItemPage() { calculated_price: string; }>>>({}); const [editCustData, setEditCustData] = useState(null); + const [collapsedPriceCards, setCollapsedPriceCards] = useState>(new Set()); // 카테고리 로드 @@ -368,6 +369,7 @@ export default function SalesItemPage() { page: 1, size: 500, dataFilter: { enabled: true, filters: [{ columnName: "item_id", operator: "equals", value: itemKey }] }, autoFilter: true, + sort: { columnName: "created_date", order: "asc" }, }); const mappings = mapRes.data?.data?.data || mapRes.data?.data?.rows || []; @@ -618,6 +620,7 @@ export default function SalesItemPage() { { columnName: "customer_id", operator: "equals", value: custKey }, { columnName: "item_id", operator: "equals", value: selectedItem!.item_number }, ]}, autoFilter: true, + sort: { columnName: "created_date", order: "asc" }, }); const allMappings = mapRes.data?.data?.data || mapRes.data?.data?.rows || []; mappingRows = allMappings @@ -639,7 +642,8 @@ export default function SalesItemPage() { { columnName: "item_id", operator: "equals", value: selectedItem!.item_number }, ]}, autoFilter: true, }); - const allPriceData = priceRes.data?.data?.data || priceRes.data?.data?.rows || []; + const allPriceData = (priceRes.data?.data?.data || priceRes.data?.data?.rows || []) + .sort((a: any, b: any) => (a.start_date || "").localeCompare(b.start_date || "")); priceRows = allPriceData.map((p: any) => ({ _id: `p_existing_${p.id}`, start_date: p.start_date ? String(p.start_date).split("T")[0] : "", @@ -680,104 +684,104 @@ export default function SalesItemPage() { const mappingRows = custMappings[custKey] || []; if (isEditingExisting && editCustData?.id) { - // 매핑: 기존→UPDATE, 신규→INSERT, 삭제된→DELETE - const keptIds = new Set(); - let firstMappingId: string | null = null; + // 기존 매핑 조회 + let existingMaps: any[] = []; + try { + const existingMappings = await apiClient.post(`/table-management/tables/${MAPPING_TABLE}/data`, { + page: 1, size: 100, + dataFilter: { enabled: true, filters: [ + { columnName: "customer_id", operator: "equals", value: custKey }, + { columnName: "item_id", operator: "equals", value: selectedItem.item_number }, + ]}, autoFilter: true, + sort: { columnName: "created_date", order: "asc" }, + }); + existingMaps = existingMappings.data?.data?.data || existingMappings.data?.data?.rows || []; + } catch { /* skip */ } + + // 매핑 upsert: 인덱스 기반 + const usedExistingIds = new Set(); + let firstMappingId: string | null = editCustData.id; for (let mi = 0; mi < mappingRows.length; mi++) { - const m = mappingRows[mi]; - if (m._id?.startsWith("m_existing_")) { - const realId = m._id.replace("m_existing_", ""); - keptIds.add(realId); - if (mi === 0) firstMappingId = realId; + const existMap = existingMaps[mi]; + if (existMap) { await apiClient.put(`/table-management/tables/${MAPPING_TABLE}/edit`, { - originalData: { id: realId }, + originalData: { id: existMap.id }, updatedData: { - customer_item_code: m.customer_item_code || "", - customer_item_name: m.customer_item_name || "", + customer_item_code: mappingRows[mi].customer_item_code || "", + customer_item_name: mappingRows[mi].customer_item_name || "", }, }); + usedExistingIds.add(existMap.id); + if (mi === 0) firstMappingId = existMap.id; } else { - const res = await apiClient.post(`/table-management/tables/${MAPPING_TABLE}/add`, { + const mRes = await apiClient.post(`/table-management/tables/${MAPPING_TABLE}/add`, { id: crypto.randomUUID(), customer_id: custKey, item_id: selectedItem.item_number, - customer_item_code: m.customer_item_code || "", - customer_item_name: m.customer_item_name || "", + customer_item_code: mappingRows[mi].customer_item_code || "", + customer_item_name: mappingRows[mi].customer_item_name || "", }); - if (mi === 0) firstMappingId = res.data?.data?.id || null; + if (mi === 0 && !firstMappingId) firstMappingId = mRes.data?.data?.id || null; } } - // 폼에서 삭제된 매핑 → DB 삭제 + // 초과분 delete + const toDeleteMaps = existingMaps.filter((m) => !usedExistingIds.has(m.id)); + if (toDeleteMaps.length > 0) { + await apiClient.delete(`/table-management/tables/${MAPPING_TABLE}/delete`, { + data: toDeleteMaps.map((m: any) => ({ id: m.id })), + }); + } + + // 기존 단가 조회 + let existingPriceRows: any[] = []; try { - const dbMappings = await apiClient.post(`/table-management/tables/${MAPPING_TABLE}/data`, { + const existingPrices = await apiClient.post(`/table-management/tables/customer_item_prices/data`, { page: 1, size: 100, dataFilter: { enabled: true, filters: [ { columnName: "customer_id", operator: "equals", value: custKey }, { columnName: "item_id", operator: "equals", value: selectedItem.item_number }, ]}, autoFilter: true, }); - const toDelete = (dbMappings.data?.data?.data || dbMappings.data?.data?.rows || []) - .filter((m: any) => !keptIds.has(m.id)); - if (toDelete.length > 0) { - await apiClient.delete(`/table-management/tables/${MAPPING_TABLE}/delete`, { - data: toDelete.map((m: any) => ({ id: m.id })), - }); - } + existingPriceRows = existingPrices.data?.data?.data || existingPrices.data?.data?.rows || []; } catch { /* skip */ } - if (!firstMappingId) firstMappingId = editCustData.id; - - // 단가: 기존→UPDATE, 신규→INSERT, 삭제된→DELETE - const keptPriceIds = new Set(); + // 단가 upsert: 인덱스 기반 const priceRows = (custPrices[custKey] || []).filter((p) => p.base_price || p.start_date || p.currency_code || p.base_price_type ); - for (const price of priceRows) { - if (price._id?.startsWith("p_existing_")) { - const realId = price._id.replace("p_existing_", ""); - keptPriceIds.add(realId); + const usedPriceIds = new Set(); + for (let pi = 0; pi < priceRows.length; pi++) { + const price = priceRows[pi]; + const priceData = { + mapping_id: firstMappingId || editCustData.id, + customer_id: custKey, item_id: selectedItem.item_number, + start_date: price.start_date || null, end_date: price.end_date || null, + currency_code: price.currency_code || null, base_price_type: price.base_price_type || null, + base_price: price.base_price ? Number(price.base_price) : null, + unit_price: price.calculated_price ? Number(price.calculated_price) : (price.base_price ? Number(price.base_price) : null), + discount_type: price.discount_type || null, discount_value: price.discount_value ? Number(price.discount_value) : null, + rounding_type: price.rounding_type || null, rounding_unit_value: price.rounding_unit_value || null, + calculated_price: price.calculated_price ? Number(price.calculated_price) : null, + }; + const existPrice = existingPriceRows[pi]; + if (existPrice) { await apiClient.put(`/table-management/tables/customer_item_prices/edit`, { - originalData: { id: realId }, - updatedData: { - mapping_id: firstMappingId || "", - start_date: price.start_date || null, end_date: price.end_date || null, - currency_code: price.currency_code || null, base_price_type: price.base_price_type || null, - base_price: price.base_price ? Number(price.base_price) : null, - discount_type: price.discount_type || null, discount_value: price.discount_value ? Number(price.discount_value) : null, - rounding_type: price.rounding_type || null, rounding_unit_value: price.rounding_unit_value || null, - calculated_price: price.calculated_price ? Number(price.calculated_price) : null, - }, + originalData: { id: existPrice.id }, + updatedData: priceData, }); + usedPriceIds.add(existPrice.id); } else { await apiClient.post(`/table-management/tables/customer_item_prices/add`, { - id: crypto.randomUUID(), - mapping_id: firstMappingId || "", - customer_id: custKey, item_id: selectedItem.item_number, - start_date: price.start_date || null, end_date: price.end_date || null, - currency_code: price.currency_code || null, base_price_type: price.base_price_type || null, - base_price: price.base_price ? Number(price.base_price) : null, - discount_type: price.discount_type || null, discount_value: price.discount_value ? Number(price.discount_value) : null, - rounding_type: price.rounding_type || null, rounding_unit_value: price.rounding_unit_value || null, - calculated_price: price.calculated_price ? Number(price.calculated_price) : null, + id: crypto.randomUUID(), ...priceData, }); } } - // 폼에서 삭제된 단가 → DB 삭제 - try { - const dbPrices = await apiClient.post(`/table-management/tables/customer_item_prices/data`, { - page: 1, size: 100, - dataFilter: { enabled: true, filters: [ - { columnName: "customer_id", operator: "equals", value: custKey }, - { columnName: "item_id", operator: "equals", value: selectedItem.item_number }, - ]}, autoFilter: true, + // 초과분 delete + const toDeletePrices = existingPriceRows.filter((p) => !usedPriceIds.has(p.id)); + if (toDeletePrices.length > 0) { + await apiClient.delete(`/table-management/tables/customer_item_prices/delete`, { + data: toDeletePrices.map((p: any) => ({ id: p.id })), }); - const toDeletePrices = (dbPrices.data?.data?.data || dbPrices.data?.data?.rows || []) - .filter((p: any) => !keptPriceIds.has(p.id)); - if (toDeletePrices.length > 0) { - await apiClient.delete(`/table-management/tables/customer_item_prices/delete`, { - data: toDeletePrices.map((p: any) => ({ id: p.id })), - }); - } - } catch { /* skip */ } + } } else { // 신규 등록 const mappingRes = await apiClient.post(`/table-management/tables/${MAPPING_TABLE}/add`, { @@ -807,6 +811,7 @@ export default function SalesItemPage() { start_date: price.start_date || null, end_date: price.end_date || null, currency_code: price.currency_code || null, base_price_type: price.base_price_type || null, base_price: price.base_price ? Number(price.base_price) : null, + unit_price: price.calculated_price ? Number(price.calculated_price) : (price.base_price ? Number(price.base_price) : null), discount_type: price.discount_type || null, discount_value: price.discount_value ? Number(price.discount_value) : null, rounding_type: price.rounding_type || null, rounding_unit_value: price.rounding_unit_value || null, calculated_price: price.calculated_price ? Number(price.calculated_price) : null, @@ -823,7 +828,10 @@ export default function SalesItemPage() { setSelectedItemId(null); setTimeout(() => setSelectedItemId(sid), 50); } catch (err: any) { - toast.error(err.response?.data?.message || "저장에 실패했습니다."); + console.error("거래처 상세 저장 실패:", err.response?.data); + const detail = err.response?.data?.error?.details; + const msg = err.response?.data?.message || "저장에 실패했습니다."; + toast.error(detail ? `${msg} (${typeof detail === "string" ? detail : JSON.stringify(detail)})` : msg); } finally { setSaving(false); } @@ -1716,7 +1724,7 @@ export default function SalesItemPage() { {/* ── 거래처 상세 입력/수정 모달 ── */} - + 거래처 상세정보 {editCustData ? "수정" : "입력"} — {selectedItem?.item_name || ""} @@ -1726,7 +1734,7 @@ export default function SalesItemPage() { -
+
{selectedCustsForDetail.map((cust, idx) => { const custKey = cust.customer_code || cust.id; const mappingRows = custMappings[custKey] || []; @@ -1742,17 +1750,17 @@ export default function SalesItemPage() {
-
+
{/* 좌: 거래처 품번/품명 */} -
-
+
+
거래처 품번/품명 관리
-
+
{mappingRows.length === 0 ? (
입력된 거래처 품번이 없어요
) : ( @@ -1792,35 +1800,61 @@ export default function SalesItemPage() {
{/* 우: 기간별 단가 */} -
-
+
+
기간별 단가 설정
-
+
{prices.map((price, pIdx) => ( -
-
- 단가 {pIdx + 1} +
+
setCollapsedPriceCards((prev) => { + const next = new Set(prev); + if (next.has(price._id)) next.delete(price._id); else next.add(price._id); + return next; + })} + > +
+ {collapsedPriceCards.has(price._id) + ? + : + } + 단가 {pIdx + 1} + {collapsedPriceCards.has(price._id) && price.calculated_price && ( + + {price.start_date || "—"} ~ {price.end_date || "—"} · {Number(price.calculated_price).toLocaleString()} {priceCategoryOptions["currency_code"]?.find((o) => o.code === price.currency_code)?.label || ""} + + )} +
{prices.length > 1 && ( )}
+ {!collapsedPriceCards.has(price._id) &&
{/* 기간 + 통화 */}
updatePriceRow(custKey, price._id, "start_date", e.target.value)} + onChange={(e) => { + const v = e.target.value; + updatePriceRow(custKey, price._id, "start_date", v); + if (price.end_date && v > price.end_date) { + updatePriceRow(custKey, price._id, "end_date", v); + } + }} + max={price.end_date || undefined} className="h-8 text-xs flex-1" /> ~ @@ -1828,6 +1862,7 @@ export default function SalesItemPage() { type="date" value={price.end_date} onChange={(e) => updatePriceRow(custKey, price._id, "end_date", e.target.value)} + min={price.start_date || undefined} className="h-8 text-xs flex-1" />
@@ -1922,6 +1957,7 @@ export default function SalesItemPage() { {price.calculated_price ? Number(price.calculated_price).toLocaleString() : "-"}
+
}
))}
diff --git a/frontend/components/layout/AppLayout.tsx b/frontend/components/layout/AppLayout.tsx index 46921770..f9fdc1e1 100644 --- a/frontend/components/layout/AppLayout.tsx +++ b/frontend/components/layout/AppLayout.tsx @@ -999,7 +999,11 @@ function AppLayoutInner({ children }: AppLayoutProps) {
{/* 테마 토글 */} - {(!isMobile && sidebarCollapsed) ? null : ( + {(!isMobile && sidebarCollapsed) ? ( +
+ +
+ ) : (
diff --git a/frontend/components/layout/ThemeToggle.tsx b/frontend/components/layout/ThemeToggle.tsx index b6ea71be..fa6ff2e0 100644 --- a/frontend/components/layout/ThemeToggle.tsx +++ b/frontend/components/layout/ThemeToggle.tsx @@ -32,10 +32,10 @@ export function ThemeToggle({ collapsed = false }: ThemeToggleProps) { variant="ghost" size={collapsed ? "icon" : "default"} onClick={() => setTheme(isDark ? "light" : "dark")} - className="w-full justify-start gap-2 text-sm" + className={collapsed ? "h-10 w-10 justify-center" : "w-full justify-start gap-2 text-sm"} title={isDark ? "라이트 모드" : "다크 모드"} > - {isDark ? : } + {isDark ? : } {!collapsed && (isDark ? "라이트 모드" : "다크 모드")} );