feat(dashboard): 카드 클릭 → 해당 리스트로 즉시 이동
Deploy momo-erp / deploy (push) Failing after 41s

- 관리자: 승인 대기 → /m/admin/orders?status=REQUESTED, 오늘/이번달 → /m/admin/orders,
  미수금 → /m/admin/payments
- 사용자: 대기중 → /m/orders?status=REQUESTED, 진행중 → ?status=APPROVED, 미수금/누적
  → /m/orders
- orders 페이지가 ?status= 쿼리로 초기 필터 자동 적용

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
chpark
2026-05-08 14:15:38 +09:00
parent 23599b9c18
commit 004a8e4a6b
3 changed files with 25 additions and 14 deletions
+4 -1
View File
@@ -51,7 +51,10 @@ const STATUS_COLOR: Record<string, string> = {
export default function AdminOrdersPage() {
const [orders, setOrders] = useState<Order[]>([]);
const [status, setStatus] = useState("");
const [status, setStatus] = useState(() => {
if (typeof window === "undefined") return "";
return new URLSearchParams(window.location.search).get("status") ?? "";
});
const [selected, setSelected] = useState<Set<string>>(new Set());
const [activeId, setActiveId] = useState<string>("");
const [detail, setDetail] = useState<{ order: DetailOrder; items: DetailLine[]; supplier: Supplier } | null>(null);
+17 -12
View File
@@ -51,10 +51,10 @@ export default function MomoDashboard() {
<p className="text-slate-500 text-sm mt-1"> .</p>
</div>
<div className="grid grid-cols-2 lg:grid-cols-4 gap-4">
<Card title="대기중 발주" value={s.REQUESTED_CNT} suffix="건" tone="amber" />
<Card title="진행중 발주" value={s.PROGRESS_CNT} suffix="건" tone="blue" />
<Card title="이번달 누적" value={fmt(s.MONTH_AMOUNT)} prefix="₩" tone="emerald" />
<Card title="미수금" value={fmt(s.UNPAID)} prefix="₩" tone="rose" />
<Card title="대기중 발주" value={s.REQUESTED_CNT} suffix="건" tone="amber" href="/m/orders?status=REQUESTED" />
<Card title="진행중 발주" value={s.PROGRESS_CNT} suffix="건" tone="blue" href="/m/orders?status=APPROVED" />
<Card title="이번달 누적" value={fmt(s.MONTH_AMOUNT)} prefix="₩" tone="emerald" href="/m/orders" />
<Card title="미수금" value={fmt(s.UNPAID)} prefix="₩" tone="rose" href="/m/orders?status=APPROVED" />
</div>
<Link href="/m/orders/new" className="inline-flex items-center gap-2 px-5 h-11 rounded-xl bg-emerald-700 text-white font-bold shadow hover:-translate-y-0.5 transition">
<ShoppingCart size={16} /> <ArrowRight size={16} />
@@ -88,10 +88,10 @@ export default function MomoDashboard() {
<p className="text-slate-500 text-sm mt-1"> · · .</p>
</div>
<div className="grid grid-cols-2 lg:grid-cols-4 gap-4">
<Card title="승인 대기" value={s.PENDING_CNT} suffix="건" tone="amber" icon={<ClipboardList size={18} />} />
<Card title="오늘 발주" value={s.TODAY_CNT} suffix="건" tone="blue" icon={<ShoppingCart size={18} />} />
<Card title="이번달 매출" value={fmt(s.MONTH_AMOUNT)} prefix="₩" tone="emerald" icon={<TrendingUp size={18} />} />
<Card title="미수금" value={fmt(s.UNPAID)} prefix="₩" tone="rose" icon={<AlertTriangle size={18} />} />
<Card title="승인 대기" value={s.PENDING_CNT} suffix="건" tone="amber" icon={<ClipboardList size={18} />} href="/m/admin/orders?status=REQUESTED" />
<Card title="오늘 발주" value={s.TODAY_CNT} suffix="건" tone="blue" icon={<ShoppingCart size={18} />} href="/m/admin/orders" />
<Card title="이번달 매출" value={fmt(s.MONTH_AMOUNT)} prefix="₩" tone="emerald" icon={<TrendingUp size={18} />} href="/m/admin/orders" />
<Card title="미수금" value={fmt(s.UNPAID)} prefix="₩" tone="rose" icon={<AlertTriangle size={18} />} href="/m/admin/payments" />
</div>
<div className="grid lg:grid-cols-2 gap-6">
@@ -139,15 +139,15 @@ export default function MomoDashboard() {
);
}
function Card({ title, value, suffix, prefix, tone, icon }: { title: string; value: number | string; suffix?: string; prefix?: string; tone: "amber" | "blue" | "emerald" | "rose"; icon?: React.ReactNode }) {
function Card({ title, value, suffix, prefix, tone, icon, href }: { title: string; value: number | string; suffix?: string; prefix?: string; tone: "amber" | "blue" | "emerald" | "rose"; icon?: React.ReactNode; href?: string }) {
const toneCls = {
amber: "from-amber-50 to-amber-100 text-amber-800 border-amber-200",
blue: "from-blue-50 to-blue-100 text-blue-800 border-blue-200",
emerald: "from-emerald-50 to-emerald-100 text-emerald-800 border-emerald-200",
rose: "from-rose-50 to-rose-100 text-rose-800 border-rose-200",
}[tone];
return (
<div className={`rounded-xl border bg-gradient-to-br ${toneCls} p-5`}>
const inner = (
<>
<div className="flex items-center justify-between mb-1">
<div className="text-xs font-semibold opacity-80">{title}</div>
{icon}
@@ -155,8 +155,13 @@ function Card({ title, value, suffix, prefix, tone, icon }: { title: string; val
<div className="text-2xl font-bold tabular-nums">
{prefix}{value}{suffix && <span className="text-sm font-semibold ml-1">{suffix}</span>}
</div>
</div>
</>
);
const className = `rounded-xl border bg-gradient-to-br ${toneCls} p-5 ${href ? "cursor-pointer hover:-translate-y-0.5 hover:shadow-md transition" : ""}`;
if (href) {
return <Link href={href} className={className}>{inner}</Link>;
}
return <div className={className}>{inner}</div>;
}
function Section({ title, children, linkHref, linkLabel }: { title: string; children: React.ReactNode; linkHref?: string; linkLabel?: string }) {
+4 -1
View File
@@ -45,7 +45,10 @@ const STATUS_COLOR: Record<string, string> = {
export default function MyOrdersPage() {
const [orders, setOrders] = useState<Order[]>([]);
const [status, setStatus] = useState("");
const [status, setStatus] = useState(() => {
if (typeof window === "undefined") return "";
return new URLSearchParams(window.location.search).get("status") ?? "";
});
const [detail, setDetail] = useState<{ order: Order & { CEO_NAME?: string; BIZ_NO?: string; PHONE?: string; ADDRESS?: string; EMAIL?: string; MEMO?: string }; items: DetailLine[]; supplier: Supplier } | null>(null);
const load = async () => {