PageSourceSearch

https://seodoon-church-admin.web.app/assets/StaffApprovalPage-BrPG-nbT.js

js seodoon-church-admin.web.app collected 2026-10-03 12:35:53 UTC 16,803 bytes, 1 lines download raw bytes

1import{j as e}from"./vendor-data-Z5doMMu-.js";import{r as a}from"./vendor-react-zNM0AU50.js";import{u as xe,c as d}from"./index-D1K3lVhu.js";import{s as u}from"./staffApprovalService-DRZchZHW.js";import{u as z}from"./userService-CE4aI1A4.js";import{z as n,P as X,aa as me,aL as K,at as ge,aM as ue,X as be,F as he,aN as pe,aO as fe,aP as je,am as ye,e as Q,aQ as W,a4 as G,ad as Ne,f as ve,ax as H,i as we,d as _e,T as Ce}from"./vendor-ui-CW5bJ11U.js";import{R as Se}from"./RichTextEditor-D4OTyKrK.js";import"./vendor-firebase-Da9KY1q_.js";import"./vendor-charts-08G1rM8P.js";const J={budget:"예산승인",event:"행사승인",purchase:"물품구매",leave:"휴가/출장",other:"기타"},Z={budget:{bg:"bg-emerald-50",text:"text-emerald-700",border:"border-emerald-200"},event:{bg:"bg-blue-50",text:"text-blue-700",border:"border-blue-200"},purchase:{bg:"bg-orange-50",text:"text-orange-700",border:"border-orange-200"},leave:{bg:"bg-purple-50",text:"text-purple-700",border:"border-purple-200"},other:{bg:"bg-gray-50",text:"text-gray-600",border:"border-gray-200"}},Ae=["budget","event","purchase","leave","other"],ke={drafting:"작성중",pending:"결재대기",approved:"승인",rejected:"반려",completed:"완료"},Te={drafting:{bg:"bg-gray-50",text:"text-gray-600",border:"border-gray-200",dot:"bg-gray-400"},pending:{bg:"bg-amber-50",text:"text-amber-700",border:"border-amber-200",dot:"bg-amber-500"},approved:{bg:"bg-green-50",text:"text-green-700",border:"border-green-200",dot:"bg-green-500"},rejected:{bg:"bg-red-50",text:"text-red-700",border:"border-red-200",dot:"bg-red-500"},completed:{bg:"bg-blue-50",text:"text-blue-700",border:"border-blue-200",dot:"bg-blue-500"}},ee={budget:ye,event:je,purchase:fe,leave:pe,other:he},Re={received:"받은 결재",sent:"보낸 결재",completed:"완료함"},Le={received:ue,sent:ge,completed:K};function Ye(){const{user:s,isRole:N}=xe(),R=N("담임목사","최고관리자","관리자"),[l,v]=a.useState("received"),[b,w]=a.useState([]),[L,_]=a.useState(!0),[C,S]=a.useState(null),[P,A]=a.useState(!1),[i,x]=a.useState("budget"),[c,h]=a.useState(""),[m,p]=a.useState(""),[r,g]=a.useState(""),[E,O]=a.useState(""),[F,U]=a.useState(""),[B,q]=a.useState(!1),[V,Y]=a.useState(!1),[te,I]=a.useState(null),[D,k]=a.useState(""),[M,se]=a.useState([]);a.useEffect(()=>{Promise.all([z.getUsersByRole("담임목사").catch(()=>[]),z.getUsersByRole("최고관리자").catch(()=>[])]).then(([t,o])=>{const j=[...t,...o].filter((y,ce,oe)=>oe.findIndex(ie=>ie.uid===y.uid)===ce).map(y=>({uid:y.uid,name:y.name||"담임목사",role:y.role||"담임목사"}));se(j)})},[]),a.useEffect(()=>{f()},[l,s]);async function f(){if(s)try{_(!0);let t=[];switch(l){case"received":t=await u.getReceivedApprovals(s.uid);break;case"sent":t=await u.getSentApprovals(s.uid);break;case"completed":t=await u.getCompletedApprovals(s.uid);break}w(t)}catch{n.error("결재 목록을 불러올 수 없습니다")}finally{_(!1)}}function T(){A(!1),x("budget"),h(""),p(""),g(""),O(""),U(""),q(!1)}function re(){const t=[];if(M.length>0){const o=M[0];t.push({step:0,approver_id:o.uid,approver_name:o.name,approver_role:o.role,status:"pending"})}else t.push({step:0,approver_id:"",approver_name:"담임목사",approver_role:"담임목사",status:"pending"});return t}async function ae(){if(!s||!c.trim()||!m.trim()){n.error("제목과 내용을 입력해주세요");return}Y(!0);try{const t={type:i,title:c.trim(),content:m,amount:r?Number(r):void 0,date_range:E&&F?{start:E,end:F}:void 0,is_urgent:B,requester_id:s.uid,requester_name:s.name,approval_line:re(),current_step:0,status:"pending"};await u.create(t),n.success("결재가 요청되었습니다"),T(),v("sent"),await f()}catch{n.error("결재 요청에 실패했습니다")}finally{Y(!1)}}async function ne(t){try{await u.approve(t.id,t.current_step,t.approval_line),n.success("승인 처리되었습니다"),await f()}catch{n.error("승인 처리에 실패했습니다")}}async function de(t){if(!D.trim()){n.error("반려 사유를 입력해주세요");return}try{await u.reject(t.id,t.current_step,t.approval_line,D.trim()),I(null),k(""),n.success("반려 처리되었습니다"),await f()}catch{n.error("반려 처리에 실패했습니다")}}async function le(t){if(confirm("이 결재를 삭제하시겠습니까?"))try{await u.delete(t),n.success("결재가 삭제되었습니다"),await f()}catch{n.error("삭제에 실패했습니다")}}const $=l==="received"?b.length:0;return e.jsxs("div",{className:"p-3 sm:p-6 max-w-4xl mx-auto",children:[e.jsxs("div",{className:"flex items-center gap-3 mb-4 sm:mb-6",children:[e.jsx("div",{className:"w-9 h-9 sm:w-10 sm:h-10 bg-blue-50 rounded-xl flex items-center justify-center flex-shrink-0",children:e.jsx(X,{className:"w-4 h-4 sm:w-5 sm:h-5 text-blue-600"})}),e.jsxs("div",{className:"flex-1",children:[e.jsxs("h1",{className:"text-lg sm:text-xl font-bold text-gray-900",children:["결재",$>0&&e.jsx("span",{className:"ml-2 px-2 py-0.5 bg-red-500 text-white text-xs font-medium rounded-full",children:$})]}),e.jsx("p",{className:"text-[11px] sm:text-xs text-gray-500",children:"결재 요청, 승인, 반려 처리"})]}),e.jsxs("button",{onClick:()=>{T(),A(!0)},className:"px-3 sm:px-4 py-2 bg-orange-600 text-white text-sm font-medium rounded-lg hover:bg-orange-700 transition-colors flex items-center gap-1.5",children:[e.jsx(me,{className:"w-4 h-4"}),e.jsx("span",{className:"hidden sm:inline",children:"결재 요청"})]})]}),e.jsx("div",{className:"flex gap-1 mb-4 bg-gray-100 rounded-lg p-1 
1w-full sm:w-fit",children:["received","sent","completed"].map(t=>{const o=Le[t];return e.jsxs("button",{onClick:()=>{v(t),S(null)},className:d("flex-1 sm:flex-initial px-3 sm:px-4 py-2 text-sm font-medium rounded-md transition-all flex items-center gap-1.5 justify-center",l===t?"bg-white text-gray-900 shadow-sm":"text-gray-500 hover:text-gray-700"),children:[e.jsx(o,{className:"w-3.5 h-3.5"}),Re[t]]},t)})}),P&&e.jsxs("div",{className:"bg-white rounded-xl border border-gray-200 shadow-sm mb-6 overflow-hidden",children:[e.jsxs("div",{className:"px-5 py-4 border-b border-gray-100 flex items-center justify-between",children:[e.jsx("h3",{className:"font-semibold text-gray-900 text-sm",children:"새 결재 요청"}),e.jsx("button",{onClick:T,className:"p-1 hover:bg-gray-100 rounded-lg",children:e.jsx(be,{className:"w-4 h-4 text-gray-500"})})]}),e.jsxs("div",{className:"p-5 space-y-4",children:[e.jsxs("div",{children:[e.jsx("label",{className:"block text-xs font-medium text-gray-500 mb-2",children:"결재 유형"}),e.jsx("div",{className:"flex flex-wrap gap-2",children:Ae.map(t=>{const o=ee[t],j=Z[t];return e.jsxs("button",{onClick:()=>x(t),className:d("px-3 py-1.5 text-xs font-medium rounded-lg border transition-all flex items-center gap-1.5",i===t?`${j.bg} ${j.text} ${j.border}`:"bg-gray-50 text-gray-400 border-gray-200 hover:bg-gray-100"),children:[e.jsx(o,{className:"w-3.5 h-3.5"}),J[t]]},t)})})]}),e.jsx("input",{type:"text",value:c,onChange:t=>h(t.target.value),placeholder:"결재 제목을 입력하세요",className:"w-full border border-gray-200 rounded-lg px-3 py-2 text-sm focus:ring-2 focus:ring-orange-500 focus:border-transparent"}),(i==="budget"||i==="purchase")&&e.jsxs("div",{children:[e.jsx("label",{className:"block text-xs font-medium text-gray-500 mb-1",children:"금액 (원)"}),e.jsx("input",{type:"number",value:r,onChange:t=>g(t.target.value),placeholder:"0",className:"w-full border border-gray-200 rounded-lg px-3 py-2 text-sm focus:ring-2 focus:ring-orange-500 focus:border-transparent"})]}),(i==="leave"||i==="event")&&e.jsxs("div",{className:"grid grid-cols-2 gap-3",children:[e.jsxs("div",{children:[e.jsx("label",{className:"block text-xs font-medium text-gray-500 mb-1",children:"시작일"}),e.jsx("input",{type:"date",value:E,onChange:t=>O(t.target.value),className:"w-full border border-gray-200 rounded-lg px-3 py-2 text-sm focus:ring-2 focus:ring-orange-500 focus:border-transparent"})]}),e.jsxs("div",{children:[e.jsx("label",{className:"block text-xs font-medium text-gray-500 mb-1",children:"종료일"}),e.jsx("input",{type:"date",value:F,onChange:t=>U(t.target.value),className:"w-full border border-gray-200 rounded-lg px-3 py-2 text-sm focus:ring-2 focus:ring-orange-500 focus:border-transparent"})]})]}),e.jsxs("label",{className:"flex items-center gap-2 cursor-pointer",children:[e.jsx("input",{type:"checkbox",checked:B,onChange:t=>q(t.target.checked),className:"rounded border-gray-300 text-orange-600 focus:ring-orange-500"}),e.jsx(Q,{className:"w-3.5 h-3.5 text-red-500"}),e.jsx("span",{className:"text-xs text-gray-600",children:"긴급 결재"})]}),e.jsx(Se,{value:m,onChange:p,placeholder:"결재 내용을 입력하세요...",height:200}),e.jsxs("div",{className:"bg-gray-50 rounded-lg p-3",children:[e.jsx("span",{className:"text-xs font-medium text-gray-500",children:"결재라인"}),e.jsxs("div",{className:"flex items-center gap-2 mt-2",children:[e.jsx("span",{className:"px-2 py-1 bg-blue-100 text-blue-700 text-xs rounded-md",children:(s==null?void 0:s.name)||"요청자"}),e.jsx(W,{className:"w-3 h-3 text-gray-400"}),e.jsx("span",{className:"px-2 py-1 bg-blue-100 text-blue-700 text-xs rounded-md",children:"담임목사"})]})]}),e.jsxs("div",{className:"flex justify-end gap-2",children:[e.jsx("button",{onClick:T,className:"px-4 py-2 text-sm text-gray-600 hover:bg-gray-100 rounded-lg",children:"취소"}),e.jsxs("button",{onClick:ae,disabled:V||!c.trim(),className:"px-4 py-2 bg-orange-600 text-white text-sm font-medium rounded-lg hover:bg-orange-700 disabled:opacity-50 transition-colors flex items-center gap-1.5",children:[e.jsx(G,{className:"w-3.5 h-3.5"}),V?"처리 중...":"결재 요청"]})]})]})]}),L?e.jsx("div",{className:"flex items-center justify-center py-20",children:e.jsx("div",{className:"animate-spin rounded-full h-8 w-8 border-b-2 border-orange-600"})}):b.length===0?e.jsxs("div",{className:"bg-white rounded-xl border border-gray-200 p-12 text-center text-gray-400",children:[e.jsx(X,{className:"w-10 h-10 mx-auto mb-2 opacity-40"}),e.jsx("p",{className:"text-sm",children:l==="received"?"처리할 결재가 없습니다":l==="sent"?"요청한 결재가 없습니다":"완료된 결재가 없습니다"})]}):e.jsx("div",{className:"space-y-3",children:b.map(t=>e.jsx(Pe,{approval:t,isExpanded:C===t.id,onToggle:()=>S(C===t.id?null:t.id),activeTab:l,isAdmin:R,currentUserId:(s==null?void 0:s.uid)||"",rejectingId:te,rejectComment:D,onRejectStart:()=>{I(t.id),k("")},onRejectCancel:()=>{I(null),k("")}
1,onRejectCommentChange:k,onApprove:()=>ne(t),onReject:()=>de(t),onDelete:()=>le(t.id)},t.id))})]})}function Pe({approval:s,isExpanded:N,onToggle:R,activeTab:l,currentUserId:v,rejectingId:b,rejectComment:w,onRejectStart:L,onRejectCancel:_,onRejectCommentChange:C,onApprove:S,onReject:P,onDelete:A}){const i=ee[s.type],x=Z[s.type],c=Te[s.status],h=b===s.id,m=l==="received"&&s.status==="pending",p=s.requester_id===v&&(s.status==="drafting"||s.status==="rejected");return e.jsxs("div",{className:d("bg-white rounded-xl border overflow-hidden transition-shadow",s.is_urgent?"border-red-200":s.status==="pending"?"border-amber-200":s.status==="rejected"?"border-red-200":s.status==="approved"?"border-green-200":"border-gray-200"),children:[e.jsxs("button",{onClick:R,className:"w-full text-left px-4 sm:px-5 py-4 flex items-center gap-3",children:[e.jsx("div",{className:d("w-8 h-8 rounded-full flex items-center justify-center flex-shrink-0",x.bg),children:e.jsx(i,{className:d("w-4 h-4",x.text)})}),e.jsxs("div",{className:"flex-1 min-w-0",children:[e.jsxs("div",{className:"flex items-center gap-2 flex-wrap",children:[s.is_urgent&&e.jsx(Q,{className:"w-3.5 h-3.5 text-red-500 flex-shrink-0"}),e.jsx("span",{className:"text-sm font-medium text-gray-900 truncate",children:s.title}),e.jsxs("span",{className:d("inline-flex items-center gap-1 px-1.5 py-0.5 text-[10px] font-medium rounded-full border",c.bg,c.text,c.border),children:[e.jsx("span",{className:d("w-1.5 h-1.5 rounded-full",c.dot)}),ke[s.status]]})]}),e.jsxs("div",{className:"flex items-center gap-2 mt-0.5 text-xs text-gray-400 flex-wrap",children:[e.jsx("span",{className:d("px-1.5 py-0.5 rounded text-[10px] font-medium",x.bg,x.text),children:J[s.type]}),e.jsx("span",{children:s.requester_name}),s.amount&&e.jsxs("span",{className:"font-medium text-gray-600",children:[s.amount.toLocaleString(),"원"]}),e.jsx("span",{children:new Date(s.created_at).toLocaleDateString("ko-KR")})]})]}),N?e.jsx(Ne,{className:"w-4 h-4 text-gray-400 flex-shrink-0"}):e.jsx(ve,{className:"w-4 h-4 text-gray-400 flex-shrink-0"})]}),N&&e.jsxs("div",{className:"border-t border-gray-100",children:[e.jsx("div",{className:"px-4 sm:px-5 py-4 text-sm text-gray-700 [&_p]:mb-2 [&_ul]:list-disc [&_ul]:ml-4 [&_img]:max-w-full [&_img]:rounded",dangerouslySetInnerHTML:{__html:s.content}}),(s.amount||s.date_range)&&e.jsxs("div",{className:"px-4 sm:px-5 pb-3 flex flex-wrap gap-3",children:[s.amount&&e.jsxs("div",{className:"bg-emerald-50 px-3 py-1.5 rounded-lg",children:[e.jsx("span",{className:"text-[10px] text-emerald-600 block",children:"금액"}),e.jsxs("span",{className:"text-sm font-semibold text-emerald-800",children:[s.amount.toLocaleString(),"원"]})]}),s.date_range&&e.jsxs("div",{className:"bg-blue-50 px-3 py-1.5 rounded-lg",children:[e.jsx("span",{className:"text-[10px] text-blue-600 block",children:"기간"}),e.jsxs("span",{className:"text-sm font-medium text-blue-800",children:[s.date_range.start," ~ ",s.date_range.end]})]})]}),e.jsxs("div",{className:"px-4 sm:px-5 pb-4",children:[e.jsx("span",{className:"text-xs font-medium text-gray-500 mb-2 block",children:"결재라인"}),e.jsxs("div",{className:"flex items-center gap-1 flex-wrap",children:[e.jsxs("div",{className:"flex items-center gap-1 px-2.5 py-1.5 bg-blue-50 border border-blue-200 rounded-lg",children:[e.jsx(G,{className:"w-3 h-3 text-blue-500"}),e.jsx("span",{className:"text-xs font-medium text-blue-700",children:s.requester_name})]}),s.approval_line.map((r,g)=>e.jsxs("div",{className:"flex items-center gap-1",children:[e.jsx(W,{className:"w-3 h-3 text-gray-300"}),e.jsxs("div",{className:d("flex items-center gap-1 px-2.5 py-1.5 rounded-lg border",r.status==="approved"?"bg-green-50 border-green-200":r.status==="rejected"?"bg-red-50 border-red-200":g===s.current_step&&s.status==="pending"?"bg-amber-50 border-amber-200 ring-1 ring-amber-300":"bg-gray-50 border-gray-200"),children:[r.status==="approved"&&e.jsx(K,{className:"w-3 h-3 text-green-600"}),r.status==="rejected"&&e.jsx(H,{className:"w-3 h-3 text-red-600"}),r.status==="pending"&&e.jsx(we,{className:"w-3 h-3 text-amber-500"}),e.jsx("span",{className:d("text-xs font-medium",r.status==="approved"?"text-green-700":r.status==="rejected"?"text-red-700":"text-gray-700"),children:r.approver_name})]})]},g))]}),s.approval_line.filter(r=>r.comment).map((r,g)=>e.jsxs("div",{className:d("mt-2 px-3 py-2 rounded-lg text-xs",r.status==="rejected"?"bg-red-50 text-red-700":"bg-green-50 text-green-700"),children:[e.jsx("span",{className:"font-medium",children:r.approver_name}),e.jsx("span",{className:"mx-1",children:"·"}),e.jsxs("span",{children:[r.status==="rejected"?"반려":"승인"," 의견:"]}),e.jsx("span",{className:"ml-1",children:r.comment})]},g))]}),(m||p)&&e.jsxs("div",{className:"px-4 sm:px-5 py-3 bg-gray-50 border-t border-gray-100",children:[m&&!h&&e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsxs("button",{onClick:S,className:"px-4 py-2 bg-green-600 text-white text-sm font-medium rounded-lg hover:bg-green-700 transition-colors flex items-center gap-1.5",children:[e.jsx(_e,{className:"w-3.5 h-3.5"})," 승인"]}
1),e.jsxs("button",{onClick:L,className:"px-4 py-2 bg-red-600 text-white text-sm font-medium rounded-lg hover:bg-red-700 transition-colors flex items-center gap-1.5",children:[e.jsx(H,{className:"w-3.5 h-3.5"})," 반려"]})]}),m&&h&&e.jsxs("div",{className:"space-y-2",children:[e.jsx("input",{type:"text",value:w,onChange:r=>C(r.target.value),placeholder:"반려 사유를 입력해주세요 (필수)",className:"w-full border border-red-200 rounded-lg px-3 py-2 text-sm focus:ring-2 focus:ring-red-500 focus:border-transparent bg-white",autoFocus:!0}),e.jsxs("div",{className:"flex gap-2",children:[e.jsx("button",{onClick:P,disabled:!w.trim(),className:"px-4 py-2 bg-red-600 text-white text-sm font-medium rounded-lg hover:bg-red-700 disabled:opacity-50 transition-colors",children:"반려 확인"}),e.jsx("button",{onClick:_,className:"px-4 py-2 text-sm text-gray-600 hover:bg-gray-100 rounded-lg",children:"취소"})]})]}),p&&e.jsxs("button",{onClick:A,className:"text-xs text-red-600 hover:underline flex items-center gap-0.5 mt-2",children:[e.jsx(Ce,{className:"w-3 h-3"})," 삭제"]})]})]})]})}export{Ye as StaffApprovalPage};

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.