PageSourceSearch

https://wedraw.kr/assets/TeamSettingsPage.JCjkVMNS.js

js wedraw.kr collected 2026-10-04 07:42:56 UTC 17,214 bytes, 1 lines download raw bytes

1import{j as e}from"./vendor-ui.BwPBmVwt.js";import{j as G,u as X,r as l}from"./vendor-react.kR8tqwKZ.js";import{d,f as B,p as U}from"./vendor-utils.D2q0l15H.js";import{e as J,p as K,l as Q,q as H,r as W,B as j,X as P,D as I,f as L,h as $,i as D,m as A,j as O,t as Y,v as Z,w as ee,x as se,y as ae,z as re,A as te,C as ne,G as ie}from"./index.86ltQqcV.js";import{I as z}from"./input.Bn8hRSEL.js";import{L as F}from"./label.BLlGNrU0.js";import{T as le}from"./textarea.CzIuFU26.js";import{S as k,a as M,b as R,c as E,d as _}from"./select.DEFUaHfV.js";import{L as V}from"./loader-circle.PPp0m7l9.js";import{A as ce}from"./arrow-left.COB2K-vb.js";import{I as oe}from"./info.oSrbbhNg.js";import{U as de}from"./users.BboaRFUh.js";import{M as xe}from"./mail.DbDdjDWF.js";import{A as me}from"./activity.dmW5sXDt.js";import{T as he}from"./triangle-alert.DiFS_pz6.js";import"./vendor-three.C5-HLXBy.js";import"./chevron-down.8Oyg22r0.js";import"./check.Qs6HOoRX.js";import"./chevron-up.B4ORgOxs.js";const ue=[{id:"info",label:"정보",icon:e.jsx(oe,{className:"h-4 w-4"})},{id:"members",label:"멤버",icon:e.jsx(de,{className:"h-4 w-4"})},{id:"invite",label:"초대",icon:e.jsx(xe,{className:"h-4 w-4"})},{id:"logs",label:"활동 로그",icon:e.jsx(me,{className:"h-4 w-4"})},{id:"danger",label:"위험 영역",icon:e.jsx(he,{className:"h-4 w-4"})}],C={owner:"Owner",editor:"편집자",viewer:"뷰어"},fe={"team.create":()=>"팀 생성","member.invite":a=>`${a.email??""}님 초대`,"member.join":a=>`${a.name??a.email??""}님 합류`,"member.role_change":a=>`${a.name??a.email??""}님 역할 변경: ${C[a.old_role]??a.old_role} → ${C[a.new_role]??a.new_role}`,"member.remove":a=>`${a.name??a.email??""}님 제거`,"project.create":a=>`프로젝트 생성: ${a.project_name??""}`,"project.update":a=>`프로젝트 수정: ${a.project_name??""}
1`,"project.delete":a=>`프로젝트 삭제: ${a.project_name??""}`,"project.import":a=>`프로젝트 가져오기: ${a.project_name??""}`,"team.transfer_owner":a=>`Owner 위임: ${a.old_owner??""} → ${a.new_owner??""}`,"team.dissolve":()=>"팀 해체"};function je(a){const n=fe[a.action];return n?n(a.metadata):a.action}function Ve(){const{teamId:a}=G(),n=X(),{user:y}=J(),[c,p]=l.useState("info"),[i,t]=l.useState(null),[x,g]=l.useState([]),[N,h]=l.useState([]),[f,u]=l.useState([]),[w,S]=l.useState(!0),b=x.find(o=>o.user_id===y?.id)?.role??null,s=b==="owner",m=b==="owner"||b==="editor",r=l.useCallback(async()=>{if(a){S(!0);try{const[o,q]=await Promise.all([K(a),Q(a)]);t(o),g(q)}catch(o){d.error("팀 정보 로드 실패"),console.error(o)}finally{S(!1)}}},[a]);if(l.useEffect(()=>{r()},[r]),l.useEffect(()=>{c==="invite"&&a&&H(a).then(h).catch(o=>{d.error("초대 목록 로드 실패"),console.error(o)}),c==="logs"&&a&&m&&W(a).then(u).catch(o=>{d.error("활동 로그 로드 실패"),console.error(o)})},[c,a,m]),w)return e.jsx("div",{className:"min-h-screen bg-white flex items-center justify-center",style:{paddingTop:"72px"},children:e.jsx(V,{className:"h-6 w-6 animate-spin text-gray-400"})});if(!i)return e.jsxs("div",{className:"min-h-screen bg-white flex flex-col items-center justify-center gap-4",style:{paddingTop:"72px"},children:[e.jsx("p",{className:"text-gray-500",children:"팀을 찾을 수 없습니다."}),e.jsx(j,{variant:"outline",onClick:()=>n("/pro/library"),children:"라이브러리로 돌아가기"})]});const v=ue.filter(o=>o.id==="danger"?!0:o.id==="logs"?m:!0);return e.jsx("div",{className:"min-h-screen bg-white",style:{paddingTop:"72px"},children:e.jsxs("div",{className:"max-w-4xl mx-auto px-6 py-6",children:[e.jsxs("div",{className:"flex items-center gap-3 mb-6",children:[e.jsx(j,{variant:"ghost",size:"icon",onClick:()=>n("/pro/library"),className:"h-8 w-8",children:e.jsx(ce,{className:"h-4 w-4"})}),e.jsxs("div",{children:[e.jsx("h1",{className:"text-xl font-bold text-gray-900",children:i.name}),e.jsx("p",{className:"text-sm text-gray-500",children:"팀 설정"})]})]}),e.jsxs("div",{className:"flex gap-6",children:[e.jsx("nav",{className:"w-44 shrink-0 space-y-1",children:v.map(o=>e.jsxs("button",{className:`w-full flex items-center gap-2 px-3 py-2 rounded-md text-sm transition-colors cursor-pointer ${c===o.id?"bg-blue-50 text-blue-700 font-medium":"text-gray-600 hover:bg-gray-100"} ${o.id==="danger"?c===o.id?"":"text-red-600 hover:bg-red-50":""}`,onClick:()=>p(o.id),children:[o.icon,o.label]},o.id))}),e.jsxs("div",{className:"flex-1 min-w-0",children:[c==="info"&&e.jsx(pe,{team:i,isOwner:s,onUpdated:o=>t(o)}),c==="members"&&e.jsx(ge,{teamId:i.id,members:x,currentUserId:y?.id??"",isOwner:s,onMembersChanged:g}),c==="invite"&&e.jsx(ye,{teamId:i.id,invitations:N,isOwner:s,onInvitationsChanged:h}),c==="logs"&&e.jsx(ve,{logs:f}),c==="danger"&&e.jsx(Ne,{team:i,isOwner:s,onDissolved:()=>n("/pro/library"),onLeft:()=>n("/pro/library")})]})]})]})})}function pe({team:a,isOwner:n,onUpdated:y}){const[c,p]=l.useState(a.name),[i,t]=l.useState(a.description??""),[x,g]=l.useState(!1),N=async h=>{h.preventDefault();const f=c.trim();if(f){g(!0);try{await Z(a.id,f,i.trim()),y({...a,name:f,description:i.trim()||null}),d.success("팀 정보가 저장되었습니다")}catch(u){d.error("저장에 실패했습니다"),console.error(u)}finally{g(!1)}}};return e.jsxs("div",{className:"space-y-6",children:[e.jsx("h2",{className:"text-base font-semibold text-gray-900",children:"팀 정보"}),e.jsxs("form",{onSubmit:N,className:"space-y-4 max-w-md",children:[e.jsxs("div",{className:"space-y-1.5",children:[e.jsx(F,{htmlFor:"info-name",children:"팀 이름"}),e.jsx(z,{id:"info-name",value:c,onChange:h=>p(h.target.value),maxLength:50,disabled:!n})]}),e.jsxs("div",{className:"space-y-1.5",children:[e.jsx(F,{htmlFor:"info-desc",children:"설명"}),e.jsx(le,{id:"info-desc",value:i,onChange:h=>t(h.target.value),rows:3,disabled:!n})]}),n&&e.jsx(j,{type:"submit",disabled:!c.trim()||x,className:"bg-gray-900 text-white hover:bg-gray-800",children:x?"저장 중...":"저장"})]})]})}function ge({teamId:a,members:n,currentUserId:y,isOwner:c,onMembersChanged:p}){const[i,t]=l.useState(null),[x,g]=l.useState(!1),[N,h]=l.useState(null),[f,u]=l.useState(null),w=async(s,m)=>{u(s.id);try{await ee(s.id,m),p(n.map(r=>r.id===s.id?{...r,role:m}:r)),d.success("역할이 변경되었습니다")}catch(r){d.error("역할 변경에 실패했습니다"),console.error(r)}finally{u(null)}},S=async s=>{h(s.id);try{await se(s.id),p(n.filter(m=>
1m.id!==s.id)),d.success(`${s.user_email??"멤버"}를 팀에서 제거했습니다`)}catch(m){d.error("멤버 제거에 실패했습니다"),console.error(m)}finally{h(null)}},T=async()=>{if(i){g(!0);try{await ae(a,i),d.success("Owner 권한이 위임되었습니다"),p(n.map(s=>s.user_id===y?{...s,role:"editor"}:s.user_id===i?{...s,role:"owner"}:s)),t(null)}catch(s){d.error("Owner 위임에 실패했습니다"),console.error(s)}finally{g(!1)}}},b=n.filter(s=>s.role!=="owner");return e.jsxs("div",{className:"space-y-4",children:[e.jsxs("h2",{className:"text-base font-semibold text-gray-900",children:["멤버 (",n.length,"명)"]}),e.jsx("div",{className:"border rounded-lg divide-y",children:n.map(s=>e.jsxs("div",{className:"flex items-center gap-3 px-4 py-3",children:[e.jsxs("div",{className:"flex-1 min-w-0",children:[e.jsx("p",{className:"text-sm font-medium text-gray-900 truncate",children:s.user_email??s.user_id}),e.jsxs("p",{className:"text-xs text-gray-400 mt-0.5",children:["가입일: ",B(U(s.joined_at),"yyyy.MM.dd")]})]}),e.jsx("span",{className:`text-xs px-2 py-0.5 rounded-full font-medium ${s.role==="owner"?"bg-blue-100 text-blue-700":s.role==="editor"?"bg-green-100 text-green-700":"bg-gray-100 text-gray-600"}`,children:C[s.role]}),c&&s.user_id===y&&s.role==="owner"&&e.jsx(j,{variant:"outline",size:"sm",className:"h-7 text-xs",onClick:()=>t(b[0]?.user_id??null),disabled:b.length===0,children:"Owner 위임"}),c&&s.user_id!==y&&s.role!=="owner"&&e.jsxs("div",{className:"flex items-center gap-1",children:[e.jsxs(k,{value:s.role,onValueChange:m=>w(s,m),disabled:f===s.id,children:[e.jsx(M,{className:"h-7 w-24 text-xs",children:e.jsx(R,{})}),e.jsxs(E,{children:[e.jsx(_,{value:"editor",children:"편집자"}),e.jsx(_,{value:"viewer",children:"뷰어"})]})]}),e.jsx(j,{variant:"ghost",size:"icon",className:"h-7 w-7 text-red-500 hover:bg-red-50",onClick:()=>S(s),disabled:N===s.id,children:N===s.id?e.jsx(V,{className:"h-3.5 w-3.5 animate-spin"}):e.jsx(P,{className:"h-3.5 w-3.5"})})]})]},s.id))}),e.jsx(I,{open:i!=null&&typeof i=="string"&&i!=="",onOpenChange:s=>{s||t(null)},children:e.jsxs(L,{className:"max-w-sm",children:[e.jsxs($,{children:[e.jsx(D,{children:"Owner 위임"}),e.jsx(A,{children:"새 Owner를 선택하세요. 위임 후 현재 계정은 editor로 변경됩니다."})]}),e.jsxs(k,{value:i??"",onValueChange:t,children:[e.jsx(M,{children:e.jsx(R,{placeholder:"멤버 선택"})}),e.jsx(E,{children:b.map(s=>e.jsxs(_,{value:s.user_id,children:[s.user_email??s.user_id," (",C[s.role],")"]},s.user_id))})]}),e.jsxs(O,{children:[e.jsx(j,{variant:"outline",onClick:()=>t(null),children:"취소"}),e.jsx(j,{className:"bg-gray-900 text-white hover:bg-gray-800",onClick:T,disabled:!i||x,children:x?"처리 중...":"위임"})]})]})})]})}function ye({teamId:a,invitations:n,isOwner:y,onInvitationsChanged:c}){const[p,i]=l.useState(""),[t,x]=l.useState("not_found"),[g,N]=l.useState("viewer"),[h,f]=l.useState(!1),u=l.useRef(null);l.useEffect(()=>{const r=p.trim();if(!r){x("not_found");return}return x("searching"),u.current&&clearTimeout(u.current),u.current=setTimeout(async()=>{try{const v=await Y(r);x(v??"not_found")}catch(v){console.error(v),x("not_found")}},300),()=>{u.current&&clearTimeout(u.current)}},[p]);const w=typeof t=="object"&&t!==null?n.some(r=>r.invited_email===t.email&&r.status==="pending"):!1,S=typeof t=="object"&&t!==null&&!w,T=async()=>{if(!(!S||typeof t!="object"||t===null)){f(!0);try{await re(a,t.email,g),d.success(`${t.email}님에게 초대를 보냈습니다`),i(""),x("not_found");const r=await H(a);c(r)}catch(r){const v=r instanceof Error?r.message:"초대에 실패했습니다";d.error(v),console.error(r)}finally{f(!1)}}},b=async r=>{try{await te(r),c(n.map(v=>v.id===r?{...v,status:"cancelled"}:v)),d.success("초대를 취소했습니다")}catch(v){d.error("초대 취소에 실패했습니다"),console.error(v)}},s={pending:"대기 중",accepted:"수락",rejected:"거절",expired:"만료",cancelled:"취소됨"},m={pending:"text-amber-700 bg-amber-50",accepted:"text-green-700 bg-green-50",rejected:"text-red-700 bg-red-50",expired:"text-gray-500 bg-gray-100",cancelled:"text-gray-400 bg-gray-100"};return e.jsxs("div",{className:"space-y-6",children:[e.jsxs("div",{className:"space-y-3",children:[e.jsx("h2",{className:"text-base font-semibold text-gray-900",children:"멤버 초대"}),y?e.jsxs("div",{className:"space-y-3",children:[e.jsxs("div",{className:"flex gap-2",children:[e.jsx(z,{placeholder:"이메일 주소 입력",value:p,onChange:r=>i(r.target.value),className:"flex-1"}),e.jsxs(k,{value:g,onValueChange:r=>N(r),children:[e.jsx(M,{className:"w-28",children:e.jsx(R,{})}),e.jsxs(E,{children:[e.jsx(_,{value:"editor",children:"편집자"}),e.jsx(_,{value:"viewer",children:"뷰어"})]})]}),e.jsx(j,{onClick:T,disabled:!S||h,className:"bg-gray-900 text-white hover:bg-gray-800",children:h?"전송 중...":"초대"})]}),p.trim()&&e.jsxs("div",{className:"text-sm",children:[t==="searching"&&e.jsxs("span",{className:"text-gray-400 flex items-center gap-1",children:[e.jsx(V,{className:"h-3.5 w-3.5 animate-spin"}),"검색 중..."]}),t==="not_found"&&e.jsx("span",{className:"text-red-600",children:"회원 가입된 이메일만 초대 가능합니다"}),typeof t=="object"&&t!==null&&w&&e.jsx("span",{className:"text-amber-600",children:"이미 초대를 보낸 이메일입니다"}),typeof t=="object"&&t!==null&&!w&&e.jsxs("span",{className:"text-green-600",children:[t.name?`${t.name} (${t.email})`:t.email," — 초대 가능"]})]})]}):e.jsx("p",{className:"text-sm text-gray-500",children:"초대는 Owner만 보낼 수 있습니다."})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx("h3",{className:"text-sm font-medium text-gray-700",children:"보낸 초대"}),n.length===0?e.jsx("p",{className:"text-sm text-gray-400",children:"보낸 초대가 없습니다"}):e.jsx("div",{className:"border rounded-lg divide-y",children:n.map(r=>e.jsxs("div",{className:"flex items-center gap-3 px-4 py-3",children:[e.jsxs("div",{className:"flex-1 min-w-0",children:[e.jsx("p",{className:"text-sm text-gray-900 truncate",children:r.invited_email}),e.jsxs("p",{className:"text-xs text-gray-400 mt-0.5",children:["만료: ",B(U(r.expires_at),"yyyy.MM.dd")," ·"," ",C[r.proposed_role]]})]}),e.jsx("span",{className:`text-xs px-2 py-0.5 rounded-full font-medium ${m[r.status]??"text-gray-500"}`,children:s[r.status]??r.status}),y&&r.status==="pending"&&e.jsx(j,{variant:"ghost",size:"icon",className:"h-7 w-7 text-gray-400 hover:text-red-500",onClick:()=>b(r.id),children:e.jsx(P,{className:"h-3.5 w-3.5"})})]},r.id))})]})]})}function ve({logs:a}){return e.jsxs("div",{className:"space-y-4",children:[e.jsx("h2",{className:"text-base font-semibold text-gray-900",children:"활동 로그 (최근 100건)"}),a.length===0?e.jsx("p",{className:"text-sm text-gray-400",children:"활동 기록이 없습니다"}):e.jsx("div",{className:"border rounded-lg divide-y",children:a.map(n=>e.jsxs("div",{className:"flex items-start gap-3 px-4 py-3",children:[e.jsxs("div",{className:"flex-1 min-w-0",children:[e.jsx("p",{className:"text-sm text-gray-900",children:je(n)}),e.jsx("p",{className:"text-xs text-gray-400 mt-0.5",children:n.actor_email??n.actor_id})]}),e.jsx("span",{className:"text-xs text-gray-400 whitespace-nowrap",children:B(U(n.created_at),"M월 d일 HH:mm")}
1)]},n.id))})]})}function Ne({team:a,isOwner:n,onDissolved:y,onLeft:c}){const[p,i]=l.useState(!1),[t,x]=l.useState(""),[g,N]=l.useState(!1),[h,f]=l.useState(!1),[u,w]=l.useState(!1),S=t.trim()===a.name,T=async()=>{if(S){N(!0);try{await ie(a.id),d.success(`팀 "${a.name}"이 해체되었습니다`),y()}catch(s){const m=s instanceof Error?s.message:"팀 해체에 실패했습니다";d.error(m),console.error(s)}finally{N(!1)}}},b=async()=>{w(!0);try{await ne(a.id),d.success(`팀 "${a.name}"에서 탈퇴했습니다`),c()}catch(s){const m=s instanceof Error?s.message:"팀 탈퇴에 실패했습니다";d.error(m),console.error(s)}finally{w(!1),f(!1)}};return n?e.jsxs("div",{className:"space-y-4",children:[e.jsx("h2",{className:"text-base font-semibold text-red-600",children:"위험 영역"}),e.jsxs("div",{className:"border border-red-200 rounded-lg p-5 space-y-3",children:[e.jsxs("div",{children:[e.jsx("h3",{className:"text-sm font-semibold text-gray-900",children:"팀 해체"}),e.jsxs("p",{className:"text-sm text-gray-500 mt-1",children:["팀을 해체하면 모든 팀 프로젝트, 멤버, 폴더가 영구 삭제됩니다. 이 작업은 되돌릴 수 없습니다.",e.jsx("br",{}),e.jsx("span",{className:"text-amber-700",children:"Owner인 경우 탈퇴하려면 먼저 다른 멤버에게 Owner를 위임하세요 (멤버 탭)."})]})]}),e.jsx(j,{variant:"outline",className:"border-red-300 text-red-600 hover:bg-red-50",onClick:()=>i(!0),children:"팀 해체"})]}),e.jsx(I,{open:p,onOpenChange:s=>{s||(i(!1),x(""))},children:e.jsxs(L,{className:"max-w-sm",children:[e.jsxs($,{children:[e.jsx(D,{children:"팀 해체 확인"}),e.jsxs(A,{children:["이 작업은 되돌릴 수 없습니다. 계속하려면 팀 이름"," ",e.jsx("span",{className:"font-mono font-semibold text-gray-900",children:a.name}),"을 입력하세요."]})]}),e.jsx(z,{placeholder:a.name,value:t,onChange:s=>x(s.target.value)}),e.jsxs(O,{children:[e.jsx(j,{variant:"outline",onClick:()=>{i(!1),x("")},children:"취소"}),e.jsx(j,{className:"bg-red-600 text-white hover:bg-red-700",disabled:!S||g,onClick:T,children:g?"해체 중...":"팀 해체"})]})]})})]}):e.jsxs("div",{className:"space-y-4",children:[e.jsx("h2",{className:"text-base font-semibold text-red-600",children:"위험 영역"}),e.jsxs("div",{className:"border border-red-200 rounded-lg p-5 space-y-3",children:[e.jsxs("div",{children:[e.jsx("h3",{className:"text-sm font-semibold text-gray-900",children:"팀 탈퇴"}),e.jsxs("p",{className:"text-sm text-gray-500 mt-1",children:["팀에서 탈퇴하면 팀 프로젝트와 폴더에 더 이상 접근할 수 없습니다.",e.jsx("br",{}),"팀의 프로젝트, 폴더, 다른 멤버에게는 영향이 없습니다."]})]}),e.jsx(j,{variant:"outline",className:"border-red-300 text-red-600 hover:bg-red-50",onClick:()=>f(!0),children:"팀 탈퇴"})]}),e.jsx(I,{open:h,onOpenChange:s=>!s&&f(!1),children:e.jsxs(L,{className:"max-w-sm",children:[e.jsxs($,{children:[e.jsx(D,{children:"팀 탈퇴 확인"}),e.jsxs(A,{children:[e.jsx("strong",{children:a.name})," 팀에서 탈퇴하시겠습니까?",e.jsx("br",{}),"팀 프로젝트와 폴더에 더 이상 접근할 수 없습니다."]})]}),e.jsxs(O,{children:[e.jsx(j,{variant:"outline",onClick:()=>f(!1),disabled:u,children:"취소"}),e.jsx(j,{className:"bg-red-600 text-white hover:bg-red-700",disabled:u,onClick:b,children:u?"탈퇴 중...":"탈퇴"})]})]})})]})}export{Ve 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.