PageSourceSearch

https://wedraw.kr/assets/MemberPointsPage.B2tbIVVb.js

js wedraw.kr collected 2026-10-04 07:43:53 UTC 25,925 bytes, 1 lines download raw bytes

1import{j as e}from"./vendor-ui.BwPBmVwt.js";import{k as V,r}from"./vendor-react.kR8tqwKZ.js";import{m as M}from"./memberPointService.C73wbA9B.js";import{H as W}from"./history.Bbo3PYMK.js";import{S as J}from"./settings.Eoz354Vz.js";import{X as D,e as Z}from"./index.86ltQqcV.js";import{C as q}from"./chevron-left.C8eB59fV.js";import{C as F}from"./chevron-right.BO4QQ722.js";import{p as k,n as ee,C as te,c as se,T as ae}from"./pointCouponService.BNZBii8h.js";import{C as re}from"./chevron-down.8Oyg22r0.js";import{P as ne}from"./pencil.DZ4g47Je.js";import{u as le}from"./AdminWriteGuard.xT1R3h4-.js";import{C as oe}from"./coins.BjA7CaPj.js";import{S as ie}from"./search.CoLV_vkF.js";import"./vendor-three.C5-HLXBy.js";import"./vendor-utils.D2q0l15H.js";const T=20;function de(){const[t,s]=V(),a=parseInt(t.get("page")||"1",10),l=t.get("q")||"",[x,d]=r.useState([]),[u,c]=r.useState(0),[v,o]=r.useState(!0),[j,w]=r.useState(l),[p,S]=r.useState({isOpen:!1,user:null}),[N,h]=r.useState({isOpen:!1,user:null,history:[],total:0,page:1,loading:!1}),f=Math.ceil(u/T),y=r.useCallback(async()=>{o(!0);try{const i=await M.getAdminUserPoints({search:l||void 0,page:a,limit:T});d(i.users),c(i.total)}catch(i){console.error("[useMemberPoints] loadUsers error:",i)}finally{o(!1)}},[l,a]);r.useEffect(()=>{y()},[y]);const P=i=>{i.preventDefault(),s({q:j,page:"1"})},A=i=>{const m=new URLSearchParams(t);Object.entries(i).forEach(([g,L])=>{L===null?m.delete(g):m.set(g,L)}),s(m)},_=i=>{S({isOpen:!0,user:i})},E=()=>{S({isOpen:!1,user:null})};return{users:x,totalCount:u,loading:v,currentPage:a,totalPages:f,itemsPerPage:T,searchInput:j,setSearchInput:w,handleSearch:P,updateSearchParams:A,adjustModal:p,openAdjustModal:_,closeAdjustModal:E,submitAdjust:async i=>{if(!p.user)return{success:!1,error:"회원 정보가 없습니다."};const m=parseInt(i.amount,10);if(isNaN(m)||m<=0)return{success:!1,error:"유효한 금액을 입력해주세요."};if(!i.reason.trim())return{success:!1,error:"사유를 입력해주세요."};const g=i.type==="grant"?await M.grantPointsAdmin(p.user.id,m,i.reason.trim()):await M.deductPointsAdmin(p.user.id,m,i.reason.trim());return g.success&&(E(),await y()),g},historyModal:N,openHistoryModal:async i=>{h({isOpen:!0,user:i,history:[],total:0,page:1,loading:!0});const m=await M.getAdminPointHistory(i.id,1,10);h(g=>({...g,history:m.data,total:m.total,loading:!1}))},closeHistoryModal:()=>{h({isOpen:!1,user:null,history:[],total:0,page:1,loading:!1})},changeHistoryPage:async i=>{if(!N.user)return;h(g=>({...g,page:i,loading:!0}));const m=await M.getAdminPointHistory(N.user.id,i,10);h(g=>({...g,history:m.data,total:m.total,page:i,loading:!1}))}}}function ce({users:t,loading:s,onViewHistory:a,onAdjust:l,isStaff:x}){return s?e.jsx("div",{className:"text-center py-12 text-gray-400",children:"로딩 중..."}):t.length===0?e.jsx("div",{className:"text-center py-12 text-gray-400",children:"검색 결과가 없습니다."}):e.jsxs("table",{className:"w-full text-sm",children:[e.jsx("thead",{className:"bg-gray-50 border-b",children:e.jsxs("tr",{children:[e.jsx("th",{className:"text-left px-4 py-3 font-medium text-gray-600",children:"이메일"}),e.jsx("th",{className:"text-left px-4 py-3 font-medium text-gray-600",children:"이름"}),e.jsx("th",{className:"text-left px-4 py-3 font-medium text-gray-600",children:"레거시 ID"}),e.jsx("th",{className:"text-right px-4 py-3 font-medium text-gray-600",children:"보유 포인트"}),e.jsx("th",{className:"text-center px-4 py-3 font-medium text-gray-600",children:"관리"})]})}),e.jsx("tbody",{children:t.map(d=>e.jsxs("tr",{className:"border-b hover:bg-gray-50",children:[e.jsx("td",{className:"px-4 py-3 text-gray-900",children:d.email}),e.jsx("td",{className:"px-4 py-3 text-gray-700",children:d.full_name||"-"}),e.jsx("td",{className:"px-4 py-3 text-gray-500 text-xs",children:d.legacy_member_id||"-"}),e.jsx("td",{className:"px-4 py-3 text-right font-semibold",children:e.jsxs("span",{className:d.total_points>0?"text-green-700":"text-gray-400",children:[d.total_points.toLocaleString(),"P"]})}),e.jsx("td",{className:"px-4 py-3 text-center",children:e.jsxs("div",{className:"flex justify-center gap-1",children:[e.jsx("button",{onClick:()=>a(d),className:"p-1.5 rounded hover:bg-gray-100 text-gray-500 hover:text-gray-700",title:"이력 보기",children:e.jsx(W,{className:"w-4 h-4"})}),!x&&e.jsx("button",{onClick:()=>l(d),className:"p-1.5 rounded hover:bg-blue-50 text-blue-500 hover:text-blue-700",title:"포인트 조정",children:e.jsx(J,{className:"w-4 h-4"})})]})})]},d.id))})]})}function xe({user:t,onSubmit:s,onClose:a}){const[l,x]=r.useState("grant"),[d,u]=r.useState(""),[c,v]=r.useState(""),[o,j]=r.useState(""),[w,p]=r.useState(!1),S=f=>{const y=f.target.value.replace(/[^0-9]/g,"");u(y),j("")}
1,N=d?parseInt(d,10).toLocaleString():"",h=async f=>{f.preventDefault(),j(""),p(!0);const y=await s({type:l,amount:d,reason:c});y.success||j(y.error||"처리 중 오류가 발생했습니다."),p(!1)};return e.jsx("div",{className:"fixed inset-0 bg-black/50 flex items-center justify-center z-50",children:e.jsxs("div",{className:"bg-white rounded-xl shadow-xl max-w-md w-full mx-4",children:[e.jsxs("div",{className:"flex items-center justify-between px-6 py-4 border-b",children:[e.jsx("h3",{className:"text-lg font-semibold",children:"포인트 조정"}),e.jsx("button",{onClick:a,className:"p-1 rounded hover:bg-gray-100",children:e.jsx(D,{className:"w-5 h-5 text-gray-400"})})]}),e.jsxs("form",{onSubmit:h,className:"px-6 py-4 space-y-4",children:[e.jsxs("div",{className:"bg-gray-50 rounded-lg p-3 text-sm",children:[e.jsx("div",{className:"text-gray-500",children:t.email}),e.jsx("div",{className:"font-medium",children:t.full_name||"-"}),e.jsxs("div",{className:"text-green-700 font-semibold mt-1",children:["현재 보유: ",t.total_points.toLocaleString(),"P"]})]}),e.jsxs("div",{className:"flex gap-3",children:[e.jsxs("label",{className:`flex-1 flex items-center justify-center gap-2 px-4 py-2.5 rounded-lg border-2 cursor-pointer transition-colors ${l==="grant"?"border-blue-500 bg-blue-50 text-blue-700":"border-gray-200 text-gray-600"}`,children:[e.jsx("input",{type:"radio",name:"type",value:"grant",checked:l==="grant",onChange:()=>x("grant"),className:"sr-only"}),e.jsx("span",{className:"font-medium",children:"부여 (+)"})]}),e.jsxs("label",{className:`flex-1 flex items-center justify-center gap-2 px-4 py-2.5 rounded-lg border-2 cursor-pointer transition-colors ${l==="deduct"?"border-red-500 bg-red-50 text-red-700":"border-gray-200 text-gray-600"}`,children:[e.jsx("input",{type:"radio",name:"type",value:"deduct",checked:l==="deduct",onChange:()=>x("deduct"),className:"sr-only"}),e.jsx("span",{className:"font-medium",children:"차감 (-)"})]})]}),e.jsxs("div",{children:[e.jsx("label",{className:"block text-sm font-medium text-gray-700 mb-1",children:"포인트"}),e.jsxs("div",{className:"relative",children:[e.jsx("input",{type:"text",value:N,onChange:S,placeholder:"0",className:"w-full px-4 py-2.5 pr-8 border border-gray-300 rounded-lg text-right text-lg font-semibold focus:outline-none focus:ring-2 focus:ring-blue-500"}),e.jsx("span",{className:"absolute right-3 top-1/2 -translate-y-1/2 text-gray-400 font-medium",children:"P"})]})]}),e.jsxs("div",{children:[e.jsx("label",{className:"block text-sm font-medium text-gray-700 mb-1",children:"사유 (필수)"}),e.jsx("textarea",{value:c,onChange:f=>{v(f.target.value),j("")},placeholder:"포인트 조정 사유를 입력하세요",rows:3,className:"w-full px-4 py-2.5 border border-gray-300 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-blue-500 resize-none"})]}),o&&e.jsx("div",{className:"text-sm text-red-600 bg-red-50 px-3 py-2 rounded-lg",children:o}),e.jsxs("div",{className:"flex gap-3 pt-2",children:[e.jsx("button",{type:"button",onClick:a,className:"flex-1 px-4 py-2.5 border border-gray-300 rounded-lg text-sm font-medium text-gray-700 hover:bg-gray-50",children:"취소"}),e.jsx("button",{type:"submit",disabled:w||!d||!c.trim(),className:`flex-1 px-4 py-2.5 rounded-lg text-sm font-medium text-white disabled:opacity-50 ${l==="grant"?"bg-blue-600 hover:bg-blue-700":"bg-red-600 hover:bg-red-700"}`,children:w?"처리 중...":l==="grant"?"부여":"차감"})]})]})]})})}const me={earn:"구매 적립",use:"포인트 사용",refund_use:"포인트 복구",refund_earn:"적립 회수",admin_grant:"관리자 지급",admin_deduct:"관리자 차감",expire:"만료",legacy_transfer:"페인트인포 이관",coupon:"쿠폰 등록"},ue={pending:"대기",confirmed:"확정"},ge=10;function pe({user:t,history:s,total:a,page:l,loading:x,onChangePage:d,onClose:u}){const c=Math.ceil(a/ge),v=o=>new Date(o).toLocaleDateString("ko-KR",{year:"numeric",month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit"});return e.jsx("div",{className:"fixed inset-0 bg-black/50 flex items-center justify-center z-50",children:e.jsxs("div",{className:"bg-white rounded-xl shadow-xl max-w-lg w-full mx-4 max-h-[85vh] flex flex-col",children:[e.jsxs("div",{className:"flex items-center justify-between px-6 py-4 border-b shrink-0",children:[e.jsxs("div",{children:[e.jsx("h3",{className:"text-lg font-semibold",children:"포인트 이력"}),e.jsxs("p",{className:"text-sm text-gray-500",children:[t.email," (",t.full_name||"-",")"]})]}),e.jsx("button",{onClick:u,className:"p-1 rounded hover:bg-gray-100",children:e.jsx(D,{className:"w-5 h-5 text-gray-400"})})]}),e.jsxs("div",{className:"px-6 py-3 bg-gray-50 border-b shrink-0",children:[e.jsx("span",{className:"text-sm text-gray-500",children:"보유 포인트: "}),e.jsxs("span",{className:"text-lg font-bold text-green-700",children:[t.total_points.toLocaleStr
1ing(),"P"]})]}),e.jsx("div",{className:"flex-1 overflow-y-auto px-6 py-3",children:x?e.jsx("div",{className:"text-center py-8 text-gray-400",children:"로딩 중..."}):s.length===0?e.jsx("div",{className:"text-center py-8 text-gray-400",children:"포인트 내역이 없습니다."}):e.jsx("div",{className:"divide-y divide-gray-100",children:s.map(o=>e.jsxs("div",{className:"flex justify-between items-center py-3",children:[e.jsxs("div",{children:[e.jsxs("div",{className:"text-sm text-gray-900",children:[me[o.type]||o.type,o.status==="pending"&&e.jsx("span",{className:"ml-1.5 text-xs text-amber-600 bg-amber-50 px-1.5 py-0.5 rounded",children:ue[o.status]})]}),e.jsxs("div",{className:"text-xs text-gray-400 mt-0.5",children:[v(o.created_at),o.order?.order_code&&e.jsxs("span",{children:[" · ",e.jsxs("a",{href:`/admin/orders/${o.order_id}`,className:"text-blue-500 hover:underline",children:["#",o.order.order_code]})]})]}),o.description&&e.jsx("div",{className:"text-xs text-gray-500 mt-0.5",children:o.description})]}),e.jsxs("div",{className:`text-sm font-semibold whitespace-nowrap ${o.amount>0?"text-green-700":"text-red-600"}`,children:[o.amount>0?"+":"",o.amount.toLocaleString(),"P"]})]},o.id))})}),c>1&&e.jsxs("div",{className:"flex items-center justify-between px-6 py-3 border-t bg-gray-50 shrink-0",children:[e.jsxs("span",{className:"text-xs text-gray-500",children:["총 ",a,"건"]}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("button",{onClick:()=>d(l-1),disabled:l<=1,className:"p-1 rounded hover:bg-gray-200 disabled:opacity-50 disabled:cursor-not-allowed",children:e.jsx(q,{className:"w-4 h-4"})}),e.jsxs("span",{className:"text-xs text-gray-700",children:[l," / ",c]}),e.jsx("button",{onClick:()=>d(l+1),disabled:l>=c,className:"p-1 rounded hover:bg-gray-200 disabled:opacity-50 disabled:cursor-not-allowed",children:e.jsx(F,{className:"w-4 h-4"})})]})]})]})})}const z={code:"",points:"",description:"",maxRedemptions:"",endsAt:""};function he(){const t=Z(n=>n.user?.id),[s,a]=r.useState([]),[l,x]=r.useState(!0),[d,u]=r.useState(""),[c,v]=r.useState(z),[o,j]=r.useState(!1),[w,p]=r.useState(""),[S,N]=r.useState(""),[h,f]=r.useState(null),[y,P]=r.useState(""),[A,_]=r.useState(!1),[E,I]=r.useState(null),[U,R]=r.useState([]),[$,i]=r.useState(!1),m=r.useCallback(async()=>{x(!0),u("");try{a(await k.listCoupons())}catch(n){console.error("[usePointCoupons] 목록 조회 실패:",n),u(n instanceof Error?n.message:"쿠폰 목록을 불러오지 못했습니다.")}finally{x(!1)}},[]);r.useEffect(()=>{m()},[m]);const g=r.useCallback(n=>{v(b=>({...b,...n,...n.code!==void 0?{code:ee(n.code).slice(0,te)}:{}})),p(""),N("")},[]),L=r.useCallback(async()=>{if(!o){if(!t){p("로그인 정보를 확인하지 못했습니다.");return}j(!0),p(""),N("");try{const n=await k.createCoupon({code:c.code,points:Number(c.points),description:c.description,maxRedemptions:c.maxRedemptions?Number(c.maxRedemptions):null,endsAt:c.endsAt||null},t);a(b=>[n,...b]),v(z),N(`쿠폰 ${n.code} 이(가) 발급되었습니다.`)}catch(n){console.error("[usePointCoupons] 쿠폰 발급 실패:",n),p(n instanceof Error?n.message:"쿠폰 발급에 실패했습니다.")}finally{j(!1)}}},[o,t,c]),B=r.useCallback(async n=>{const b=!n.is_active;u("");try{await k.setCouponActive(n.id,b),a(C=>C.map(H=>H.id===n.id?{...H,is_active:b}:H))}catch(C){console.error("[usePointCoupons] 상태 변경 실패:",C),u(C instanceof Error?C.message:"쿠폰 상태 변경에 실패했습니다.")}},[]),G=r.useCallback(n=>{f(n.id),P(se(n.ends_at)),u("")},[]),K=r.useCallback(()=>{f(null),P("")},[]),X=r.useCallback(async()=>{if(!(!h||A)){_(!0),u("");try{const n=await k.updateCouponEndsAt(h,y||null);a(b=>b.map(C=>C.id===n.id?n:C)),f(null),P("")}catch(n){console.error("[usePointCoupons] 종료일 변경 실패:",n),u(n instanceof Error?n.message:"쿠폰 종료일 변경에 실패했습니다.")}finally{_(!1)}}},[h,y,A]),Y=r.useCallback(async n=>{if(E===n){I(null);return}I(n),R([]),i(!0),u("");try{R(await k.getRedemptions(n))}catch(b){console.error("[usePointCoupons] 등록 현황 조회 실패:",b),u(b instanceof Error?b.message:"등록 현황을 불러오지 못했습니다.")}finally{i(!1)}},[E]),Q=!!(c.code&&Number(c.points)>0)&&!o;return{coupons:s,loading:l,error:d,form:c,updateForm:g,creating:o,createError:w,createdMessage:S,canSubmit:Q,createCoupon:L,toggleActive:B,editingEndsAtId:h,editingEndsAt:y,setEditingEndsAt:P,savingEndsAt:A,startEditEndsAt:G,cancelEditEndsAt:K,saveEndsAt:X,expandedCouponId:E,redemptions:U,redemptionsLoading:$,toggleRedemptions:Y,reload:m}}const O=t=>t?new Date(t).toLocaleDateString("ko-KR",{year:"numeric",month:"2-digit",day:"2-digit"}):"-";function ye({isStaff:t}){const s=he();return e.jsxs("div",{className:"space-y-6",children:[!t&&e.jsxs("div",{className:"bg-white rounded-lg border p-4",children:[e.jsxs("h2",{className:"text-sm font-semibold text-gray-900 mb-3 flex items-center",children:[e.jsx(ae,{className:"w-4 h-4 mr-1.5"}),"쿠폰 발급"]}
1),e.jsxs("div",{className:"grid grid-cols-1 md:grid-cols-5 gap-3",children:[e.jsxs("div",{children:[e.jsx("label",{className:"block text-xs font-medium text-gray-600 mb-1",children:"쿠폰 코드 *"}),e.jsx("input",{type:"text",value:s.form.code,onChange:a=>s.updateForm({code:a.target.value}),placeholder:"WELCOME",className:"w-full px-3 py-2 border border-gray-300 rounded-lg text-sm font-semibold tracking-wider uppercase focus:outline-none focus:ring-2 focus:ring-blue-500"})]}),e.jsxs("div",{children:[e.jsx("label",{className:"block text-xs font-medium text-gray-600 mb-1",children:"지급 포인트 *"}),e.jsx("input",{type:"text",inputMode:"numeric",value:s.form.points,onChange:a=>s.updateForm({points:a.target.value.replace(/[^0-9]/g,"")}),placeholder:"5000",className:"w-full px-3 py-2 border border-gray-300 rounded-lg text-sm text-right focus:outline-none focus:ring-2 focus:ring-blue-500"})]}),e.jsxs("div",{children:[e.jsx("label",{className:"block text-xs font-medium text-gray-600 mb-1",children:"발급 수량"}),e.jsx("input",{type:"text",inputMode:"numeric",value:s.form.maxRedemptions,onChange:a=>s.updateForm({maxRedemptions:a.target.value.replace(/[^0-9]/g,"")}),placeholder:"무제한",className:"w-full px-3 py-2 border border-gray-300 rounded-lg text-sm text-right focus:outline-none focus:ring-2 focus:ring-blue-500"})]}),e.jsxs("div",{children:[e.jsx("label",{className:"block text-xs font-medium text-gray-600 mb-1",children:"종료일"}),e.jsx("input",{type:"date",value:s.form.endsAt,onChange:a=>s.updateForm({endsAt:a.target.value}),className:"w-full px-3 py-2 border border-gray-300 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-blue-500"})]}),e.jsxs("div",{children:[e.jsx("label",{className:"block text-xs font-medium text-gray-600 mb-1",children:"메모"}),e.jsx("input",{type:"text",value:s.form.description,onChange:a=>s.updateForm({description:a.target.value}),placeholder:"신규가입 이벤트",className:"w-full px-3 py-2 border border-gray-300 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-blue-500"})]})]}),e.jsxs("div",{className:"flex items-center gap-3 mt-3",children:[e.jsx("button",{onClick:s.createCoupon,disabled:!s.canSubmit,className:"px-4 py-2 bg-blue-600 text-white rounded-lg text-sm font-medium hover:bg-blue-700 disabled:opacity-50",children:s.creating?"발급 중...":"쿠폰 발급"}),e.jsx("p",{className:"text-xs text-gray-500",children:"코드는 대문자 영문/숫자 4~32자 · 계정당 1회 등록 · 적립 포인트는 6개월 후 만료"})]}),s.createError&&e.jsx("div",{className:"mt-3 text-sm text-red-600 bg-red-50 px-3 py-2 rounded-lg",children:s.createError}),s.createdMessage&&e.jsx("div",{className:"mt-3 text-sm text-green-700 bg-green-50 px-3 py-2 rounded-lg",children:s.createdMessage})]}),s.error&&e.jsx("div",{className:"text-sm text-red-600 bg-red-50 px-3 py-2 rounded-lg",children:s.error}),e.jsx("div",{className:"bg-white rounded-lg border overflow-hidden",children:e.jsxs("table",{className:"w-full text-sm",children:[e.jsx("thead",{className:"bg-gray-50 text-gray-600",children:e.jsxs("tr",{children:[e.jsx("th",{className:"px-4 py-3 text-left font-medium",children:"코드"}),e.jsx("th",{className:"px-4 py-3 text-right font-medium",children:"지급 P"}),e.jsx("th",{className:"px-4 py-3 text-right font-medium",children:"사용 / 수량"}),e.jsx("th",{className:"px-4 py-3 text-left font-medium",children:"종료일"}),e.jsx("th",{className:"px-4 py-3 text-left font-medium",children:"메모"}),e.jsx("th",{className:"px-4 py-3 text-center font-medium",children:"상태"}),e.jsx("th",{className:"px-4 py-3 text-right font-medium",children:"관리"})]})}),e.jsx("tbody",{className:"divide-y",children:s.loading?e.jsx("tr",{children:e.jsx("td",{colSpan:7,className:"px-4 py-10 text-center text-gray-400",children:"불러오는 중..."})}):s.coupons.length===0?e.jsx("tr",{children:e.jsx("td",{colSpan:7,className:"px-4 py-10 text-center text-gray-400",children:"발급된 쿠폰이 없습니다."})}):s.coupons.map(a=>e.jsxs(r.Fragment,{children:[e.jsxs("tr",{className:"hover:bg-gray-50",children:[e.jsx("td",{className:"px-4 py-3",children:e.jsxs("button",{onClick:()=>s.toggleRedemptions(a.id),className:"flex items-center gap-1 font-semibold tracking-wider text-gray-900 hover:text-blue-600",title:"등록 현황 보기",children:[s.expandedCouponId===a.id?e.jsx(re,{className:"w-4 h-4"}):e.jsx(F,{className:"w-4 h-4"}),a.code]})}),e.jsxs("td",{className:"px-4 py-3 text-right font-medium text-gray-900",children:[a.points.toLocaleStr
1ing(),"P"]}),e.jsxs("td",{className:"px-4 py-3 text-right text-gray-700",children:[a.redeemed_count.toLocaleString()," / ",a.max_redemptions?.toLocaleString()??"무제한"]}),e.jsx("td",{className:"px-4 py-3 text-gray-700",children:s.editingEndsAtId===a.id?e.jsxs("div",{className:"flex items-center gap-1.5",children:[e.jsx("input",{type:"date",value:s.editingEndsAt,onChange:l=>s.setEditingEndsAt(l.target.value),className:"px-2 py-1 border border-gray-300 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-blue-500"}),e.jsx("button",{onClick:s.saveEndsAt,disabled:s.savingEndsAt,className:"px-2.5 py-1 bg-blue-600 text-white rounded-lg text-xs font-medium hover:bg-blue-700 disabled:opacity-50",children:s.savingEndsAt?"저장 중...":"저장"}),e.jsx("button",{onClick:s.cancelEditEndsAt,disabled:s.savingEndsAt,className:"px-2.5 py-1 border border-gray-300 rounded-lg text-xs font-medium text-gray-700 hover:bg-gray-50 disabled:opacity-50",children:"취소"})]}):t?O(a.ends_at):e.jsxs("button",{onClick:()=>s.startEditEndsAt(a),className:"flex items-center gap-1 text-gray-700 hover:text-blue-600",title:"종료일 수정 (비우면 무기한)",children:[O(a.ends_at),e.jsx(ne,{className:"w-3 h-3 text-gray-400"})]})}),e.jsx("td",{className:"px-4 py-3 text-gray-500",children:a.description||"-"}),e.jsx("td",{className:"px-4 py-3 text-center",children:e.jsx("span",{className:`inline-block px-2 py-0.5 rounded text-xs font-medium ${a.is_active?"bg-green-50 text-green-700":"bg-gray-100 text-gray-500"}`,children:a.is_active?"활성":"중지"})}),e.jsx("td",{className:"px-4 py-3 text-right",children:!t&&e.jsx("button",{onClick:()=>s.toggleActive(a),className:"px-3 py-1.5 border border-gray-300 rounded-lg text-xs font-medium text-gray-700 hover:bg-gray-50",children:a.is_active?"중지":"활성화"})})]}),s.expandedCouponId===a.id&&e.jsx("tr",{className:"bg-gray-50",children:e.jsx("td",{colSpan:7,className:"px-4 py-3",children:s.redemptionsLoading?e.jsx("p",{className:"text-sm text-gray-400",children:"등록 현황 불러오는 중..."}):s.redemptions.length===0?e.jsx("p",{className:"text-sm text-gray-400",children:"아직 등록한 회원이 없습니다."}):e.jsx("ul",{className:"space-y-1",children:s.redemptions.map(l=>e.jsxs("li",{className:"flex justify-between text-sm text-gray-700",children:[e.jsxs("span",{children:[l.user?.email||l.user_id,l.user?.full_name&&e.jsxs("span",{className:"text-gray-400",children:[" (",l.user.full_name,")"]})]}),e.jsxs("span",{className:"text-gray-500",children:[l.points.toLocaleString(),"P · ",O(l.created_at)]})]},l.id))})})})]},a.id))})]})})]})}function Re(){const t=de(),s=le(),[a,l]=r.useState("members");return e.jsxs("div",{className:"p-6",children:[!s&&t.adjustModal.isOpen&&t.adjustModal.user&&e.jsx(xe,{user:t.adjustModal.user,onSubmit:t.submitAdjust,onClose:t.closeAdjustModal}),t.historyModal.isOpen&&t.historyModal.user&&e.jsx(pe,{user:t.historyModal.user,history:t.historyModal.history,total:t.historyModal.total,page:t.historyModal.page,loading:t.historyModal.loading,onChangePage:t.changeHistoryPage,onClose:t.closeHistoryModal}),e.jsxs("div",{className:"mb-6",children:[e.jsxs("h1",{className:"text-2xl font-bold text-gray-900 flex items-center",children:[e.jsx(oe,{className:"w-7 h-7 mr-2"}),"포인트 관리"]}),e.jsx("p",{className:"mt-1 text-sm text-gray-500",children:"회원 포인트 조회·수동 부여/차감 및 포인트 쿠폰 관리"})]}),e.jsx("div",{className:"flex gap-1 border-b mb-6",children:["members","coupons"].map(x=>e.jsx("button",{onClick:()=>l(x),className:`px-4 py-2 text-sm font-medium border-b-2 -mb-px ${a===x?"border-blue-600 text-blue-600":"border-transparent text-gray-500 hover:text-gray-700"}`,children:x==="members"?"회원 포인트":"쿠폰"},x))}),a==="coupons"&&e.jsx(ye,{isStaff:s}),a==="members"&&e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"grid grid-cols-2 gap-4 mb-6",children:[e.jsxs("div",{className:"bg-white rounded-lg border p-4",children:[e.jsx("p",{className:"text-sm text-gray-500",children:"전체 회원"}),e.jsx("p",{className:"text-2xl font-bold text-gray-900",children:t.totalCount.toLocaleStr
1ing()})]}),e.jsxs("div",{className:"bg-white rounded-lg border p-4",children:[e.jsx("p",{className:"text-sm text-gray-500",children:"현재 페이지"}),e.jsxs("p",{className:"text-2xl font-bold text-gray-900",children:[t.currentPage," / ",t.totalPages||1]})]})]}),e.jsx("div",{className:"bg-white rounded-lg border p-4 mb-6",children:e.jsxs("form",{onSubmit:t.handleSearch,className:"flex gap-2",children:[e.jsxs("div",{className:"relative flex-1",children:[e.jsx(ie,{className:"absolute left-3 top-1/2 -translate-y-1/2 text-gray-400 w-4 h-4"}),e.jsx("input",{type:"text",placeholder:"이메일/이름/레거시 ID 검색",value:t.searchInput,onChange:x=>t.setSearchInput(x.target.value),className:"w-full pl-10 pr-10 py-2 border border-gray-300 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-blue-500"}),t.searchInput&&e.jsx("button",{type:"button",onClick:()=>{t.setSearchInput(""),t.updateSearchParams({q:null,page:"1"})},className:"absolute right-3 top-1/2 -translate-y-1/2 p-0.5 rounded hover:bg-gray-100 text-gray-400 hover:text-gray-600",title:"검색어 지우기",children:e.jsx(D,{className:"w-4 h-4"})})]}),e.jsx("button",{type:"submit",className:"px-4 py-2 bg-blue-600 text-white rounded-lg text-sm font-medium hover:bg-blue-700",children:"검색"})]})}),e.jsxs("div",{className:"bg-white rounded-lg border overflow-hidden",children:[e.jsx(ce,{users:t.users,loading:t.loading,onViewHistory:t.openHistoryModal,onAdjust:t.openAdjustModal,isStaff:s}),t.totalPages>1&&e.jsxs("div",{className:"flex items-center justify-between px-4 py-3 border-t bg-gray-50",children:[e.jsxs("p",{className:"text-sm text-gray-500",children:["전체 ",t.totalCount.toLocaleString(),"명 중"," ",((t.currentPage-1)*t.itemsPerPage+1).toLocaleString(),"-",Math.min(t.currentPage*t.itemsPerPage,t.totalCount).toLocaleString()]}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("button",{onClick:()=>t.updateSearchParams({page:String(t.currentPage-1)}),disabled:t.currentPage<=1,className:"p-1 rounded hover:bg-gray-200 disabled:opacity-50 disabled:cursor-not-allowed",children:e.jsx(q,{className:"w-5 h-5"})}),e.jsxs("span",{className:"text-sm text-gray-700",children:[t.currentPage," / ",t.totalPages]}),e.jsx("button",{onClick:()=>t.updateSearchParams({page:String(t.currentPage+1)}),disabled:t.currentPage>=t.totalPages,className:"p-1 rounded hover:bg-gray-200 disabled:opacity-50 disabled:cursor-not-allowed",children:e.jsx(F,{className:"w-5 h-5"})})]})]})]})]})]})}export{Re as default};

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.