feat(payments): 입금 등록/수정 모달 드래그 이동 가능
Deploy momo-erp / deploy (push) Successful in 1m56s

SweetAlert2 팝업 제목 바를 잡고 마우스/터치로 옮길 수 있게 makeSwalDraggable 추가.
출고정산 입금관리 + 매입 입금관리 모달에 적용.
This commit is contained in:
chpark
2026-05-27 12:07:05 +09:00
parent 5716686fb2
commit 92297145a8
3 changed files with 62 additions and 0 deletions
+2
View File
@@ -3,6 +3,7 @@
import { useEffect, useState, useCallback } from "react";
import { RefreshCcw } from "lucide-react";
import Swal from "sweetalert2";
import { makeSwalDraggable } from "@/lib/swal-draggable";
interface Order { OBJID: string; ORDER_NO: string; ORDER_DATE: string; COMPANY_NAME: string; STATUS: string; TOTAL_AMOUNT: number; PAID_AMOUNT: number }
const fmt = (n: number) => Number(n || 0).toLocaleString("ko-KR");
@@ -58,6 +59,7 @@ export default function PaymentsPage() {
title: `${o.COMPANY_NAME} 입금 등록`,
html: `미입금 ₩${fmt(remain)}`, input: "number", inputValue: remain,
showCancelButton: true, confirmButtonText: "입금 처리", confirmButtonColor: "#0f766e",
didOpen: () => makeSwalDraggable(),
});
if (!r.isConfirmed) return;
const amt = Number(r.value);
@@ -4,6 +4,7 @@ import { useEffect, useState, useMemo, useCallback } from "react";
import Swal from "sweetalert2";
import { SearchableSelect } from "@/components/ui/searchable-select";
import { Loading } from "@/components/ui/loading";
import { makeSwalDraggable } from "@/lib/swal-draggable";
interface Proc {
OBJID: string;
@@ -105,6 +106,7 @@ export default function ProcPaymentsPage() {
confirmButtonColor: "#0f766e",
cancelButtonText: "취소",
focusConfirm: false,
didOpen: () => makeSwalDraggable(),
preConfirm: () => {
const a = (document.getElementById("sw-amount") as HTMLInputElement)?.value;
const m = (document.getElementById("sw-method") as HTMLInputElement)?.value;
@@ -160,6 +162,7 @@ export default function ProcPaymentsPage() {
confirmButtonColor: "#0f766e",
denyButtonColor: "#dc2626",
focusConfirm: false,
didOpen: () => makeSwalDraggable(),
preConfirm: () => ({
paidDate: (document.getElementById("sw-date") as HTMLInputElement)?.value || undefined,
amount: Number((document.getElementById("sw-amount") as HTMLInputElement)?.value) || Number(p.TOTAL_AMOUNT),
+57
View File
@@ -0,0 +1,57 @@
// SweetAlert2 팝업을 제목 바를 잡고 마우스/터치로 이동 가능하게 만든다.
// Swal.fire({ didOpen: () => makeSwalDraggable() }) 형태로 사용.
export function makeSwalDraggable() {
if (typeof document === "undefined") return;
const popup = document.querySelector<HTMLElement>(".swal2-popup");
if (!popup) return;
const handle = popup.querySelector<HTMLElement>(".swal2-title") ?? popup;
let committedX = 0, committedY = 0; // 지금까지 이동 누적
let startX = 0, startY = 0;
let dragging = false;
handle.style.cursor = "move";
handle.style.userSelect = "none";
handle.style.touchAction = "none";
const point = (e: MouseEvent | TouchEvent) =>
"touches" in e ? e.touches[0] ?? (e as TouchEvent).changedTouches[0] : (e as MouseEvent);
const onMove = (e: MouseEvent | TouchEvent) => {
if (!dragging) return;
const p = point(e);
const nx = committedX + (p.clientX - startX);
const ny = committedY + (p.clientY - startY);
popup.style.transform = `translate(${nx}px, ${ny}px)`;
if ("touches" in e) e.preventDefault();
};
const onUp = (e: MouseEvent | TouchEvent) => {
if (!dragging) return;
dragging = false;
const p = point(e);
committedX += p.clientX - startX;
committedY += p.clientY - startY;
document.removeEventListener("mousemove", onMove);
document.removeEventListener("mouseup", onUp);
document.removeEventListener("touchmove", onMove);
document.removeEventListener("touchend", onUp);
};
const onDown = (e: MouseEvent | TouchEvent) => {
// 입력/버튼 위에서 시작하면 드래그 안 함
const target = e.target as HTMLElement;
if (target.closest("input, textarea, select, button, a")) return;
const p = point(e);
startX = p.clientX;
startY = p.clientY;
dragging = true;
document.addEventListener("mousemove", onMove);
document.addEventListener("mouseup", onUp);
document.addEventListener("touchmove", onMove, { passive: false });
document.addEventListener("touchend", onUp);
};
handle.addEventListener("mousedown", onDown);
handle.addEventListener("touchstart", onDown, { passive: true });
}